about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock57
-rw-r--r--compiler/rustc_ast/src/ast.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs155
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs43
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs126
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs71
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs90
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs21
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs168
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs24
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs33
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs26
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs38
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs19
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs37
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs15
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs46
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs31
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs70
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs127
-rw-r--r--compiler/rustc_const_eval/src/errors.rs60
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs2
-rw-r--r--compiler/rustc_data_structures/src/flock/linux.rs7
-rw-r--r--compiler/rustc_data_structures/src/sso/set.rs2
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs12
-rw-r--r--compiler/rustc_driver/src/lib.rs34
-rw-r--r--compiler/rustc_driver/src/session_diagnostics.rs14
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl2
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/infer.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/session.ftl4
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs25
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs35
-rw-r--r--compiler/rustc_errors/src/lib.rs3
-rw-r--r--compiler/rustc_expand/src/base.rs5
-rw-r--r--compiler/rustc_expand/src/errors.rs12
-rw-r--r--compiler/rustc_expand/src/expand.rs7
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs6
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs38
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs312
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs99
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs106
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs502
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs159
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs9
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs6
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml28
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs (renamed from compiler/rustc_hir_analysis/src/check/_match.rs)11
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs (renamed from compiler/rustc_hir_analysis/src/check/autoderef.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs (renamed from compiler/rustc_hir_analysis/src/check/callee.rs)5
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs (renamed from compiler/rustc_hir_analysis/src/check/cast.rs)7
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs324
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs (renamed from compiler/rustc_hir_analysis/src/check/closure.rs)33
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs (renamed from compiler/rustc_hir_analysis/src/check/coercion.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs (renamed from compiler/rustc_hir_analysis/src/check/demand.rs)11
-rw-r--r--compiler/rustc_hir_typeck/src/diverges.rs (renamed from compiler/rustc_hir_analysis/src/check/diverges.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs126
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs (renamed from compiler/rustc_hir_analysis/src/check/expectation.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs (renamed from compiler/rustc_hir_analysis/src/check/expr.rs)49
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs (renamed from compiler/rustc_hir_analysis/src/expr_use_visitor.rs)9
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs (renamed from compiler/rustc_hir_analysis/src/check/fallback.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs)21
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs)30
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs)9
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs (renamed from compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs)19
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs (renamed from compiler/rustc_hir_analysis/src/check/gather_locals.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs)19
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/generator_interior.rs)24
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs (renamed from compiler/rustc_hir_analysis/src/check/inherited.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs108
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs507
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs (renamed from compiler/rustc_hir_analysis/src/mem_categorization.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs (renamed from compiler/rustc_hir_analysis/src/check/method/confirm.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs (renamed from compiler/rustc_hir_analysis/src/check/method/mod.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs (renamed from compiler/rustc_hir_analysis/src/check/method/prelude2021.rs)9
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs (renamed from compiler/rustc_hir_analysis/src/check/method/probe.rs)7
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs (renamed from compiler/rustc_hir_analysis/src/check/method/suggest.rs)91
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs (renamed from compiler/rustc_hir_analysis/src/check/op.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs (renamed from compiler/rustc_hir_analysis/src/check/pat.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs (renamed from compiler/rustc_hir_analysis/src/check/place_op.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs (renamed from compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs (renamed from compiler/rustc_hir_analysis/src/check/upvar.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs (renamed from compiler/rustc_hir_analysis/src/check/writeback.rs)3
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs131
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs4
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs26
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs17
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs23
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs19
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs8
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs5
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/errors.rs28
-rw-r--r--compiler/rustc_interface/src/interface.rs109
-rw-r--r--compiler/rustc_interface/src/passes.rs1
-rw-r--r--compiler/rustc_interface/src/tests.rs14
-rw-r--r--compiler/rustc_interface/src/util.rs122
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs212
-rw-r--r--compiler/rustc_lint/src/context.rs19
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs8
-rw-r--r--compiler/rustc_lint/src/errors.rs57
-rw-r--r--compiler/rustc_lint/src/expect.rs4
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs14
-rw-r--r--compiler/rustc_lint/src/internal.rs36
-rw-r--r--compiler/rustc_lint/src/levels.rs6
-rw-r--r--compiler/rustc_lint/src/methods.rs10
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs14
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs65
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs26
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs6
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs18
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs4
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs4
-rw-r--r--compiler/rustc_lint/src/traits.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs198
-rw-r--r--compiler/rustc_lint/src/unused.rs44
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs3
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs35
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs65
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs14
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs47
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs17
-rw-r--r--compiler/rustc_metadata/src/errors.rs186
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs17
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs62
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs3
-rw-r--r--compiler/rustc_middle/src/error.rs12
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs33
-rw-r--r--compiler/rustc_middle/src/macros.rs13
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs136
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs28
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs10
-rw-r--r--compiler/rustc_middle/src/mir/query.rs16
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs48
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs32
-rw-r--r--compiler/rustc_middle/src/query/mod.rs213
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs1
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs13
-rw-r--r--compiler/rustc_middle/src/ty/context.rs29
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs5
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs18
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs61
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs145
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs204
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs258
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs83
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs21
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs17
-rw-r--r--compiler/rustc_middle/src/ty/query.rs1
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs25
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs56
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs47
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs16
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs12
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs10
-rw-r--r--compiler/rustc_mir_dataflow/src/errors.rs20
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs249
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs21
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs40
-rw-r--r--compiler/rustc_parse/src/errors.rs354
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs9
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs19
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs28
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs16
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs82
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs20
-rw-r--r--compiler/rustc_passes/src/check_attr.rs12
-rw-r--r--compiler/rustc_passes/src/errors.rs401
-rw-r--r--compiler/rustc_passes/src/stability.rs17
-rw-r--r--compiler/rustc_plugin_impl/src/errors.rs4
-rw-r--r--compiler/rustc_privacy/src/errors.rs24
-rw-r--r--compiler/rustc_privacy/src/lib.rs82
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs1
-rw-r--r--compiler/rustc_query_system/src/error.rs30
-rw-r--r--compiler/rustc_resolve/src/access_levels.rs143
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs13
-rw-r--r--compiler/rustc_resolve/src/imports.rs29
-rw-r--r--compiler/rustc_resolve/src/late.rs31
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs166
-rw-r--r--compiler/rustc_resolve/src/macros.rs16
-rw-r--r--compiler/rustc_save_analysis/src/errors.rs2
-rw-r--r--compiler/rustc_session/src/config/sigpipe.rs13
-rw-r--r--compiler/rustc_session/src/errors.rs89
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/session.rs102
-rw-r--r--compiler/rustc_session/src/utils.rs11
-rw-r--r--compiler/rustc_span/src/lib.rs5
-rw-r--r--compiler/rustc_span/src/source_map.rs44
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs45
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/errors.rs2
-rw-r--r--compiler/rustc_target/src/spec/abi.rs268
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs35
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs217
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs17
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs3
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs43
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs48
-rw-r--r--compiler/rustc_type_ir/src/lib.rs6
-rw-r--r--compiler/rustc_type_ir/src/sty.rs4
-rw-r--r--config.toml.example5
-rw-r--r--library/alloc/src/borrow.rs1
-rw-r--r--library/alloc/src/boxed.rs51
-rw-r--r--library/alloc/src/collections/btree/map.rs9
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/rc.rs2
-rw-r--r--library/alloc/src/string.rs31
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/alloc/src/vec/into_iter.rs4
-rw-r--r--library/alloc/src/vec/mod.rs5
-rw-r--r--library/core/benches/iter.rs20
-rw-r--r--library/core/benches/lib.rs1
-rw-r--r--library/core/src/array/iter.rs5
-rw-r--r--library/core/src/array/mod.rs6
-rw-r--r--library/core/src/cell.rs44
-rw-r--r--library/core/src/char/methods.rs5
-rw-r--r--library/core/src/intrinsics.rs8
-rw-r--r--library/core/src/iter/adapters/copied.rs74
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/marker.rs112
-rw-r--r--library/core/src/mem/maybe_uninit.rs42
-rw-r--r--library/core/src/mem/mod.rs35
-rw-r--r--library/core/src/num/int_macros.rs2
-rw-r--r--library/core/src/num/uint_macros.rs82
-rw-r--r--library/core/src/ptr/alignment.rs4
-rw-r--r--library/core/src/ptr/metadata.rs14
-rw-r--r--library/core/src/ptr/mod.rs28
-rw-r--r--library/core/src/ptr/mut_ptr.rs6
-rw-r--r--library/core/src/ptr/non_null.rs6
-rw-r--r--library/core/src/slice/mod.rs43
-rw-r--r--library/core/src/str/pattern.rs2
-rw-r--r--library/core/src/sync/atomic.rs16
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/mem.rs12
-rw-r--r--library/proc_macro/src/lib.rs2
-rw-r--r--library/std/src/backtrace.rs6
-rw-r--r--library/std/src/fs.rs67
-rw-r--r--library/std/src/os/wasi/io/mod.rs4
-rw-r--r--library/std/src/process.rs12
-rw-r--r--library/std/src/rt.rs2
-rw-r--r--library/std/src/sys/hermit/args.rs74
-rw-r--r--library/std/src/sys/hermit/mod.rs4
-rw-r--r--library/std/src/sys/solid/fs.rs20
-rw-r--r--library/std/src/sys/unix/fs.rs95
-rw-r--r--library/std/src/sys/unix/mod.rs38
-rw-r--r--library/std/src/sys/unix/process/process_common.rs2
-rw-r--r--library/std/src/sys/unix/process/process_common/tests.rs79
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs72
-rw-r--r--library/std/src/sys/windows/c.rs3
-rw-r--r--library/std/src/sys/windows/io.rs11
-rw-r--r--library/std/src/sys/windows/process.rs6
-rw-r--r--library/std/src/sys_common/backtrace.rs9
-rw-r--r--library/std/src/sys_common/mutex.rs44
-rw-r--r--library/std/src/thread/mod.rs27
-rw-r--r--library/std/src/time.rs2
-rw-r--r--library/test/src/console.rs2
-rw-r--r--library/test/src/lib.rs17
-rw-r--r--library/test/src/term.rs2
-rw-r--r--library/test/src/term/win.rs7
-rw-r--r--library/test/src/tests.rs27
-rw-r--r--src/bootstrap/compile.rs38
-rw-r--r--src/bootstrap/config.rs30
-rw-r--r--src/bootstrap/tool.rs4
-rw-r--r--src/ci/docker/README.md86
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile43
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-mips-linux/build-mips-toolchain.sh26
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.config740
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch44
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch63
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile44
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-mips64-linux/build-mips64-toolchain.sh26
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.config741
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile43
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-mips64el-linux/build-mips64el-toolchain.sh26
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.config741
-rw-r--r--src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile44
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-mipsel-linux/build-mipsel-toolchain.sh26
-rw-r--r--src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.config740
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/dylib-lto.md4
-rw-r--r--src/doc/unstable-book/src/language-features/asm-sym.md13
-rw-r--r--src/doc/unstable-book/src/language-features/unix-sigpipe.md10
-rw-r--r--src/librustdoc/clean/blanket_impl.rs196
-rw-r--r--src/librustdoc/clean/mod.rs85
-rw-r--r--src/librustdoc/config.rs80
-rw-r--r--src/librustdoc/core.rs19
-rw-r--r--src/librustdoc/doctest.rs17
-rw-r--r--src/librustdoc/html/markdown.rs1
-rw-r--r--src/librustdoc/html/render/context.rs37
-rw-r--r--src/librustdoc/html/render/mod.rs10
-rw-r--r--src/librustdoc/html/static/css/noscript.css2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css252
-rw-r--r--src/librustdoc/html/static/css/settings.css19
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css4
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css4
-rw-r--r--src/librustdoc/html/static/css/themes/light.css6
-rw-r--r--src/librustdoc/html/static/js/main.js184
-rw-r--r--src/librustdoc/html/static/js/settings.js4
-rw-r--r--src/librustdoc/html/static/js/source-script.js33
-rw-r--r--src/librustdoc/html/static/js/storage.js4
-rw-r--r--src/librustdoc/html/templates/page.html50
-rw-r--r--src/librustdoc/lib.rs80
-rw-r--r--src/librustdoc/markdown.rs7
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs10
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs35
-rw-r--r--src/librustdoc/visit_ast.rs8
-rw-r--r--src/librustdoc/visit_lib.rs10
m---------src/llvm-project0
-rw-r--r--src/test/assembly/asm/aarch64-types.rs2
-rw-r--r--src/test/assembly/asm/arm-types.rs2
-rw-r--r--src/test/assembly/asm/avr-types.rs2
-rw-r--r--src/test/assembly/asm/bpf-types.rs2
-rw-r--r--src/test/assembly/asm/global_asm.rs6
-rw-r--r--src/test/assembly/asm/hexagon-types.rs2
-rw-r--r--src/test/assembly/asm/mips-types.rs2
-rw-r--r--src/test/assembly/asm/msp430-types.rs2
-rw-r--r--src/test/assembly/asm/nvptx-types.rs2
-rw-r--r--src/test/assembly/asm/powerpc-types.rs2
-rw-r--r--src/test/assembly/asm/riscv-types.rs2
-rw-r--r--src/test/assembly/asm/s390x-types.rs2
-rw-r--r--src/test/assembly/asm/wasm-types.rs2
-rw-r--r--src/test/assembly/asm/x86-types.rs2
-rw-r--r--src/test/codegen/deduced-param-attrs.rs60
-rw-r--r--src/test/codegen/function-arguments.rs2
-rw-r--r--src/test/pretty/issue-85089.pp20
-rw-r--r--src/test/pretty/issue-85089.rs16
-rw-r--r--src/test/pretty/raw-str-nonexpr.rs1
-rw-r--r--src/test/pretty/tests-are-sorted.pp69
-rw-r--r--src/test/pretty/tests-are-sorted.rs13
-rw-r--r--src/test/run-make-fulldeps/intrinsic-unreachable/Makefile1
-rw-r--r--src/test/run-make-fulldeps/issue-19371/foo.rs2
-rw-r--r--src/test/run-make/coverage-reports/Makefile9
-rw-r--r--src/test/rustdoc-gui/anchors.goml247
-rw-r--r--src/test/rustdoc-gui/code-color.goml36
-rw-r--r--src/test/rustdoc-gui/codeblock-tooltip.goml168
-rw-r--r--src/test/rustdoc-gui/docblock-details.goml11
-rw-r--r--src/test/rustdoc-gui/headers-color.goml173
-rw-r--r--src/test/rustdoc-gui/headings.goml176
-rw-r--r--src/test/rustdoc-gui/help-page.goml24
-rw-r--r--src/test/rustdoc-gui/item-decl-colors.goml74
-rw-r--r--src/test/rustdoc-gui/jump-to-def-background.goml55
-rw-r--r--src/test/rustdoc-gui/mobile.goml2
-rw-r--r--src/test/rustdoc-gui/search-form-elements.goml42
-rw-r--r--src/test/rustdoc-gui/settings.goml11
-rw-r--r--src/test/rustdoc-gui/shortcuts.goml18
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile-scroll.goml8
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml9
-rw-r--r--src/test/rustdoc-gui/sidebar.goml24
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml24
-rw-r--r--src/test/rustdoc-gui/src/test_docs/lib.rs30
-rw-r--r--src/test/rustdoc-gui/type-declation-overflow.goml6
-rw-r--r--src/test/rustdoc-ui/z-help.stdout1
-rw-r--r--src/test/rustdoc/associated-consts.rs8
-rw-r--r--src/test/rustdoc/deref-recursive-pathbuf.rs4
-rw-r--r--src/test/rustdoc/deref-recursive.rs4
-rw-r--r--src/test/rustdoc/deref-typedef.rs2
-rw-r--r--src/test/rustdoc/escape-deref-methods.rs2
-rw-r--r--src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html1
-rw-r--r--src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html1
-rw-r--r--src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html (renamed from src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html)0
-rw-r--r--src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs (renamed from src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs)15
-rw-r--r--src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html1
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs (renamed from src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs)1
-rw-r--r--src/test/rustdoc/inline_cross/auxiliary/issue-24183.rs14
-rw-r--r--src/test/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html1
-rw-r--r--src/test/rustdoc/inline_cross/issue-24183.rs18
-rw-r--r--src/test/rustdoc/intra-doc/no-doc-primitive.rs15
-rw-r--r--src/test/rustdoc/issue-100241.rs12
-rw-r--r--src/test/rustdoc/logo-class-default.rs2
-rw-r--r--src/test/rustdoc/logo-class.rs4
-rw-r--r--src/test/rustdoc/negative-impl-sidebar.rs2
-rw-r--r--src/test/rustdoc/not-wf-ambiguous-normalization.rs24
-rw-r--r--src/test/rustdoc/sidebar-items.rs18
-rw-r--r--src/test/rustdoc/sidebar-links-to-foreign-impl.rs2
-rw-r--r--src/test/rustdoc/tuple-struct-fields-doc.rs2
-rw-r--r--src/test/ui-fulldeps/fluent-messages/test.rs5
-rw-r--r--src/test/ui-fulldeps/fluent-messages/test.stderr29
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.rs10
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.stderr2
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs279
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr202
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs124
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr150
-rw-r--r--src/test/ui/abi/abi-sysv64-register-usage.rs26
-rw-r--r--src/test/ui/alloc-error/default-alloc-error-hook.rs11
-rw-r--r--src/test/ui/asm/aarch64/bad-reg.rs2
-rw-r--r--src/test/ui/asm/aarch64/may_unwind.rs2
-rw-r--r--src/test/ui/asm/aarch64/sym.rs2
-rw-r--r--src/test/ui/asm/aarch64/type-check-2-2.rs2
-rw-r--r--src/test/ui/asm/aarch64/type-check-2.rs2
-rw-r--r--src/test/ui/asm/generic-const.rs2
-rw-r--r--src/test/ui/asm/naked-functions.rs2
-rw-r--r--src/test/ui/asm/type-check-1.rs2
-rw-r--r--src/test/ui/asm/unpretty-expanded.rs1
-rw-r--r--src/test/ui/asm/unpretty-expanded.stdout1
-rw-r--r--src/test/ui/asm/x86_64/bad-reg.rs2
-rw-r--r--src/test/ui/asm/x86_64/issue-96797.rs2
-rw-r--r--src/test/ui/asm/x86_64/may_unwind.rs2
-rw-r--r--src/test/ui/asm/x86_64/multiple-clobber-abi.rs2
-rw-r--r--src/test/ui/asm/x86_64/sym.rs2
-rw-r--r--src/test/ui/asm/x86_64/type-check-2.rs2
-rw-r--r--src/test/ui/asm/x86_64/type-check-4.rs5
-rw-r--r--src/test/ui/asm/x86_64/type-check-4.stderr6
-rw-r--r--src/test/ui/asm/x86_64/type-check-5.rs2
-rw-r--r--src/test/ui/associated-type-bounds/inside-adt.rs4
-rw-r--r--src/test/ui/associated-type-bounds/inside-adt.stderr10
-rw-r--r--src/test/ui/associated-types/issue-87261.rs6
-rw-r--r--src/test/ui/associated-types/issue-87261.stderr18
-rw-r--r--src/test/ui/async-await/in-trait/issue-102310.rs15
-rw-r--r--src/test/ui/async-await/issues/issue-72312.stderr13
-rw-r--r--src/test/ui/async-await/no-const-async.stderr2
-rw-r--r--src/test/ui/attr-from-macro.rs20
-rw-r--r--src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs6
-rw-r--r--src/test/ui/auxiliary/attr-from-macro.rs15
-rw-r--r--src/test/ui/binop/issue-77910-1.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr5
-rw-r--r--src/test/ui/borrowck/issue-103250.rs37
-rw-r--r--src/test/ui/borrowck/issue-103250.stderr17
-rw-r--r--src/test/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs (renamed from src/test/ui/issues/issue-23338-params-outlive-temps-of-body.rs)0
-rw-r--r--src/test/ui/borrowck/two-phase-across-loop.stderr5
-rw-r--r--src/test/ui/closures/closure-bounds-subtype.stderr4
-rw-r--r--src/test/ui/closures/issue-97607.rs12
-rw-r--r--src/test/ui/command/command-current-dir.rs1
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/closures.stderr4
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs1
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/function-call.rs1
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/function-call.stderr2
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.rs1
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.stderr16
-rw-r--r--src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs1
-rw-r--r--src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr6
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr20
-rw-r--r--src/test/ui/consts/issue-25826.stderr4
-rw-r--r--src/test/ui/consts/issue-94675.stderr4
-rw-r--r--src/test/ui/deriving/deriving-all-codegen.rs2
-rw-r--r--src/test/ui/deriving/deriving-all-codegen.stdout80
-rw-r--r--src/test/ui/deriving/deriving-hash.rs20
-rw-r--r--src/test/ui/deriving/issue-103157.rs12
-rw-r--r--src/test/ui/deriving/issue-103157.stderr30
-rw-r--r--src/test/ui/drop/drop_order.rs4
-rw-r--r--src/test/ui/drop/issue-100276.rs12
-rw-r--r--src/test/ui/drop/issue-23338-ensure-param-drop-order.rs (renamed from src/test/ui/issues/issue-23338-ensure-param-drop-order.rs)0
-rw-r--r--src/test/ui/dropck/issue-24805-dropck-itemless.rs (renamed from src/test/ui/issues/issue-24805-dropck-itemless.rs)0
-rw-r--r--src/test/ui/empty_global_asm.rs15
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_sym.rs19
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_sym.stderr21
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-89008.stderr19
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-91762.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-89008.rs (renamed from src/test/ui/generic-associated-types/bugs/issue-89008.rs)28
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-100689.rs29
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-102899.rs32
-rw-r--r--src/test/ui/hygiene/globs.stderr18
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.stderr8
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak.stderr8
-rw-r--r--src/test/ui/impl-trait/hidden-lifetimes.stderr4
-rw-r--r--src/test/ui/impl-trait/in-trait/default-body-type-err-2.rs13
-rw-r--r--src/test/ui/impl-trait/in-trait/default-body-type-err-2.stderr11
-rw-r--r--src/test/ui/impl-trait/in-trait/default-body-type-err.rs13
-rw-r--r--src/test/ui/impl-trait/in-trait/default-body-type-err.stderr12
-rw-r--r--src/test/ui/impl-trait/in-trait/default-body-with-rpit.rs2
-rw-r--r--src/test/ui/impl-trait/in-trait/default-body-with-rpit.stderr12
-rw-r--r--src/test/ui/impl-trait/in-trait/issue-102301.rs18
-rw-r--r--src/test/ui/impl-trait/issue-103181-1.rs85
-rw-r--r--src/test/ui/impl-trait/issue-103181-1.stderr12
-rw-r--r--src/test/ui/impl-trait/issue-103181-2.rs29
-rw-r--r--src/test/ui/impl-trait/issue-103181-2.stderr9
-rw-r--r--src/test/ui/impl-trait/issue-86465.rs6
-rw-r--r--src/test/ui/impl-trait/issue-86465.stderr2
-rw-r--r--src/test/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs23
-rw-r--r--src/test/ui/inference/char-as-str-single.fixed1
-rw-r--r--src/test/ui/inference/char-as-str-single.rs1
-rw-r--r--src/test/ui/inference/char-as-str-single.stderr15
-rw-r--r--src/test/ui/inference/issue-36053.rs (renamed from src/test/ui/issues/issue-36053.rs)0
-rw-r--r--src/test/ui/inference/need_type_info/issue-103053.rs18
-rw-r--r--src/test/ui/inference/need_type_info/issue-103053.stderr14
-rw-r--r--src/test/ui/inference/str-as-char.fixed4
-rw-r--r--src/test/ui/inference/str-as-char.rs4
-rw-r--r--src/test/ui/inference/str-as-char.stderr24
-rw-r--r--src/test/ui/issues/issue-30490.rs1
-rw-r--r--src/test/ui/issues/issue-35241.stderr2
-rw-r--r--src/test/ui/issues/issue-59488.stderr4
-rw-r--r--src/test/ui/issues/issue-6458-3.stderr6
-rw-r--r--src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr2
-rw-r--r--src/test/ui/let-else/let-else-non-diverging.rs2
-rw-r--r--src/test/ui/lexical-scopes.stderr2
-rw-r--r--src/test/ui/lifetimes/elided-lifetime-in-param-pat.rs11
-rw-r--r--src/test/ui/lint/invalid_value.rs7
-rw-r--r--src/test/ui/lint/invalid_value.stderr113
-rw-r--r--src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr42
-rw-r--r--src/test/ui/lint/unused/unused-supertrait.rs11
-rw-r--r--src/test/ui/lint/unused/unused-supertrait.stderr15
-rw-r--r--src/test/ui/macros/macro-context.stderr2
-rw-r--r--src/test/ui/methods/issues/issue-90315.rs79
-rw-r--r--src/test/ui/methods/issues/issue-90315.stderr198
-rw-r--r--src/test/ui/mir/mir_let_chains_drop_order.rs8
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr15
-rw-r--r--src/test/ui/nll/closures-in-loops.stderr16
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.stderr16
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr6
-rw-r--r--src/test/ui/parser/issues/issue-93282.rs1
-rw-r--r--src/test/ui/parser/issues/issue-93282.stderr27
-rw-r--r--src/test/ui/parser/label-is-actually-char.rs16
-rw-r--r--src/test/ui/parser/label-is-actually-char.stderr46
-rw-r--r--src/test/ui/parser/numeric-lifetime.stderr16
-rw-r--r--src/test/ui/parser/require-parens-for-chained-comparison.rs2
-rw-r--r--src/test/ui/parser/require-parens-for-chained-comparison.stderr16
-rw-r--r--src/test/ui/parser/semi-after-closure-in-macro.rs14
-rw-r--r--src/test/ui/privacy/access_levels.rs34
-rw-r--r--src/test/ui/privacy/access_levels.stderr34
-rw-r--r--src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr4
-rw-r--r--src/test/ui/proc-macro/mixed-site-span.stderr4
-rw-r--r--src/test/ui/process/process-spawn-with-unicode-params.rs1
-rw-r--r--src/test/ui/query-visibility.rs9
-rw-r--r--src/test/ui/resolve/issue-103202.rs7
-rw-r--r--src/test/ui/resolve/issue-103202.stderr9
-rw-r--r--src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr13
-rw-r--r--src/test/ui/resolve/privacy-enum-ctor.stderr6
-rw-r--r--src/test/ui/return/issue-64620.rs (renamed from src/test/ui/issues/issue-64620.rs)0
-rw-r--r--src/test/ui/return/issue-64620.stderr (renamed from src/test/ui/issues/issue-64620.stderr)0
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs11
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr17
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs18
-rw-r--r--src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr15
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr5
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr65
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs12
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr65
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-90052.rs9
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-90052.stderr14
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr14
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr8
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs17
-rw-r--r--src/test/ui/runtime/rt-explody-panic-payloads.rs11
-rw-r--r--src/test/ui/single-use-lifetime/derive-eq.rs11
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-trait-impl.rs16
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr16
-rw-r--r--src/test/ui/structs-enums/issue-2718-a.rs (renamed from src/test/ui/issues/issue-2718-a.rs)0
-rw-r--r--src/test/ui/structs-enums/issue-2718-a.stderr (renamed from src/test/ui/issues/issue-2718-a.stderr)0
-rw-r--r--src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr9
-rw-r--r--src/test/ui/suggestions/call-on-unimplemented-ctor.rs17
-rw-r--r--src/test/ui/suggestions/call-on-unimplemented-ctor.stderr21
-rw-r--r--src/test/ui/suggestions/call-on-unimplemented-fn-ptr.rs15
-rw-r--r--src/test/ui/suggestions/call-on-unimplemented-fn-ptr.stderr21
-rw-r--r--src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr9
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr6
-rw-r--r--src/test/ui/suggestions/issue-103112.rs4
-rw-r--r--src/test/ui/suggestions/issue-103112.stderr15
-rw-r--r--src/test/ui/suggestions/suggest-let-for-assignment.fixed17
-rw-r--r--src/test/ui/suggestions/suggest-let-for-assignment.rs17
-rw-r--r--src/test/ui/suggestions/suggest-let-for-assignment.stderr60
-rw-r--r--src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs1
-rw-r--r--src/test/ui/test-attrs/test-thread-capture.rs1
-rw-r--r--src/test/ui/test-attrs/test-thread-capture.run.stdout2
-rw-r--r--src/test/ui/test-attrs/test-thread-nocapture.rs1
-rw-r--r--src/test/ui/test-attrs/test-thread-nocapture.run.stderr2
-rw-r--r--src/test/ui/threads-sendsync/sync-send-in-std.rs1
-rw-r--r--src/test/ui/traits/issue-33140-hack-boundaries.stderr17
-rw-r--r--src/test/ui/traits/object/issue-33140-traitobject-crate.stderr53
-rw-r--r--src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs (renamed from src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs)0
-rw-r--r--src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr (renamed from src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr)2
-rw-r--r--src/test/ui/treat-err-as-bug/delay_span_bug.rs2
-rw-r--r--src/test/ui/treat-err-as-bug/delay_span_bug.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs6
-rw-r--r--src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs7
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr12
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_lifetime_param.rs5
-rw-r--r--src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-89686.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-89686.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs7
-rw-r--r--src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr8
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs6
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs6
-rw-r--r--src/test/ui/typeck/issue-87181/empty-tuple-method.stderr2
-rw-r--r--src/test/ui/typeck/issue-87181/enum-variant.stderr2
-rw-r--r--src/test/ui/typeck/issue-87181/tuple-field.stderr2
-rw-r--r--src/test/ui/typeck/slow-lhs-suggestion.rs26
-rw-r--r--src/test/ui/typeck/slow-lhs-suggestion.stderr187
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs7
-rw-r--r--src/tools/clippy/tests/ui/entry.fixed1
-rw-r--r--src/tools/clippy/tests/ui/entry.rs1
-rw-r--r--src/tools/clippy/tests/ui/entry.stderr20
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.stderr55
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.stderr55
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.rs1
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.stderr48
-rw-r--r--src/tools/compiletest/src/header.rs15
-rw-r--r--src/tools/compiletest/src/main.rs6
-rw-r--r--src/tools/miri/tests/pass-dep/shims/fs.rs28
-rw-r--r--src/tools/remote-test-server/src/main.rs25
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml27
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml10
-rw-r--r--src/tools/rust-analyzer/Cargo.lock189
-rw-r--r--src/tools/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/cfg/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs99
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs71
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs88
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs92
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs822
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs113
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs41
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs76
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs150
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs45
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs1939
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs22
-rw-r--r--src/tools/rust-analyzer/crates/mbe/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/benchmark.rs30
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander.rs3
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs54
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs57
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/parser.rs41
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/profile/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs56
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs23
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs53
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs85
-rw-r--r--src/tools/rust-analyzer/crates/text-edit/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/docs/dev/guide.md5
-rw-r--r--src/tools/rust-analyzer/docs/dev/syntax.md6
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc17
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts16
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/xtask/Cargo.toml2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--triagebot.toml36
769 files changed, 17613 insertions, 9402 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f393a918094..3e1c904e337 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1843,9 +1843,9 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.10.1"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
 dependencies = [
  "either",
 ]
@@ -2652,9 +2652,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "pkg-config"
-version = "0.3.18"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
+checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
 
 [[package]]
 name = "polonius-engine"
@@ -3569,6 +3569,32 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_hir_typeck"
+version = "0.1.0"
+dependencies = [
+ "rustc_ast",
+ "rustc_data_structures",
+ "rustc_errors",
+ "rustc_graphviz",
+ "rustc_hir",
+ "rustc_hir_analysis",
+ "rustc_hir_pretty",
+ "rustc_index",
+ "rustc_infer",
+ "rustc_lint",
+ "rustc_macros",
+ "rustc_middle",
+ "rustc_serialize",
+ "rustc_session",
+ "rustc_span",
+ "rustc_target",
+ "rustc_trait_selection",
+ "rustc_type_ir",
+ "smallvec",
+ "tracing",
+]
+
+[[package]]
 name = "rustc_incremental"
 version = "0.0.0"
 dependencies = [
@@ -3637,6 +3663,7 @@ dependencies = [
  "rustc_expand",
  "rustc_hir",
  "rustc_hir_analysis",
+ "rustc_hir_typeck",
  "rustc_incremental",
  "rustc_lint",
  "rustc_macros",
@@ -4448,9 +4475,9 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.143"
+version = "1.0.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
+checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
 dependencies = [
  "serde_derive",
 ]
@@ -4467,9 +4494,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.143"
+version = "1.0.147"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
+checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4953,16 +4980,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_datetime"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808b51e57d0ef8f71115d8f3a01e7d3750d01c79cac4b3eda910f4389fdf92fd"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "toml_edit"
-version = "0.14.3"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba98375fd631b83696f87c64e4ed8e29e6a1f3404d6aed95fa95163bad38e705"
+checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646"
 dependencies = [
  "combine",
  "indexmap",
  "itertools",
  "kstring",
  "serde",
+ "toml_datetime",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 60b7f2e4c22..7112c267577 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2060,8 +2060,11 @@ impl TyKind {
     }
 
     pub fn is_simple_path(&self) -> Option<Symbol> {
-        if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 {
-            Some(segments[0].ident.name)
+        if let TyKind::Path(None, Path { segments, .. }) = &self
+            && let [segment] = &segments[..]
+            && segment.args.is_none()
+        {
+            Some(segment.ident.name)
         } else {
             None
         }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 54c83fb7604..450cdf246b1 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -192,16 +192,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     InlineAsmOperand::Sym { ref sym } => {
-                        if !self.tcx.features().asm_sym {
-                            feature_err(
-                                &sess.parse_sess,
-                                sym::asm_sym,
-                                *op_sp,
-                                "sym operands for inline assembly are unstable",
-                            )
-                            .emit();
-                        }
-
                         let static_def_id = self
                             .resolver
                             .get_partial_res(sym.id)
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index c6c85ffa84d..157f46501e1 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -1,12 +1,9 @@
-use rustc_errors::{
-    fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay,
-    SubdiagnosticMessage,
-};
+use rustc_errors::DiagnosticArgFromDisplay;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")]
+#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")]
 pub struct GenericTypeWithParentheses {
     #[primary_span]
     #[label]
@@ -15,27 +12,17 @@ pub struct GenericTypeWithParentheses {
     pub sub: Option<UseAngleBrackets>,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
+#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
 pub struct UseAngleBrackets {
+    #[suggestion_part(code = "<")]
     pub open_param: Span,
+    #[suggestion_part(code = ">")]
     pub close_param: Span,
 }
 
-impl AddToDiagnostic for UseAngleBrackets {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        diag.multipart_suggestion(
-            fluent::ast_lowering::use_angle_brackets,
-            vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
-            Applicability::MaybeIncorrect,
-        );
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(ast_lowering::invalid_abi, code = "E0703")]
+#[diag(ast_lowering_invalid_abi, code = "E0703")]
 #[note]
 pub struct InvalidAbi {
     #[primary_span]
@@ -49,7 +36,7 @@ pub struct InvalidAbi {
 
 #[derive(Subdiagnostic)]
 #[suggestion(
-    ast_lowering::invalid_abi_suggestion,
+    ast_lowering_invalid_abi_suggestion,
     code = "{suggestion}",
     applicability = "maybe-incorrect"
 )]
@@ -60,7 +47,7 @@ pub struct InvalidAbiSuggestion {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::assoc_ty_parentheses)]
+#[diag(ast_lowering_assoc_ty_parentheses)]
 pub struct AssocTyParentheses {
     #[primary_span]
     pub span: Span,
@@ -68,34 +55,24 @@ pub struct AssocTyParentheses {
     pub sub: AssocTyParenthesesSub,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
 pub enum AssocTyParenthesesSub {
-    Empty { parentheses_span: Span },
-    NotEmpty { open_param: Span, close_param: Span },
-}
-
-impl AddToDiagnostic for AssocTyParenthesesSub {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self {
-            Self::Empty { parentheses_span } => diag.multipart_suggestion(
-                fluent::ast_lowering::remove_parentheses,
-                vec![(parentheses_span, String::new())],
-                Applicability::MaybeIncorrect,
-            ),
-            Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion(
-                fluent::ast_lowering::use_angle_brackets,
-                vec![(open_param, String::from("<")), (close_param, String::from(">"))],
-                Applicability::MaybeIncorrect,
-            ),
-        };
-    }
+    #[multipart_suggestion(ast_lowering_remove_parentheses)]
+    Empty {
+        #[suggestion_part(code = "")]
+        parentheses_span: Span,
+    },
+    #[multipart_suggestion(ast_lowering_use_angle_brackets)]
+    NotEmpty {
+        #[suggestion_part(code = "<")]
+        open_param: Span,
+        #[suggestion_part(code = ">")]
+        close_param: Span,
+    },
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")]
+#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")]
 pub struct MisplacedImplTrait<'a> {
     #[primary_span]
     pub span: Span,
@@ -103,14 +80,14 @@ pub struct MisplacedImplTrait<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::rustc_box_attribute_error)]
+#[diag(ast_lowering_rustc_box_attribute_error)]
 pub struct RustcBoxAttributeError {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::underscore_expr_lhs_assign)]
+#[diag(ast_lowering_underscore_expr_lhs_assign)]
 pub struct UnderscoreExprLhsAssign {
     #[primary_span]
     #[label]
@@ -118,7 +95,7 @@ pub struct UnderscoreExprLhsAssign {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::base_expression_double_dot)]
+#[diag(ast_lowering_base_expression_double_dot)]
 pub struct BaseExpressionDoubleDot {
     #[primary_span]
     #[label]
@@ -126,24 +103,24 @@ pub struct BaseExpressionDoubleDot {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")]
+#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")]
 pub struct AwaitOnlyInAsyncFnAndBlocks {
     #[primary_span]
     #[label]
     pub dot_await_span: Span,
-    #[label(ast_lowering::this_not_async)]
+    #[label(ast_lowering_this_not_async)]
     pub item_span: Option<Span>,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")]
+#[diag(ast_lowering_generator_too_many_parameters, code = "E0628")]
 pub struct GeneratorTooManyParameters {
     #[primary_span]
     pub fn_decl_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")]
+#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")]
 pub struct ClosureCannotBeStatic {
     #[primary_span]
     pub fn_decl_span: Span,
@@ -151,14 +128,14 @@ pub struct ClosureCannotBeStatic {
 
 #[derive(Diagnostic, Clone, Copy)]
 #[help]
-#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")]
+#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
 pub struct AsyncNonMoveClosureNotSupported {
     #[primary_span]
     pub fn_decl_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::functional_record_update_destructuring_assignment)]
+#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
 pub struct FunctionalRecordUpdateDestructuringAssignemnt {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -166,28 +143,28 @@ pub struct FunctionalRecordUpdateDestructuringAssignemnt {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::async_generators_not_supported, code = "E0727")]
+#[diag(ast_lowering_async_generators_not_supported, code = "E0727")]
 pub struct AsyncGeneratorsNotSupported {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")]
+#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")]
 pub struct InlineAsmUnsupportedTarget {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::att_syntax_only_x86)]
+#[diag(ast_lowering_att_syntax_only_x86)]
 pub struct AttSyntaxOnlyX86 {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::abi_specified_multiple_times)]
+#[diag(ast_lowering_abi_specified_multiple_times)]
 pub struct AbiSpecifiedMultipleTimes {
     #[primary_span]
     pub abi_span: Span,
@@ -199,7 +176,7 @@ pub struct AbiSpecifiedMultipleTimes {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::clobber_abi_not_supported)]
+#[diag(ast_lowering_clobber_abi_not_supported)]
 pub struct ClobberAbiNotSupported {
     #[primary_span]
     pub abi_span: Span,
@@ -207,7 +184,7 @@ pub struct ClobberAbiNotSupported {
 
 #[derive(Diagnostic)]
 #[note]
-#[diag(ast_lowering::invalid_abi_clobber_abi)]
+#[diag(ast_lowering_invalid_abi_clobber_abi)]
 pub struct InvalidAbiClobberAbi {
     #[primary_span]
     pub abi_span: Span,
@@ -215,7 +192,7 @@ pub struct InvalidAbiClobberAbi {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_register)]
+#[diag(ast_lowering_invalid_register)]
 pub struct InvalidRegister<'a> {
     #[primary_span]
     pub op_span: Span,
@@ -224,7 +201,7 @@ pub struct InvalidRegister<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_register_class)]
+#[diag(ast_lowering_invalid_register_class)]
 pub struct InvalidRegisterClass<'a> {
     #[primary_span]
     pub op_span: Span,
@@ -233,12 +210,12 @@ pub struct InvalidRegisterClass<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)]
+#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
 pub struct InvalidAsmTemplateModifierRegClass {
     #[primary_span]
-    #[label(ast_lowering::template_modifier)]
+    #[label(ast_lowering_template_modifier)]
     pub placeholder_span: Span,
-    #[label(ast_lowering::argument)]
+    #[label(ast_lowering_argument)]
     pub op_span: Span,
     #[subdiagnostic]
     pub sub: InvalidAsmTemplateModifierRegClassSub,
@@ -246,34 +223,34 @@ pub struct InvalidAsmTemplateModifierRegClass {
 
 #[derive(Subdiagnostic)]
 pub enum InvalidAsmTemplateModifierRegClassSub {
-    #[note(ast_lowering::support_modifiers)]
+    #[note(ast_lowering_support_modifiers)]
     SupportModifier { class_name: Symbol, modifiers: String },
-    #[note(ast_lowering::does_not_support_modifiers)]
+    #[note(ast_lowering_does_not_support_modifiers)]
     DoesNotSupportModifier { class_name: Symbol },
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_asm_template_modifier_const)]
+#[diag(ast_lowering_invalid_asm_template_modifier_const)]
 pub struct InvalidAsmTemplateModifierConst {
     #[primary_span]
-    #[label(ast_lowering::template_modifier)]
+    #[label(ast_lowering_template_modifier)]
     pub placeholder_span: Span,
-    #[label(ast_lowering::argument)]
+    #[label(ast_lowering_argument)]
     pub op_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_asm_template_modifier_sym)]
+#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
 pub struct InvalidAsmTemplateModifierSym {
     #[primary_span]
-    #[label(ast_lowering::template_modifier)]
+    #[label(ast_lowering_template_modifier)]
     pub placeholder_span: Span,
-    #[label(ast_lowering::argument)]
+    #[label(ast_lowering_argument)]
     pub op_span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::register_class_only_clobber)]
+#[diag(ast_lowering_register_class_only_clobber)]
 pub struct RegisterClassOnlyClobber {
     #[primary_span]
     pub op_span: Span,
@@ -281,12 +258,12 @@ pub struct RegisterClassOnlyClobber {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::register_conflict)]
+#[diag(ast_lowering_register_conflict)]
 pub struct RegisterConflict<'a> {
     #[primary_span]
-    #[label(ast_lowering::register1)]
+    #[label(ast_lowering_register1)]
     pub op_span1: Span,
-    #[label(ast_lowering::register2)]
+    #[label(ast_lowering_register2)]
     pub op_span2: Span,
     pub reg1_name: &'a str,
     pub reg2_name: &'a str,
@@ -296,12 +273,12 @@ pub struct RegisterConflict<'a> {
 
 #[derive(Diagnostic, Clone, Copy)]
 #[help]
-#[diag(ast_lowering::sub_tuple_binding)]
+#[diag(ast_lowering_sub_tuple_binding)]
 pub struct SubTupleBinding<'a> {
     #[primary_span]
     #[label]
     #[suggestion_verbose(
-        ast_lowering::sub_tuple_binding_suggestion,
+        ast_lowering_sub_tuple_binding_suggestion,
         code = "..",
         applicability = "maybe-incorrect"
     )]
@@ -312,56 +289,56 @@ pub struct SubTupleBinding<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::extra_double_dot)]
+#[diag(ast_lowering_extra_double_dot)]
 pub struct ExtraDoubleDot<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(ast_lowering::previously_used_here)]
+    #[label(ast_lowering_previously_used_here)]
     pub prev_span: Span,
     pub ctx: &'a str,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
 #[note]
-#[diag(ast_lowering::misplaced_double_dot)]
+#[diag(ast_lowering_misplaced_double_dot)]
 pub struct MisplacedDoubleDot {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::misplaced_relax_trait_bound)]
+#[diag(ast_lowering_misplaced_relax_trait_bound)]
 pub struct MisplacedRelaxTraitBound {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)]
+#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)]
 pub struct NotSupportedForLifetimeBinderAsyncClosure {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::arbitrary_expression_in_pattern)]
+#[diag(ast_lowering_arbitrary_expression_in_pattern)]
 pub struct ArbitraryExpressionInPattern {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::inclusive_range_with_no_end)]
+#[diag(ast_lowering_inclusive_range_with_no_end)]
 pub struct InclusiveRangeWithNoEnd {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering::trait_fn_async, code = "E0706")]
+#[diag(ast_lowering_trait_fn_async, code = "E0706")]
 #[note]
-#[note(ast_lowering::note2)]
+#[note(note2)]
 pub struct TraitFnAsync {
     #[primary_span]
     pub fn_span: Span,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 724056f7268..427b71722ab 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -507,6 +507,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
+    /// resolver (if any).
+    fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+        self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
+    }
+
+    fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
+        self.orig_opt_local_def_id(node)
+            .unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+    }
+
+    /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
     ///
     /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
@@ -520,10 +531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
     /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.resolver
-            .node_id_to_def_id
-            .get(&node)
-            .map(|local_def_id| self.get_remapped_def_id(*local_def_id))
+        self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id))
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
@@ -532,9 +540,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
     /// `generics_def_id_map` field.
-    fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+    fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId {
         // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
-        // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+        // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`.
         //
         // Consider:
         //
@@ -544,18 +552,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         //
         // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
         //
-        // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
-        // impl_sized#'b, so iterating forward is the wrong thing to do.
-        for map in self.generics_def_id_map.iter().rev() {
-            if let Some(r) = map.get(&local_def_id) {
-                debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
-                local_def_id = *r;
-            } else {
-                debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
-            }
-        }
-
-        local_def_id
+        // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b.
+        // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b.
+        self.generics_def_id_map
+            .iter()
+            .rev()
+            .find_map(|map| map.get(&local_def_id).map(|local_def_id| *local_def_id))
+            .unwrap_or(local_def_id)
     }
 
     /// Freshen the `LoweringContext` and ready it to lower a nested item.
@@ -1633,7 +1636,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
+                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
                         let node_id = self.next_node_id();
 
                         let new_def_id = self.create_def(
@@ -1878,7 +1881,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
         debug!(?extra_lifetime_params);
         for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let outer_def_id = self.local_def_id(outer_node_id);
+            let outer_def_id = self.orig_local_def_id(outer_node_id);
             let inner_node_id = self.next_node_id();
 
             // Add a definition for the in scope lifetime def.
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 1a4c60087c3..03664324404 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -14,6 +14,7 @@ use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
+use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
     DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -38,6 +39,13 @@ enum SelfSemantic {
     No,
 }
 
+/// What is the context that prevents using `~const`?
+enum DisallowTildeConstContext<'a> {
+    TraitObject,
+    ImplTrait,
+    Fn(FnKind<'a>),
+}
+
 struct AstValidator<'a> {
     session: &'a Session,
 
@@ -56,7 +64,7 @@ struct AstValidator<'a> {
     /// e.g., `impl Iterator<Item = impl Debug>`.
     outer_impl_trait: Option<Span>,
 
-    is_tilde_const_allowed: bool,
+    disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
 
     /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
     /// or `Foo::Bar<impl Trait>`
@@ -93,18 +101,26 @@ impl<'a> AstValidator<'a> {
         self.is_impl_trait_banned = old;
     }
 
-    fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
+    fn with_tilde_const(
+        &mut self,
+        disallowed: Option<DisallowTildeConstContext<'a>>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
         f(self);
-        self.is_tilde_const_allowed = old;
+        self.disallow_tilde_const = old;
     }
 
     fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
-        self.with_tilde_const(true, f)
+        self.with_tilde_const(None, f)
     }
 
-    fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
-        self.with_tilde_const(false, f)
+    fn with_banned_tilde_const(
+        &mut self,
+        ctx: DisallowTildeConstContext<'a>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        self.with_tilde_const(Some(ctx), f)
     }
 
     fn with_let_management(
@@ -154,7 +170,7 @@ impl<'a> AstValidator<'a> {
                 DEPRECATED_WHERE_CLAUSE_LOCATION,
                 id,
                 where_clauses.0.1,
-                fluent::ast_passes::deprecated_where_clause_location,
+                fluent::ast_passes_deprecated_where_clause_location,
                 BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
                     where_clauses.1.1.shrink_to_hi(),
                     suggestion,
@@ -172,7 +188,7 @@ impl<'a> AstValidator<'a> {
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.outer_impl_trait, outer);
         if outer.is_some() {
-            self.with_banned_tilde_const(f);
+            self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
         } else {
             f(self);
         }
@@ -197,7 +213,10 @@ impl<'a> AstValidator<'a> {
             TyKind::ImplTrait(..) => {
                 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
             }
-            TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
+            TyKind::TraitObject(..) => self
+                .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
+                    visit::walk_ty(this, t)
+                }),
             TyKind::Path(ref qself, ref path) => {
                 // We allow these:
                 //  - `Option<impl Trait>`
@@ -233,20 +252,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
-        if let Some(ident) = field.ident {
-            if ident.name == kw::Underscore {
-                self.visit_vis(&field.vis);
-                self.visit_ident(ident);
-                self.visit_ty_common(&field.ty);
-                self.walk_ty(&field.ty);
-                walk_list!(self, visit_attribute, &field.attrs);
-                return;
-            }
-        }
-        self.visit_field_def(field);
-    }
-
     fn err_handler(&self) -> &rustc_errors::Handler {
         &self.session.diagnostic()
     }
@@ -987,8 +992,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_lifetime(self, lifetime);
     }
 
-    fn visit_field_def(&mut self, s: &'a FieldDef) {
-        visit::walk_field_def(self, s)
+    fn visit_field_def(&mut self, field: &'a FieldDef) {
+        visit::walk_field_def(self, field)
     }
 
     fn visit_item(&mut self, item: &'a Item) {
@@ -1176,42 +1181,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
             }
-            ItemKind::Struct(ref vdata, ref generics) => match vdata {
-                // Duplicating the `Visitor` logic allows catching all cases
-                // of `Anonymous(Struct, Union)` outside of a field struct or union.
-                //
-                // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
-                // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
-                // it uses `visit_ty_common`, which doesn't contain that specific check.
-                VariantData::Struct(ref fields, ..) => {
-                    self.visit_vis(&item.vis);
-                    self.visit_ident(item.ident);
-                    self.visit_generics(generics);
-                    self.with_banned_assoc_ty_bound(|this| {
-                        walk_list!(this, visit_struct_field_def, fields);
-                    });
-                    walk_list!(self, visit_attribute, &item.attrs);
-                    return;
-                }
-                _ => {}
-            },
-            ItemKind::Union(ref vdata, ref generics) => {
+            ItemKind::Union(ref vdata, ..) => {
                 if vdata.fields().is_empty() {
                     self.err_handler().span_err(item.span, "unions cannot have zero fields");
                 }
-                match vdata {
-                    VariantData::Struct(ref fields, ..) => {
-                        self.visit_vis(&item.vis);
-                        self.visit_ident(item.ident);
-                        self.visit_generics(generics);
-                        self.with_banned_assoc_ty_bound(|this| {
-                            walk_list!(this, visit_struct_field_def, fields);
-                        });
-                        walk_list!(self, visit_attribute, &item.attrs);
-                        return;
-                    }
-                    _ => {}
-                }
             }
             ItemKind::Const(def, .., None) => {
                 self.check_defaultness(item.span, def);
@@ -1411,13 +1384,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     );
                     err.emit();
                 }
-                (_, TraitBoundModifier::MaybeConst) => {
-                    if !self.is_tilde_const_allowed {
-                        self.err_handler()
-                            .struct_span_err(bound.span(), "`~const` is not allowed here")
-                            .note("only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions")
-                            .emit();
-                    }
+                (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
+                    let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
+                    match reason {
+                        DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
+                        DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
+                        DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
+                        DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
+                    };
+                    err.emit();
                 }
                 (_, TraitBoundModifier::MaybeConstMaybe) => {
                     self.err_handler()
@@ -1523,10 +1498,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             });
         }
 
-        let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { .. }))
-            || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+        let tilde_const_allowed =
+            matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
+                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+
+        let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
 
-        self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
+        self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1770,7 +1748,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
         in_const_trait_impl: false,
         has_proc_macro_decls: false,
         outer_impl_trait: None,
-        is_tilde_const_allowed: false,
+        disallow_tilde_const: None,
         is_impl_trait_banned: false,
         is_assoc_ty_bound_banned: false,
         forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
@@ -1782,15 +1760,17 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
 }
 
 /// Used to forbid `let` expressions in certain syntactic locations.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
 pub(crate) enum ForbiddenLetReason {
     /// `let` is not valid and the source environment is not important
     GenericForbidden,
     /// A let chain with the `||` operator
-    NotSupportedOr(Span),
+    #[note(not_supported_or)]
+    NotSupportedOr(#[primary_span] Span),
     /// A let chain with invalid parentheses
     ///
     /// For example, `let 1 = 1 && (expr && expr)` is allowed
     /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
-    NotSupportedParentheses(Span),
+    #[note(not_supported_parentheses)]
+    NotSupportedParentheses(#[primary_span] Span),
 }
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ba2ed24fc08..59f582f10d9 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -7,7 +7,7 @@ use rustc_span::{Span, Symbol};
 use crate::ast_validation::ForbiddenLetReason;
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_let)]
+#[diag(ast_passes_forbidden_let)]
 #[note]
 pub struct ForbiddenLet {
     #[primary_span]
@@ -16,25 +16,8 @@ pub struct ForbiddenLet {
     pub(crate) reason: ForbiddenLetReason,
 }
 
-impl AddToDiagnostic for ForbiddenLetReason {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self {
-            Self::GenericForbidden => {}
-            Self::NotSupportedOr(span) => {
-                diag.span_note(span, fluent::ast_passes::not_supported_or);
-            }
-            Self::NotSupportedParentheses(span) => {
-                diag.span_note(span, fluent::ast_passes::not_supported_parentheses);
-            }
-        }
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_let_stable)]
+#[diag(ast_passes_forbidden_let_stable)]
 #[note]
 pub struct ForbiddenLetStable {
     #[primary_span]
@@ -42,21 +25,21 @@ pub struct ForbiddenLetStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_assoc_constraint)]
+#[diag(ast_passes_forbidden_assoc_constraint)]
 pub struct ForbiddenAssocConstraint {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::keyword_lifetime)]
+#[diag(ast_passes_keyword_lifetime)]
 pub struct KeywordLifetime {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::invalid_label)]
+#[diag(ast_passes_invalid_label)]
 pub struct InvalidLabel {
     #[primary_span]
     pub span: Span,
@@ -64,11 +47,11 @@ pub struct InvalidLabel {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::invalid_visibility, code = "E0449")]
+#[diag(ast_passes_invalid_visibility, code = "E0449")]
 pub struct InvalidVisibility {
     #[primary_span]
     pub span: Span,
-    #[label(ast_passes::implied)]
+    #[label(implied)]
     pub implied: Option<Span>,
     #[subdiagnostic]
     pub note: Option<InvalidVisibilityNote>,
@@ -76,14 +59,14 @@ pub struct InvalidVisibility {
 
 #[derive(Subdiagnostic)]
 pub enum InvalidVisibilityNote {
-    #[note(ast_passes::individual_impl_items)]
+    #[note(individual_impl_items)]
     IndividualImplItems,
-    #[note(ast_passes::individual_foreign_items)]
+    #[note(individual_foreign_items)]
     IndividualForeignItems,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::trait_fn_const, code = "E0379")]
+#[diag(ast_passes_trait_fn_const, code = "E0379")]
 pub struct TraitFnConst {
     #[primary_span]
     #[label]
@@ -91,21 +74,21 @@ pub struct TraitFnConst {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_lifetime_bound)]
+#[diag(ast_passes_forbidden_lifetime_bound)]
 pub struct ForbiddenLifetimeBound {
     #[primary_span]
     pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_non_lifetime_param)]
+#[diag(ast_passes_forbidden_non_lifetime_param)]
 pub struct ForbiddenNonLifetimeParam {
     #[primary_span]
     pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_too_many)]
+#[diag(ast_passes_fn_param_too_many)]
 pub struct FnParamTooMany {
     #[primary_span]
     pub span: Span,
@@ -113,21 +96,21 @@ pub struct FnParamTooMany {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_c_var_args_only)]
+#[diag(ast_passes_fn_param_c_var_args_only)]
 pub struct FnParamCVarArgsOnly {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_c_var_args_not_last)]
+#[diag(ast_passes_fn_param_c_var_args_not_last)]
 pub struct FnParamCVarArgsNotLast {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_doc_comment)]
+#[diag(ast_passes_fn_param_doc_comment)]
 pub struct FnParamDocComment {
     #[primary_span]
     #[label]
@@ -135,14 +118,14 @@ pub struct FnParamDocComment {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_forbidden_attr)]
+#[diag(ast_passes_fn_param_forbidden_attr)]
 pub struct FnParamForbiddenAttr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_param_forbidden_self)]
+#[diag(ast_passes_fn_param_forbidden_self)]
 #[note]
 pub struct FnParamForbiddenSelf {
     #[primary_span]
@@ -151,7 +134,7 @@ pub struct FnParamForbiddenSelf {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::forbidden_default)]
+#[diag(ast_passes_forbidden_default)]
 pub struct ForbiddenDefault {
     #[primary_span]
     pub span: Span,
@@ -160,7 +143,7 @@ pub struct ForbiddenDefault {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::assoc_const_without_body)]
+#[diag(ast_passes_assoc_const_without_body)]
 pub struct AssocConstWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -169,7 +152,7 @@ pub struct AssocConstWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::assoc_fn_without_body)]
+#[diag(ast_passes_assoc_fn_without_body)]
 pub struct AssocFnWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -178,7 +161,7 @@ pub struct AssocFnWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::assoc_type_without_body)]
+#[diag(ast_passes_assoc_type_without_body)]
 pub struct AssocTypeWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -187,7 +170,7 @@ pub struct AssocTypeWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::const_without_body)]
+#[diag(ast_passes_const_without_body)]
 pub struct ConstWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -196,7 +179,7 @@ pub struct ConstWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::static_without_body)]
+#[diag(ast_passes_static_without_body)]
 pub struct StaticWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -205,7 +188,7 @@ pub struct StaticWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::ty_alias_without_body)]
+#[diag(ast_passes_ty_alias_without_body)]
 pub struct TyAliasWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -214,7 +197,7 @@ pub struct TyAliasWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes::fn_without_body)]
+#[diag(ast_passes_fn_without_body)]
 pub struct FnWithoutBody {
     #[primary_span]
     pub span: Span,
@@ -243,7 +226,7 @@ impl AddToDiagnostic for ExternBlockSuggestion {
         let end_suggestion = " }".to_owned();
 
         diag.multipart_suggestion(
-            fluent::ast_passes::extern_block_suggestion,
+            fluent::extern_block_suggestion,
             vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
             Applicability::MaybeIncorrect,
         );
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index d3e9a16a9a8..edccfa1c8ff 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -10,14 +10,14 @@ use rustc_span::{Span, Symbol};
 use crate::UnsupportedLiteralReason;
 
 #[derive(Diagnostic)]
-#[diag(attr::expected_one_cfg_pattern, code = "E0536")]
+#[diag(attr_expected_one_cfg_pattern, code = "E0536")]
 pub(crate) struct ExpectedOneCfgPattern {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_predicate, code = "E0537")]
+#[diag(attr_invalid_predicate, code = "E0537")]
 pub(crate) struct InvalidPredicate {
     #[primary_span]
     pub span: Span,
@@ -26,7 +26,7 @@ pub(crate) struct InvalidPredicate {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::multiple_item, code = "E0538")]
+#[diag(attr_multiple_item, code = "E0538")]
 pub(crate) struct MultipleItem {
     #[primary_span]
     pub span: Span,
@@ -35,7 +35,7 @@ pub(crate) struct MultipleItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_meta_item, code = "E0539")]
+#[diag(attr_incorrect_meta_item, code = "E0539")]
 pub(crate) struct IncorrectMetaItem {
     #[primary_span]
     pub span: Span,
@@ -54,39 +54,39 @@ impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
         let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            fluent::attr::unknown_meta_item,
+            fluent::attr_unknown_meta_item,
             error_code!(E0541),
         );
         diag.set_arg("item", self.item);
         diag.set_arg("expected", expected.join(", "));
-        diag.span_label(self.span, fluent::attr::label);
+        diag.span_label(self.span, fluent::label);
         diag
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_since, code = "E0542")]
+#[diag(attr_missing_since, code = "E0542")]
 pub(crate) struct MissingSince {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_note, code = "E0543")]
+#[diag(attr_missing_note, code = "E0543")]
 pub(crate) struct MissingNote {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::multiple_stability_levels, code = "E0544")]
+#[diag(attr_multiple_stability_levels, code = "E0544")]
 pub(crate) struct MultipleStabilityLevels {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_issue_string, code = "E0545")]
+#[diag(attr_invalid_issue_string, code = "E0545")]
 pub(crate) struct InvalidIssueString {
     #[primary_span]
     pub span: Span,
@@ -99,31 +99,31 @@ pub(crate) struct InvalidIssueString {
 // translatable.
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidIssueStringCause {
-    #[label(attr::must_not_be_zero)]
+    #[label(must_not_be_zero)]
     MustNotBeZero {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::empty)]
+    #[label(empty)]
     Empty {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::invalid_digit)]
+    #[label(invalid_digit)]
     InvalidDigit {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::pos_overflow)]
+    #[label(pos_overflow)]
     PosOverflow {
         #[primary_span]
         span: Span,
     },
 
-    #[label(attr::neg_overflow)]
+    #[label(neg_overflow)]
     NegOverflow {
         #[primary_span]
         span: Span,
@@ -144,21 +144,21 @@ impl InvalidIssueStringCause {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_feature, code = "E0546")]
+#[diag(attr_missing_feature, code = "E0546")]
 pub(crate) struct MissingFeature {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::non_ident_feature, code = "E0546")]
+#[diag(attr_non_ident_feature, code = "E0546")]
 pub(crate) struct NonIdentFeature {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::missing_issue, code = "E0547")]
+#[diag(attr_missing_issue, code = "E0547")]
 pub(crate) struct MissingIssue {
     #[primary_span]
     pub span: Span,
@@ -167,7 +167,7 @@ pub(crate) struct MissingIssue {
 // FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider
 // changing this to `IncorrectMetaItem`. See #51489.
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_meta_item, code = "E0551")]
+#[diag(attr_incorrect_meta_item, code = "E0551")]
 pub(crate) struct IncorrectMetaItem2 {
     #[primary_span]
     pub span: Span,
@@ -176,14 +176,14 @@ pub(crate) struct IncorrectMetaItem2 {
 // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
 // It is more similar to `IncorrectReprFormatGeneric`.
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
+#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
 pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")]
+#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")]
 pub(crate) struct InvalidReprHintNoParen {
     #[primary_span]
     pub span: Span,
@@ -192,7 +192,7 @@ pub(crate) struct InvalidReprHintNoParen {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_hint_no_value, code = "E0552")]
+#[diag(attr_invalid_repr_hint_no_value, code = "E0552")]
 pub(crate) struct InvalidReprHintNoValue {
     #[primary_span]
     pub span: Span,
@@ -213,13 +213,13 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
             match self.reason {
-                UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
-                UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
+                UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
+                UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
                 UnsupportedLiteralReason::DeprecatedString => {
-                    fluent::attr::unsupported_literal_deprecated_string
+                    fluent::attr_unsupported_literal_deprecated_string
                 }
                 UnsupportedLiteralReason::DeprecatedKvPair => {
-                    fluent::attr::unsupported_literal_deprecated_kv_pair
+                    fluent::attr_unsupported_literal_deprecated_kv_pair
                 }
             },
             error_code!(E0565),
@@ -227,7 +227,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
         if self.is_bytestr {
             diag.span_suggestion(
                 self.start_point_span,
-                fluent::attr::unsupported_literal_suggestion,
+                fluent::attr_unsupported_literal_suggestion,
                 "",
                 Applicability::MaybeIncorrect,
             );
@@ -237,7 +237,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_align_need_arg, code = "E0589")]
+#[diag(attr_invalid_repr_align_need_arg, code = "E0589")]
 pub(crate) struct InvalidReprAlignNeedArg {
     #[primary_span]
     #[suggestion(code = "align(...)", applicability = "has-placeholders")]
@@ -245,7 +245,7 @@ pub(crate) struct InvalidReprAlignNeedArg {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::invalid_repr_generic, code = "E0589")]
+#[diag(attr_invalid_repr_generic, code = "E0589")]
 pub(crate) struct InvalidReprGeneric<'a> {
     #[primary_span]
     pub span: Span,
@@ -255,14 +255,14 @@ pub(crate) struct InvalidReprGeneric<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")]
+#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")]
 pub(crate) struct IncorrectReprFormatAlignOneArg {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::incorrect_repr_format_generic, code = "E0693")]
+#[diag(attr_incorrect_repr_format_generic, code = "E0693")]
 pub(crate) struct IncorrectReprFormatGeneric<'a> {
     #[primary_span]
     pub span: Span,
@@ -275,7 +275,7 @@ pub(crate) struct IncorrectReprFormatGeneric<'a> {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum IncorrectReprFormatGenericCause<'a> {
-    #[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")]
+    #[suggestion(suggestion, code = "{name}({int})", applicability = "machine-applicable")]
     Int {
         #[primary_span]
         span: Span,
@@ -287,11 +287,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> {
         int: u128,
     },
 
-    #[suggestion(
-        attr::suggestion,
-        code = "{name}({symbol})",
-        applicability = "machine-applicable"
-    )]
+    #[suggestion(suggestion, code = "{name}({symbol})", applicability = "machine-applicable")]
     Symbol {
         #[primary_span]
         span: Span,
@@ -317,28 +313,28 @@ impl<'a> IncorrectReprFormatGenericCause<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::rustc_promotable_pairing, code = "E0717")]
+#[diag(attr_rustc_promotable_pairing, code = "E0717")]
 pub(crate) struct RustcPromotablePairing {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")]
+#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")]
 pub(crate) struct RustcAllowedUnstablePairing {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::cfg_predicate_identifier)]
+#[diag(attr_cfg_predicate_identifier)]
 pub(crate) struct CfgPredicateIdentifier {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::deprecated_item_suggestion)]
+#[diag(attr_deprecated_item_suggestion)]
 pub(crate) struct DeprecatedItemSuggestion {
     #[primary_span]
     pub span: Span,
@@ -351,21 +347,21 @@ pub(crate) struct DeprecatedItemSuggestion {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expected_single_version_literal)]
+#[diag(attr_expected_single_version_literal)]
 pub(crate) struct ExpectedSingleVersionLiteral {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expected_version_literal)]
+#[diag(attr_expected_version_literal)]
 pub(crate) struct ExpectedVersionLiteral {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expects_feature_list)]
+#[diag(attr_expects_feature_list)]
 pub(crate) struct ExpectsFeatureList {
     #[primary_span]
     pub span: Span,
@@ -374,7 +370,7 @@ pub(crate) struct ExpectsFeatureList {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::expects_features)]
+#[diag(attr_expects_features)]
 pub(crate) struct ExpectsFeatures {
     #[primary_span]
     pub span: Span,
@@ -383,14 +379,14 @@ pub(crate) struct ExpectsFeatures {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::soft_no_args)]
+#[diag(attr_soft_no_args)]
 pub(crate) struct SoftNoArgs {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(attr::unknown_version_literal)]
+#[diag(attr_unknown_version_literal)]
 pub(crate) struct UnknownVersionLiteral {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index df04128135b..58aeb43ef97 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -92,7 +92,7 @@ pub struct OutlivesConstraint<'tcx> {
     pub span: Span,
 
     /// What caused this constraint?
-    pub category: ConstraintCategory<'tcx>,
+    pub category: ConstraintCategory,
 
     /// Variance diagnostic information
     pub variance_info: VarianceDiagInfo<'tcx>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 2a8bd4d30ab..3f5d9fb6206 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -492,10 +492,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
                 return false;
             };
+            // Regions are already solved, so we must use a fresh InferCtxt,
+            // but the type has region variables, so erase those.
             tcx.infer_ctxt()
                 .build()
-                .type_implements_trait(default_trait, ty, ty::List::empty(), param_env)
-                .may_apply()
+                .type_implements_trait(
+                    default_trait,
+                    tcx.erase_regions(ty),
+                    ty::List::empty(),
+                    param_env,
+                )
+                .must_apply_modulo_regions()
         };
 
         let assign_value = match ty.kind() {
@@ -976,7 +983,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err: &mut Diagnostic,
         location: Location,
         issued_borrow: &BorrowData<'tcx>,
-        explanation: BorrowExplanation<'tcx>,
+        explanation: BorrowExplanation,
     ) {
         let used_in_call = matches!(
             explanation,
@@ -1326,7 +1333,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
-        explanation: BorrowExplanation<'tcx>,
+        explanation: BorrowExplanation,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_local_value_does_not_live_long_enough(\
@@ -1532,7 +1539,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
         proper_span: Span,
-        explanation: BorrowExplanation<'tcx>,
+        explanation: BorrowExplanation,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
             explanation
@@ -1646,7 +1653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         borrow: &BorrowData<'tcx>,
         borrow_span: Span,
         return_span: Span,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         opt_place_desc: Option<&String>,
     ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
         let return_kind = match category {
@@ -1741,7 +1748,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         use_span: UseSpans<'tcx>,
         var_span: Span,
         fr_name: &RegionName,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         constraint_span: Span,
         captured_var: &str,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 1c01e78abd4..545237bb392 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -1,8 +1,5 @@
 //! Print diagnostics to explain why values are borrowed.
 
-use std::collections::VecDeque;
-
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
@@ -24,7 +21,7 @@ use crate::{
 use super::{find_use, RegionName, UseSpans};
 
 #[derive(Debug)]
-pub(crate) enum BorrowExplanation<'tcx> {
+pub(crate) enum BorrowExplanation {
     UsedLater(LaterUseKind, Span, Option<Span>),
     UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
     UsedLaterWhenDropped {
@@ -33,7 +30,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
         should_note_order: bool,
     },
     MustBeValidFor {
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         from_closure: bool,
         span: Span,
         region_name: RegionName,
@@ -52,7 +49,7 @@ pub(crate) enum LaterUseKind {
     Other,
 }
 
-impl<'tcx> BorrowExplanation<'tcx> {
+impl<'tcx> BorrowExplanation {
     pub(crate) fn is_explained(&self) -> bool {
         !matches!(self, BorrowExplanation::Unexplained)
     }
@@ -287,7 +284,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
     fn add_lifetime_bound_suggestion_to_diagnostic(
         &self,
         err: &mut Diagnostic,
-        category: &ConstraintCategory<'tcx>,
+        category: &ConstraintCategory,
         span: Span,
         region_name: &RegionName,
     ) {
@@ -319,7 +316,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &self,
         borrow_region: RegionVid,
         outlived_region: RegionVid,
-    ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
+    ) -> (ConstraintCategory, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
         let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
             borrow_region,
             NllRegionVariableOrigin::FreeRegion,
@@ -351,7 +348,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         location: Location,
         borrow: &BorrowData<'tcx>,
         kind_place: Option<(WriteKind, Place<'tcx>)>,
-    ) -> BorrowExplanation<'tcx> {
+    ) -> BorrowExplanation {
         let regioncx = &self.regioncx;
         let body: &Body<'_> = &self.body;
         let tcx = self.infcx.tcx;
@@ -359,19 +356,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let borrow_region_vid = borrow.region;
         debug!(?borrow_region_vid);
 
-        let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
+        let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
         debug!(?region_sub);
 
-        match find_use::find(body, regioncx, tcx, region_sub, location) {
+        let mut use_location = location;
+        let mut use_in_later_iteration_of_loop = false;
+
+        if region_sub == borrow_region_vid {
+            // When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is
+            // issued is the same location that invalidates the reference), this is likely a loop iteration
+            // - in this case, try using the loop terminator location in `find_sub_region_live_at`.
+            if let Some(loop_terminator_location) =
+                regioncx.find_loop_terminator_location(borrow.region, body)
+            {
+                region_sub = self
+                    .regioncx
+                    .find_sub_region_live_at(borrow_region_vid, loop_terminator_location);
+                debug!("explain_why_borrow_contains_point: region_sub in loop={:?}", region_sub);
+                use_location = loop_terminator_location;
+                use_in_later_iteration_of_loop = true;
+            }
+        }
+
+        match find_use::find(body, regioncx, tcx, region_sub, use_location) {
             Some(Cause::LiveVar(local, location)) => {
                 let span = body.source_info(location).span;
                 let spans = self
                     .move_spans(Place::from(local).as_ref(), location)
                     .or_else(|| self.borrow_spans(span, location));
 
-                let borrow_location = location;
-                if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
-                    let later_use = self.later_use_kind(borrow, spans, location);
+                if use_in_later_iteration_of_loop {
+                    let later_use = self.later_use_kind(borrow, spans, use_location);
                     BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
                 } else {
                     // Check if the location represents a `FakeRead`, and adapt the error
@@ -425,131 +440,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    /// true if `borrow_location` can reach `use_location` by going through a loop and
-    /// `use_location` is also inside of that loop
-    fn is_use_in_later_iteration_of_loop(
-        &self,
-        borrow_location: Location,
-        use_location: Location,
-    ) -> bool {
-        let back_edge = self.reach_through_backedge(borrow_location, use_location);
-        back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge))
-    }
-
-    /// Returns the outmost back edge if `from` location can reach `to` location passing through
-    /// that back edge
-    fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
-        let mut visited_locations = FxHashSet::default();
-        let mut pending_locations = VecDeque::new();
-        visited_locations.insert(from);
-        pending_locations.push_back(from);
-        debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
-
-        let mut outmost_back_edge = None;
-        while let Some(location) = pending_locations.pop_front() {
-            debug!(
-                "reach_through_backedge: location={:?} outmost_back_edge={:?}
-                   pending_locations={:?} visited_locations={:?}",
-                location, outmost_back_edge, pending_locations, visited_locations
-            );
-
-            if location == to && outmost_back_edge.is_some() {
-                // We've managed to reach the use location
-                debug!("reach_through_backedge: found!");
-                return outmost_back_edge;
-            }
-
-            let block = &self.body.basic_blocks[location.block];
-
-            if location.statement_index < block.statements.len() {
-                let successor = location.successor_within_block();
-                if visited_locations.insert(successor) {
-                    pending_locations.push_back(successor);
-                }
-            } else {
-                pending_locations.extend(
-                    block
-                        .terminator()
-                        .successors()
-                        .map(|bb| Location { statement_index: 0, block: bb })
-                        .filter(|s| visited_locations.insert(*s))
-                        .map(|s| {
-                            if self.is_back_edge(location, s) {
-                                match outmost_back_edge {
-                                    None => {
-                                        outmost_back_edge = Some(location);
-                                    }
-
-                                    Some(back_edge)
-                                        if location.dominates(back_edge, &self.dominators) =>
-                                    {
-                                        outmost_back_edge = Some(location);
-                                    }
-
-                                    Some(_) => {}
-                                }
-                            }
-
-                            s
-                        }),
-                );
-            }
-        }
-
-        None
-    }
-
-    /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
-    /// intermediate nodes
-    fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
-        self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
-    }
-
-    fn find_loop_head_dfs(
-        &self,
-        from: Location,
-        loop_head: Location,
-        visited_locations: &mut FxHashSet<Location>,
-    ) -> bool {
-        visited_locations.insert(from);
-
-        if from == loop_head {
-            return true;
-        }
-
-        if loop_head.dominates(from, &self.dominators) {
-            let block = &self.body.basic_blocks[from.block];
-
-            if from.statement_index < block.statements.len() {
-                let successor = from.successor_within_block();
-
-                if !visited_locations.contains(&successor)
-                    && self.find_loop_head_dfs(successor, loop_head, visited_locations)
-                {
-                    return true;
-                }
-            } else {
-                for bb in block.terminator().successors() {
-                    let successor = Location { statement_index: 0, block: bb };
-
-                    if !visited_locations.contains(&successor)
-                        && self.find_loop_head_dfs(successor, loop_head, visited_locations)
-                    {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        false
-    }
-
-    /// True if an edge `source -> target` is a backedge -- in other words, if the target
-    /// dominates the source.
-    fn is_back_edge(&self, source: Location, target: Location) -> bool {
-        target.dominates(source, &self.dominators)
-    }
-
     /// Determine how the borrow was later used.
     /// First span returned points to the location of the conflicting use
     /// Second span if `Some` is returned in the case of closures and points
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 35c3df76899..245ea07d120 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -161,7 +161,7 @@ impl OutlivesSuggestionBuilder {
     pub(crate) fn intermediate_suggestion(
         &mut self,
         mbcx: &MirBorrowckCtxt<'_, '_>,
-        errci: &ErrorConstraintInfo<'_>,
+        errci: &ErrorConstraintInfo,
         diag: &mut Diagnostic,
     ) {
         // Emit an intermediate note.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 15230718dc0..b619537f317 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -2,6 +2,7 @@
 #![deny(rustc::diagnostic_outside_of_impl)]
 //! Error reporting machinery for lifetime errors.
 
+use either::Either;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
@@ -16,7 +17,7 @@ use rustc_infer::infer::{
     NllRegionVariableOrigin, RelateParamBound,
 };
 use rustc_middle::hir::place::PlaceBase;
-use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
+use rustc_middle::mir::{ConstraintCategory, ReturnConstraint, TerminatorKind};
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::Region;
 use rustc_middle::ty::TypeVisitor;
@@ -39,7 +40,7 @@ use crate::{
     MirBorrowckCtxt,
 };
 
-impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
+impl ConstraintDescription for ConstraintCategory {
     fn description(&self) -> &'static str {
         // Must end with a space. Allows for empty names to be provided.
         match self {
@@ -115,7 +116,7 @@ pub(crate) enum RegionErrorKind<'tcx> {
 
 /// Information about the various region constraints involved in a borrow checker error.
 #[derive(Clone, Debug)]
-pub struct ErrorConstraintInfo<'tcx> {
+pub struct ErrorConstraintInfo {
     // fr: outlived_fr
     pub(super) fr: RegionVid,
     pub(super) fr_is_local: bool,
@@ -123,7 +124,7 @@ pub struct ErrorConstraintInfo<'tcx> {
     pub(super) outlived_fr_is_local: bool,
 
     // Category and span for best blame constraint
-    pub(super) category: ConstraintCategory<'tcx>,
+    pub(super) category: ConstraintCategory,
     pub(super) span: Span,
 }
 
@@ -498,7 +499,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     fn report_fnmut_error(
         &self,
-        errci: &ErrorConstraintInfo<'tcx>,
+        errci: &ErrorConstraintInfo,
         kind: ReturnConstraint,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
@@ -571,7 +572,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn report_escaping_data_error(
         &self,
-        errci: &ErrorConstraintInfo<'tcx>,
+        errci: &ErrorConstraintInfo,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo { span, category, .. } = errci;
 
@@ -675,7 +676,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     /// ```
     fn report_general_error(
         &self,
-        errci: &ErrorConstraintInfo<'tcx>,
+        errci: &ErrorConstraintInfo,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo {
             fr,
@@ -788,7 +789,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         diag: &mut Diagnostic,
         f: Region<'tcx>,
         o: Region<'tcx>,
-        category: &ConstraintCategory<'tcx>,
+        category: &ConstraintCategory,
     ) {
         if !o.is_static() {
             return;
@@ -796,7 +797,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         let tcx = self.infcx.tcx;
 
-        let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
+        let instance =
+            if let ConstraintCategory::CallArgument(location) = category
+                && let Either::Right(term) = self.body.stmt_at(*location)
+                && let TerminatorKind::Call { func, .. } = &term.kind
+        {
+            let func_ty = func.ty(self.body, tcx);
             let (fn_did, substs) = match func_ty.kind() {
                 ty::FnDef(fn_did, substs) => (fn_did, substs),
                 _ => return,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 4cefd1ec387..85b9bde2c81 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
 use rustc_middle::mir::{
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-    ConstraintCategory, Local, Location, ReturnConstraint,
+    ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
 };
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
@@ -91,7 +91,7 @@ pub struct RegionInferenceContext<'tcx> {
 
     /// Map closure bounds to a `Span` that should be used for error reporting.
     closure_bounds_mapping:
-        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     /// Map universe indexes to information on why we created it.
     universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
@@ -267,7 +267,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
-            FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>,
+            FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
         >,
         universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
@@ -1807,7 +1807,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn retrieve_closure_constraint_info(
         &self,
         constraint: OutlivesConstraint<'tcx>,
-    ) -> Option<(ConstraintCategory<'tcx>, Span)> {
+    ) -> Option<(ConstraintCategory, Span)> {
         match constraint.locations {
             Locations::All(_) => None,
             Locations::Single(loc) => {
@@ -1822,7 +1822,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         fr1: RegionVid,
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
-    ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
+    ) -> (ConstraintCategory, ObligationCause<'tcx>) {
         let BlameConstraint { category, cause, .. } = self
             .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2))
             .0;
@@ -2236,6 +2236,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
         self.universe_causes[&universe].clone()
     }
+
+    /// Tries to find the terminator of the loop in which the region 'r' resides.
+    /// Returns the location of the terminator if found.
+    pub(crate) fn find_loop_terminator_location(
+        &self,
+        r: RegionVid,
+        body: &Body<'_>,
+    ) -> Option<Location> {
+        let scc = self.constraint_sccs.scc(r.to_region_vid());
+        let locations = self.scc_values.locations_outlived_by(scc);
+        for location in locations {
+            let bb = &body[location.block];
+            if let Some(terminator) = &bb.terminator {
+                // terminator of a loop should be TerminatorKind::FalseUnwind
+                if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
+                    return Some(location);
+                }
+            }
+        }
+        None
+    }
 }
 
 impl<'tcx> RegionDefinition<'tcx> {
@@ -2341,7 +2362,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
 
 #[derive(Clone, Debug)]
 pub struct BlameConstraint<'tcx> {
-    pub category: ConstraintCategory<'tcx>,
+    pub category: ConstraintCategory,
     pub from_closure: bool,
     pub cause: ObligationCause<'tcx>,
     pub variance_info: ty::VarianceDiagInfo<'tcx>,
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 56987edd1b6..11a57ef2621 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -226,7 +226,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         }
 
         let definition_ty = instantiated_ty
-            .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
+            .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
             .ty;
 
         if !check_opaque_type_parameter_valid(
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index d737432f0ef..f3023769081 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,8 +1,8 @@
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::mir::visit::{MutVisitor, TyContext};
+use rustc_middle::mir::Constant;
 use rustc_middle::mir::{Body, Location, Promoted};
-use rustc_middle::mir::{Constant, ConstantKind};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 
@@ -38,21 +38,6 @@ where
     })
 }
 
-// FIXME(valtrees): This function is necessary because `fold_regions`
-// panics for mir constants in the visitor.
-//
-// Once `visit_mir_constant` is removed we can also remove this function
-// and just use `renumber_regions`.
-fn renumber_regions_in_mir_constant<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    value: ConstantKind<'tcx>,
-) -> ConstantKind<'tcx> {
-    infcx.tcx.super_fold_regions(value, |_region, _depth| {
-        let origin = NllRegionVariableOrigin::Existential { from_forall: false };
-        infcx.next_nll_region_var(origin)
-    })
-}
-
 struct NllVisitor<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
 }
@@ -64,13 +49,6 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
     {
         renumber_regions(self.infcx, value)
     }
-
-    fn renumber_regions_in_mir_constant(
-        &mut self,
-        value: ConstantKind<'tcx>,
-    ) -> ConstantKind<'tcx> {
-        renumber_regions_in_mir_constant(self.infcx, value)
-    }
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
@@ -103,7 +81,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) {
         let literal = constant.literal;
-        constant.literal = self.renumber_regions_in_mir_constant(literal);
+        constant.literal = self.renumber_regions(literal);
         debug!("constant: {:#?}", constant);
     }
 }
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index ff667896eb1..cff3089c397 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -6,7 +6,7 @@ use rustc_span::Span;
 use crate::diagnostics::RegionName;
 
 #[derive(Diagnostic)]
-#[diag(borrowck::move_unsized, code = "E0161")]
+#[diag(borrowck_move_unsized, code = "E0161")]
 pub(crate) struct MoveUnsized<'tcx> {
     pub ty: Ty<'tcx>,
     #[primary_span]
@@ -15,7 +15,7 @@ pub(crate) struct MoveUnsized<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::higher_ranked_lifetime_error)]
+#[diag(borrowck_higher_ranked_lifetime_error)]
 pub(crate) struct HigherRankedLifetimeError {
     #[subdiagnostic]
     pub cause: Option<HigherRankedErrorCause>,
@@ -25,21 +25,21 @@ pub(crate) struct HigherRankedLifetimeError {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum HigherRankedErrorCause {
-    #[note(borrowck::could_not_prove)]
+    #[note(borrowck_could_not_prove)]
     CouldNotProve { predicate: String },
-    #[note(borrowck::could_not_normalize)]
+    #[note(borrowck_could_not_normalize)]
     CouldNotNormalize { value: String },
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::higher_ranked_subtype_error)]
+#[diag(borrowck_higher_ranked_subtype_error)]
 pub(crate) struct HigherRankedSubtypeError {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::generic_does_not_live_long_enough)]
+#[diag(borrowck_generic_does_not_live_long_enough)]
 pub(crate) struct GenericDoesNotLiveLongEnough {
     pub kind: String,
     #[primary_span]
@@ -47,15 +47,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(borrowck::var_does_not_need_mut)]
+#[diag(borrowck_var_does_not_need_mut)]
 pub(crate) struct VarNeedNotMut {
     #[suggestion_short(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
 #[derive(Diagnostic)]
-#[diag(borrowck::var_cannot_escape_closure)]
+#[diag(borrowck_var_cannot_escape_closure)]
 #[note]
-#[note(borrowck::cannot_escape)]
+#[note(cannot_escape)]
 pub(crate) struct FnMutError {
     #[primary_span]
     pub span: Span,
@@ -65,17 +65,17 @@ pub(crate) struct FnMutError {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum VarHereDenote {
-    #[label(borrowck::var_here_captured)]
+    #[label(borrowck_var_here_captured)]
     Captured {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::var_here_defined)]
+    #[label(borrowck_var_here_defined)]
     Defined {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::closure_inferred_mut)]
+    #[label(borrowck_closure_inferred_mut)]
     FnMutInferred {
         #[primary_span]
         span: Span,
@@ -84,17 +84,17 @@ pub(crate) enum VarHereDenote {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum FnMutReturnTypeErr {
-    #[label(borrowck::returned_closure_escaped)]
+    #[label(borrowck_returned_closure_escaped)]
     ReturnClosure {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::returned_async_block_escaped)]
+    #[label(borrowck_returned_async_block_escaped)]
     ReturnAsyncBlock {
         #[primary_span]
         span: Span,
     },
-    #[label(borrowck::returned_ref_escaped)]
+    #[label(borrowck_returned_ref_escaped)]
     ReturnRef {
         #[primary_span]
         span: Span,
@@ -102,7 +102,7 @@ pub(crate) enum FnMutReturnTypeErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::lifetime_constraints_error)]
+#[diag(borrowck_lifetime_constraints_error)]
 pub(crate) struct LifetimeOutliveErr {
     #[primary_span]
     pub span: Span,
@@ -110,7 +110,7 @@ pub(crate) struct LifetimeOutliveErr {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum LifetimeReturnCategoryErr<'a> {
-    #[label(borrowck::returned_lifetime_wrong)]
+    #[label(borrowck_returned_lifetime_wrong)]
     WrongReturn {
         #[primary_span]
         span: Span,
@@ -118,7 +118,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
         outlived_fr_name: RegionName,
         fr_name: &'a RegionName,
     },
-    #[label(borrowck::returned_lifetime_short)]
+    #[label(borrowck_returned_lifetime_short)]
     ShortReturn {
         #[primary_span]
         span: Span,
@@ -142,7 +142,7 @@ impl IntoDiagnosticArg for RegionName {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum RequireStaticErr {
-    #[note(borrowck::used_impl_require_static)]
+    #[note(borrowck_used_impl_require_static)]
     UsedImpl {
         #[primary_span]
         multi_span: MultiSpan,
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index a581726a15c..459ecfe17e3 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
         &mut self,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         op: Op,
     ) -> Fallible<R>
     where
@@ -85,7 +85,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         &mut self,
         trait_ref: ty::TraitRef<'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) {
         self.prove_predicate(
             ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
@@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         &mut self,
         predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) {
         for predicate in predicates {
             let predicate = predicate.to_predicate(self.tcx());
@@ -139,7 +139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         &mut self,
         predicate: ty::Predicate<'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) {
         let param_env = self.param_env;
         self.fully_perform_op(
@@ -164,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         &mut self,
         value: T,
         location: impl NormalizeLocation,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) -> T
     where
         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index d5bfc2f5208..d7e5a118a2e 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> {
     param_env: ty::ParamEnv<'tcx>,
     locations: Locations,
     span: Span,
-    category: ConstraintCategory<'tcx>,
+    category: ConstraintCategory,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
 
@@ -50,7 +50,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
         span: Span,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     ) -> Self {
         Self {
@@ -175,7 +175,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         &mut self,
         sup: ty::RegionVid,
         sub: ty::RegionVid,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) {
         let category = match self.category {
             ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
@@ -203,7 +203,7 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
         _origin: SubregionOrigin<'tcx>,
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
-        constraint_category: ConstraintCategory<'tcx>,
+        constraint_category: ConstraintCategory,
     ) {
         let b = self.to_region_vid(b);
         let a = self.to_region_vid(a);
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index dc0f0e7cd3c..00cacd515a1 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -942,7 +942,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
     pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
 
     pub(crate) closure_bounds_mapping:
-        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     pub(crate) universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
@@ -1133,7 +1133,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     fn push_region_constraints(
         &mut self,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         data: &QueryRegionConstraints<'tcx>,
     ) {
         debug!("constraints generated: {:#?}", data);
@@ -1158,7 +1158,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         sub: Ty<'tcx>,
         sup: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) -> Fallible<()> {
         // Use this order of parameters because the sup type is usually the
         // "expected" type in diagnostics.
@@ -1171,7 +1171,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) -> Fallible<()> {
         self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
     }
@@ -1183,7 +1183,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         v: ty::Variance,
         user_ty: &UserTypeProjection,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) -> Fallible<()> {
         let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
         let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
@@ -1618,19 +1618,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
 
-        let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind {
-            Some(func.ty(body, self.infcx.tcx))
-        } else {
-            None
-        };
-        debug!(?func_ty);
-
         for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
             let op_arg_ty = op_arg.ty(body, self.tcx());
 
             let op_arg_ty = self.normalize(op_arg_ty, term_location);
             let category = if from_hir_call {
-                ConstraintCategory::CallArgument(func_ty)
+                ConstraintCategory::CallArgument(term_location)
             } else {
                 ConstraintCategory::Boring
             };
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index c97a6a1a658..b53360ea61b 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         v: ty::Variance,
         b: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) -> Fallible<()> {
         TypeRelating::new(
             self.infcx,
@@ -45,7 +45,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         a: ty::SubstsRef<'tcx>,
         b: ty::SubstsRef<'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) -> Fallible<()> {
         TypeRelating::new(
             self.infcx,
@@ -64,7 +64,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     locations: Locations,
 
     /// What category do we assign the resulting `'a: 'b` relationships?
-    category: ConstraintCategory<'tcx>,
+    category: ConstraintCategory,
 
     /// Information so that error reporting knows what types we are relating
     /// when reporting a bound region error.
@@ -75,7 +75,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     fn new(
         type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
         locations: Locations,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
         universe_info: UniverseInfo<'tcx>,
     ) -> Self {
         Self { type_checker, locations, category, universe_info }
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 46b54eae384..5638c2f6180 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -36,7 +36,7 @@ pub fn expand_cfg(
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros::requires_cfg_pattern)]
+#[diag(builtin_macros_requires_cfg_pattern)]
 struct RequiresCfgPattern {
     #[primary_span]
     #[label]
@@ -44,7 +44,7 @@ struct RequiresCfgPattern {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros::expected_one_cfg_pattern)]
+#[diag(builtin_macros_expected_one_cfg_pattern)]
 struct OneCfgPattern {
     #[primary_span]
     span: Span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a65d0bad6de..ee346047a0b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -131,6 +131,8 @@ fn inject_impl_of_structural_trait(
     // Create generics param list for where clauses and impl headers
     let mut generics = generics.clone();
 
+    let ctxt = span.ctxt();
+
     // Create the type of `self`.
     //
     // in addition, remove defaults from generic params (impls cannot have them).
@@ -138,16 +140,18 @@ fn inject_impl_of_structural_trait(
         .params
         .iter_mut()
         .map(|param| match &mut param.kind {
-            ast::GenericParamKind::Lifetime => {
-                ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
-            }
+            ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
+                cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
+            ),
             ast::GenericParamKind::Type { default } => {
                 *default = None;
-                ast::GenericArg::Type(cx.ty_ident(span, param.ident))
+                ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
             }
             ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
                 *default = None;
-                ast::GenericArg::Const(cx.const_ident(span, param.ident))
+                ast::GenericArg::Const(
+                    cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
+                )
             }
         })
         .collect();
@@ -174,6 +178,8 @@ fn inject_impl_of_structural_trait(
             })
             .cloned(),
     );
+    // Mark as `automatically_derived` to avoid some silly lints.
+    attrs.push(cx.attribute(cx.meta_word(span, sym::automatically_derived)));
 
     let newitem = cx.item(
         span,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 705141614e2..fee5d04cdae 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -36,13 +36,22 @@ pub fn expand_test_case(
     let sp = ecx.with_def_site_ctxt(attr_sp);
     let mut item = anno_item.expect_item();
     item = item.map(|mut item| {
+        let test_path_symbol = Symbol::intern(&item_path(
+            // skip the name of the root module
+            &ecx.current_expansion.module.mod_path[1..],
+            &item.ident,
+        ));
         item.vis = ast::Visibility {
             span: item.vis.span,
             kind: ast::VisibilityKind::Public,
             tokens: None,
         };
         item.ident.span = item.ident.span.with_ctxt(sp.ctxt());
-        item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker)));
+        item.attrs.push(ecx.attribute(attr::mk_name_value_item_str(
+            Ident::new(sym::rustc_test_marker, sp),
+            test_path_symbol,
+            sp,
+        )));
         item
     });
 
@@ -215,6 +224,12 @@ pub fn expand_test_or_bench(
         )
     };
 
+    let test_path_symbol = Symbol::intern(&item_path(
+        // skip the name of the root module
+        &cx.current_expansion.module.mod_path[1..],
+        &item.ident,
+    ));
+
     let mut test_const = cx.item(
         sp,
         Ident::new(item.ident.name, sp),
@@ -224,9 +239,14 @@ pub fn expand_test_or_bench(
                 Ident::new(sym::cfg, attr_sp),
                 vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))],
             )),
-            // #[rustc_test_marker]
-            cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)),
-        ],
+            // #[rustc_test_marker = "test_case_sort_key"]
+            cx.attribute(attr::mk_name_value_item_str(
+                Ident::new(sym::rustc_test_marker, attr_sp),
+                test_path_symbol,
+                attr_sp,
+            )),
+        ]
+        .into(),
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
@@ -250,14 +270,7 @@ pub fn expand_test_or_bench(
                                         cx.expr_call(
                                             sp,
                                             cx.expr_path(test_path("StaticTestName")),
-                                            vec![cx.expr_str(
-                                                sp,
-                                                Symbol::intern(&item_path(
-                                                    // skip the name of the root module
-                                                    &cx.current_expansion.module.mod_path[1..],
-                                                    &item.ident,
-                                                )),
-                                            )],
+                                            vec![cx.expr_str(sp, test_path_symbol)],
                                         ),
                                     ),
                                     // ignore: true | false
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 561ca00c719..b8b8351a36f 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -18,9 +18,11 @@ use thin_vec::thin_vec;
 
 use std::{iter, mem};
 
+#[derive(Clone)]
 struct Test {
     span: Span,
     ident: Ident,
+    name: Symbol,
 }
 
 struct TestCtxt<'a> {
@@ -120,10 +122,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = i.into_inner();
-        if is_test_case(&self.cx.ext_cx.sess, &item) {
+        if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
             debug!("this is a test item");
 
-            let test = Test { span: item.span, ident: item.ident };
+            let test = Test { span: item.span, ident: item.ident, name };
             self.tests.push(test);
         }
 
@@ -357,9 +359,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     debug!("building test vector from {} tests", cx.test_cases.len());
     let ecx = &cx.ext_cx;
 
+    let mut tests = cx.test_cases.clone();
+    tests.sort_by(|a, b| a.name.as_str().cmp(&b.name.as_str()));
+
     ecx.expr_array_ref(
         sp,
-        cx.test_cases
+        tests
             .iter()
             .map(|test| {
                 ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident])))
@@ -368,8 +373,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     )
 }
 
-fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
-    sess.contains_name(&i.attrs, sym::rustc_test_marker)
+fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
+    sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
 }
 
 fn get_test_runner(
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index d7816e395c8..15ad90f9043 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -17,7 +17,7 @@ impl IntoDiagnosticArg for ExitCode {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::ranlib_failure)]
+#[diag(codegen_gcc_ranlib_failure)]
 pub(crate) struct RanlibFailure {
     exit_code: ExitCode,
 }
@@ -29,7 +29,7 @@ impl RanlibFailure {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_basic_integer, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
     #[primary_span]
     pub span: Span,
@@ -38,7 +38,7 @@ pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_invalid_float_vector, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_float_vector, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> {
     #[primary_span]
     pub span: Span,
@@ -48,7 +48,7 @@ pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_not_float, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_not_float, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationNotFloat<'a> {
     #[primary_span]
     pub span: Span,
@@ -57,7 +57,7 @@ pub(crate) struct InvalidMonomorphizationNotFloat<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unrecognized, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unrecognized, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnrecognized {
     #[primary_span]
     pub span: Span,
@@ -65,7 +65,7 @@ pub(crate) struct InvalidMonomorphizationUnrecognized {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_expected_signed_unsigned, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_expected_signed_unsigned, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> {
     #[primary_span]
     pub span: Span,
@@ -75,7 +75,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unsupported_element, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_element, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> {
     #[primary_span]
     pub span: Span,
@@ -86,7 +86,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_invalid_bitmask, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_bitmask, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> {
     #[primary_span]
     pub span: Span,
@@ -97,7 +97,7 @@ pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_simd_shuffle, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_simd_shuffle, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> {
     #[primary_span]
     pub span: Span,
@@ -106,7 +106,7 @@ pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_expected_simd, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_expected_simd, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> {
     #[primary_span]
     pub span: Span,
@@ -116,7 +116,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_mask_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_mask_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationMaskType<'a> {
     #[primary_span]
     pub span: Span,
@@ -125,7 +125,7 @@ pub(crate) struct InvalidMonomorphizationMaskType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_length, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_length, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnLength<'a> {
     #[primary_span]
     pub span: Span,
@@ -136,7 +136,7 @@ pub(crate) struct InvalidMonomorphizationReturnLength<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_length_input_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_length_input_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> {
     #[primary_span]
     pub span: Span,
@@ -148,7 +148,7 @@ pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_element, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_element, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnElement<'a> {
     #[primary_span]
     pub span: Span,
@@ -160,7 +160,7 @@ pub(crate) struct InvalidMonomorphizationReturnElement<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnType<'a> {
     #[primary_span]
     pub span: Span,
@@ -171,7 +171,7 @@ pub(crate) struct InvalidMonomorphizationReturnType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_inserted_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_inserted_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationInsertedType<'a> {
     #[primary_span]
     pub span: Span,
@@ -182,7 +182,7 @@ pub(crate) struct InvalidMonomorphizationInsertedType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_return_integer_type, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_return_integer_type, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> {
     #[primary_span]
     pub span: Span,
@@ -192,7 +192,7 @@ pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_mismatched_lengths, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_mismatched_lengths, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationMismatchedLengths {
     #[primary_span]
     pub span: Span,
@@ -202,7 +202,7 @@ pub(crate) struct InvalidMonomorphizationMismatchedLengths {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unsupported_cast, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_cast, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> {
     #[primary_span]
     pub span: Span,
@@ -214,7 +214,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::invalid_monomorphization_unsupported_operation, code = "E0511")]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_operation, code = "E0511")]
 pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
     #[primary_span]
     pub span: Span,
@@ -224,18 +224,18 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::linkage_const_or_mut_type)]
+#[diag(codegen_gcc_linkage_const_or_mut_type)]
 pub(crate) struct LinkageConstOrMutType {
     #[primary_span]
     pub span: Span
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::lto_not_supported)]
+#[diag(codegen_gcc_lto_not_supported)]
 pub(crate) struct LTONotSupported;
 
 #[derive(Diagnostic)]
-#[diag(codegen_gcc::unwinding_inline_asm)]
+#[diag(codegen_gcc_unwinding_inline_asm)]
 pub(crate) struct UnwindingInlineAsm {
     #[primary_span]
     pub span: Span
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 46abbb553bf..38c1eac7adf 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -3,11 +3,12 @@
 // Run-time:
 //   status: 0
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::{asm, global_asm};
 
-global_asm!("
+global_asm!(
+    "
     .global add_asm
 add_asm:
      mov rax, rdi
@@ -132,7 +133,9 @@ fn main() {
     assert_eq!(x, 43);
 
     // check sym fn
-    extern "C" fn foo() -> u64 { 42 }
+    extern "C" fn foo() -> u64 {
+        42
+    }
     let x: u64;
     unsafe {
         asm!("call {}", sym foo, lateout("rax") x);
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index cef7bf1e803..a49cc7f8d66 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -32,8 +32,8 @@ pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
 
 pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
     match crate_type {
-        CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => true,
-        CrateType::Dylib | CrateType::Rlib | CrateType::ProcMacro => false,
+        CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
+        CrateType::Rlib | CrateType::ProcMacro => false,
     }
 }
 
@@ -73,17 +73,6 @@ fn prepare_lto(
     // with either fat or thin LTO
     let mut upstream_modules = Vec::new();
     if cgcx.lto != Lto::ThinLocal {
-        if cgcx.opts.cg.prefer_dynamic {
-            diag_handler
-                .struct_err("cannot prefer dynamic linking when performing LTO")
-                .note(
-                    "only 'staticlib', 'bin', and 'cdylib' outputs are \
-                               supported with LTO",
-                )
-                .emit();
-            return Err(FatalError);
-        }
-
         // Make sure we actually can run LTO
         for crate_type in cgcx.crate_types.iter() {
             if !crate_type_allows_lto(*crate_type) {
@@ -92,9 +81,25 @@ fn prepare_lto(
                                             static library outputs",
                 );
                 return Err(e);
+            } else if *crate_type == CrateType::Dylib {
+                if !cgcx.opts.unstable_opts.dylib_lto {
+                    return Err(diag_handler
+                        .fatal("lto cannot be used for `dylib` crate type without `-Zdylib-lto`"));
+                }
             }
         }
 
+        if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
+            diag_handler
+                .struct_err("cannot prefer dynamic linking when performing LTO")
+                .note(
+                    "only 'staticlib', 'bin', and 'cdylib' outputs are \
+                               supported with LTO",
+                )
+                .emit();
+            return Err(FatalError);
+        }
+
         for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
             let exported_symbols =
                 cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index b83c1e8f08f..6f0d1b7ce84 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -179,7 +179,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
             // MinGW: For backward compatibility we rely on the linker to decide whether it
             // should use dllimport for functions.
             if cx.use_dll_storage_attrs
-                && tcx.is_dllimport_foreign_item(instance_def_id)
+                && let Some(library) = tcx.native_library(instance_def_id)
+                && library.kind.is_dllimport()
                 && !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
             {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index ee2fc65e37b..dd3c43ba5ca 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -332,7 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> {
             }
         }
 
-        if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) {
+        if self.use_dll_storage_attrs
+            && let Some(library) = self.tcx.native_library(def_id)
+            && library.kind.is_dllimport()
+        {
             // For foreign (native) libs we know the exact storage type to use.
             unsafe {
                 llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 95e72184ff0..a0b5e3b6daf 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
 use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -39,6 +39,7 @@ use cc::windows_registry;
 use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
+use itertools::Itertools;
 use std::borrow::Borrow;
 use std::cell::OnceCell;
 use std::collections::BTreeSet;
@@ -208,11 +209,29 @@ pub fn link_binary<'a>(
 }
 
 pub fn each_linked_rlib(
+    sess: &Session,
     info: &CrateInfo,
     f: &mut dyn FnMut(CrateNum, &Path),
 ) -> Result<(), errors::LinkRlibError> {
     let crates = info.used_crates.iter();
     let mut fmts = None;
+
+    let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
+    if lto_active {
+        for combination in info.dependency_formats.iter().combinations(2) {
+            let (ty1, list1) = &combination[0];
+            let (ty2, list2) = &combination[1];
+            if list1 != list2 {
+                return Err(errors::LinkRlibError::IncompatibleDependencyFormats {
+                    ty1: format!("{ty1:?}"),
+                    ty2: format!("{ty2:?}"),
+                    list1: format!("{list1:?}"),
+                    list2: format!("{list2:?}"),
+                });
+            }
+        }
+    }
+
     for (ty, list) in info.dependency_formats.iter() {
         match ty {
             CrateType::Executable
@@ -222,6 +241,10 @@ pub fn each_linked_rlib(
                 fmts = Some(list);
                 break;
             }
+            CrateType::Dylib if lto_active => {
+                fmts = Some(list);
+                break;
+            }
             _ => {}
         }
     }
@@ -490,7 +513,7 @@ fn link_staticlib<'a>(
     )?;
     let mut all_native_libs = vec![];
 
-    let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| {
+    let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
         let name = codegen_results.crate_info.crate_name[&cnum];
         let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
 
@@ -1011,16 +1034,36 @@ fn link_natively<'a>(
 
     if sess.target.is_like_osx {
         match (strip, crate_type) {
-            (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+            (Strip::Debuginfo, _) => {
+                strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-S"))
+            }
             // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
             (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
-                strip_symbols_in_osx(sess, &out_filename, Some("-x"))
+                strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-x"))
+            }
+            (Strip::Symbols, _) => {
+                strip_symbols_with_external_utility(sess, "strip", &out_filename, None)
             }
-            (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None),
             (Strip::None, _) => {}
         }
     }
 
+    if sess.target.os == "illumos" {
+        // Many illumos systems will have both the native 'strip' utility and
+        // the GNU one. Use the native version explicitly and do not rely on
+        // what's in the path.
+        let stripcmd = "/usr/bin/strip";
+        match strip {
+            // Always preserve the symbol table (-x).
+            Strip::Debuginfo => {
+                strip_symbols_with_external_utility(sess, stripcmd, &out_filename, Some("-x"))
+            }
+            // Strip::Symbols is handled via the --strip-all linker option.
+            Strip::Symbols => {}
+            Strip::None => {}
+        }
+    }
+
     Ok(())
 }
 
@@ -1032,8 +1075,13 @@ fn strip_value(sess: &Session) -> Strip {
     }
 }
 
-fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
-    let mut cmd = Command::new("strip");
+fn strip_symbols_with_external_utility<'a>(
+    sess: &'a Session,
+    util: &str,
+    out_filename: &Path,
+    option: Option<&str>,
+) {
+    let mut cmd = Command::new(util);
     if let Some(option) = option {
         cmd.arg(option);
     }
@@ -1044,14 +1092,14 @@ fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Opti
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 sess.struct_warn(&format!(
-                    "stripping debug info with `strip` failed: {}",
-                    prog.status
+                    "stripping debug info with `{}` failed: {}",
+                    util, prog.status
                 ))
                 .note(&escape_string(&output))
                 .emit();
             }
         }
-        Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
+        Err(e) => sess.fatal(&format!("unable to run `{}`: {}", util, e)),
     }
 }
 
@@ -2690,7 +2738,7 @@ fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     }
 }
 
-fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
+pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
     match sess.lto() {
         config::Lto::Fat => true,
         config::Lto::Thin => {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index bad22ccb1fe..c49b19bdf00 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -610,7 +610,13 @@ impl<'a> Linker for GccLinker<'a> {
         match strip {
             Strip::None => {}
             Strip::Debuginfo => {
-                self.linker_arg("--strip-debug");
+                // The illumos linker does not support --strip-debug although
+                // it does support --strip-all as a compatibility alias for -s.
+                // The --strip-debug case is handled by running an external
+                // `strip` utility as a separate step after linking.
+                if self.sess.target.os != "illumos" {
+                    self.linker_arg("--strip-debug");
+                }
             }
             Strip::Symbols => {
                 self.linker_arg("--strip-all");
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index b92e146bee2..99ddd176478 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -117,6 +117,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
         "riscv32" => Architecture::Riscv32,
         "riscv64" => Architecture::Riscv64,
         "sparc64" => Architecture::Sparc64,
+        "avr" => Architecture::Avr,
+        "msp430" => Architecture::Msp430,
+        "hexagon" => Architecture::Hexagon,
+        "bpf" => Architecture::Bpf,
         // Unsupported architecture.
         _ => return None,
     };
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 8d7e2c5cf39..c2ecc41601c 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::{self, SymbolName, TyCtxt};
-use rustc_session::config::CrateType;
+use rustc_session::config::{CrateType, OomStrategy};
 use rustc_target::spec::SanitizerSet;
 
 pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
@@ -76,7 +76,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
             // let it through if it's included statically.
             match tcx.hir().get_by_def_id(def_id) {
                 Node::ForeignItem(..) => {
-                    tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
+                    tcx.native_library(def_id).map_or(false, |library| library.kind.is_statically_included()).then_some(def_id)
                 }
 
                 // Only consider nodes that actually have exported symbols.
@@ -206,6 +206,15 @@ fn exported_symbols_provider_local<'tcx>(
                 },
             ));
         }
+
+        symbols.push((
+            ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)),
+            SymbolExportInfo {
+                level: SymbolExportLevel::Rust,
+                kind: SymbolExportKind::Text,
+                used: false,
+            },
+        ));
     }
 
     if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index a292bfce31e..d0ac016b02e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -999,6 +999,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
     let coordinator_send = tx_to_llvm_workers;
     let sess = tcx.sess;
 
+    let mut each_linked_rlib_for_lto = Vec::new();
+    drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+        if link::ignored_for_lto(sess, crate_info, cnum) {
+            return;
+        }
+        each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
+    }));
+
     // Compute the set of symbols we need to retain when doing LTO (if we need to)
     let exported_symbols = {
         let mut exported_symbols = FxHashMap::default();
@@ -1020,7 +1028,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
             }
             Lto::Fat | Lto::Thin => {
                 exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
-                for &cnum in tcx.crates(()).iter() {
+                for &(cnum, ref _path) in &each_linked_rlib_for_lto {
                     exported_symbols.insert(cnum, copy_symbols(cnum));
                 }
                 Some(Arc::new(exported_symbols))
@@ -1040,14 +1048,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         })
         .expect("failed to spawn helper thread");
 
-    let mut each_linked_rlib_for_lto = Vec::new();
-    drop(link::each_linked_rlib(crate_info, &mut |cnum, path| {
-        if link::ignored_for_lto(sess, crate_info, cnum) {
-            return;
-        }
-        each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
-    }));
-
     let ol =
         if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
             // If we know that we won’t be doing codegen, create target machines without optimisation.
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 0ca6408aab9..ff1eee37ad9 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -1,3 +1,4 @@
+use crate::back::link::are_upstream_rust_objects_already_included;
 use crate::back::metadata::create_compressed_metadata_file;
 use crate::back::write::{
     compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
@@ -892,10 +893,14 @@ impl CrateInfo {
 
         // Handle circular dependencies in the standard library.
         // See comment before `add_linked_symbol_object` function for the details.
-        // With msvc-like linkers it's both unnecessary (they support circular dependencies),
-        // and causes linking issues (when weak lang item symbols are "privatized" by LTO).
+        // If global LTO is enabled then almost everything (*) is glued into a single object file,
+        // so this logic is not necessary and can cause issues on some targets (due to weak lang
+        // item symbols being "privatized" to that object file), so we disable it.
+        // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued,
+        // and we assume that they cannot define weak lang items. This is not currently enforced
+        // by the compiler, but that's ok because all this stuff is unstable anyway.
         let target = &tcx.sess.target;
-        if !target.is_like_msvc {
+        if !are_upstream_rust_objects_already_included(tcx.sess) {
             let missing_weak_lang_items: FxHashSet<&Symbol> = info
                 .used_crates
                 .iter()
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 135ed680da2..e05646e1e86 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -666,10 +666,8 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                     hcx.while_hashing_spans(false, |hcx| {
                         ct.to_valtree().hash_stable(hcx, &mut hasher)
                     });
-                    // Note: Don't use `StableHashResult` impl of `u64` here directly, since that
-                    // would lead to endianness problems.
-                    let hash: u128 = hasher.finish();
-                    (hash.to_le() as u64).to_le()
+                    let hash: u64 = hasher.finish();
+                    hash
                 });
 
                 if cpp_like_debuginfo(tcx) {
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 0ffe8872022..ebb531f1c43 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -13,43 +13,43 @@ use std::path::{Path, PathBuf};
 use std::process::ExitStatus;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::lib_def_write_failure)]
+#[diag(codegen_ssa_lib_def_write_failure)]
 pub struct LibDefWriteFailure {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::version_script_write_failure)]
+#[diag(codegen_ssa_version_script_write_failure)]
 pub struct VersionScriptWriteFailure {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::symbol_file_write_failure)]
+#[diag(codegen_ssa_symbol_file_write_failure)]
 pub struct SymbolFileWriteFailure {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::ld64_unimplemented_modifier)]
+#[diag(codegen_ssa_ld64_unimplemented_modifier)]
 pub struct Ld64UnimplementedModifier;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::linker_unsupported_modifier)]
+#[diag(codegen_ssa_linker_unsupported_modifier)]
 pub struct LinkerUnsupportedModifier;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)]
+#[diag(codegen_ssa_L4Bender_exporting_symbols_unimplemented)]
 pub struct L4BenderExportingSymbolsUnimplemented;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::no_natvis_directory)]
+#[diag(codegen_ssa_no_natvis_directory)]
 pub struct NoNatvisDirectory {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::copy_path_buf)]
+#[diag(codegen_ssa_copy_path_buf)]
 pub struct CopyPathBuf {
     pub source_file: PathBuf,
     pub output_path: PathBuf,
@@ -58,7 +58,7 @@ pub struct CopyPathBuf {
 
 // Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::copy_path)]
+#[diag(codegen_ssa_copy_path)]
 pub struct CopyPath<'a> {
     from: DebugArgPath<'a>,
     to: DebugArgPath<'a>,
@@ -80,36 +80,36 @@ impl IntoDiagnosticArg for DebugArgPath<'_> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::ignoring_emit_path)]
+#[diag(codegen_ssa_ignoring_emit_path)]
 pub struct IgnoringEmitPath {
     pub extension: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::ignoring_output)]
+#[diag(codegen_ssa_ignoring_output)]
 pub struct IgnoringOutput {
     pub extension: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::create_temp_dir)]
+#[diag(codegen_ssa_create_temp_dir)]
 pub struct CreateTempDir {
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::incompatible_linking_modifiers)]
+#[diag(codegen_ssa_incompatible_linking_modifiers)]
 pub struct IncompatibleLinkingModifiers;
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::add_native_library)]
+#[diag(codegen_ssa_add_native_library)]
 pub struct AddNativeLibrary {
     pub library_path: PathBuf,
     pub error: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa::multiple_external_func_decl)]
+#[diag(codegen_ssa_multiple_external_func_decl)]
 pub struct MultipleExternalFuncDecl<'a> {
     #[primary_span]
     pub span: Span,
@@ -119,14 +119,17 @@ pub struct MultipleExternalFuncDecl<'a> {
 
 #[derive(Diagnostic)]
 pub enum LinkRlibError {
-    #[diag(codegen_ssa::rlib_missing_format)]
+    #[diag(codegen_ssa_rlib_missing_format)]
     MissingFormat,
 
-    #[diag(codegen_ssa::rlib_only_rmeta_found)]
+    #[diag(codegen_ssa_rlib_only_rmeta_found)]
     OnlyRmetaFound { crate_name: Symbol },
 
-    #[diag(codegen_ssa::rlib_not_found)]
+    #[diag(codegen_ssa_rlib_not_found)]
     NotFound { crate_name: Symbol },
+
+    #[diag(codegen_ssa_rlib_incompatible_dependency_formats)]
+    IncompatibleDependencyFormats { ty1: String, ty2: String, list1: String, list2: String },
 }
 
 pub struct ThorinErrorWrapper(pub thorin::Error);
@@ -136,188 +139,188 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper {
         let mut diag;
         match self.0 {
             thorin::Error::ReadInput(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_read_input_failure);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_read_input_failure);
                 diag
             }
             thorin::Error::ParseFileKind(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_file_kind);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind);
                 diag
             }
             thorin::Error::ParseObjectFile(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_object_file);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file);
                 diag
             }
             thorin::Error::ParseArchiveFile(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_archive_file);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file);
                 diag
             }
             thorin::Error::ParseArchiveMember(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_archive_member);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_archive_member);
                 diag
             }
             thorin::Error::InvalidInputKind => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_invalid_input_kind);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind);
                 diag
             }
             thorin::Error::DecompressData(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_decompress_data);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_decompress_data);
                 diag
             }
             thorin::Error::NamelessSection(_, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_without_name);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_section_without_name);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
                 diag =
-                    handler.struct_err(fluent::codegen_ssa::thorin_relocation_with_invalid_symbol);
+                    handler.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::MultipleRelocations(section, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_relocations);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::UnsupportedRelocation(section, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_unsupported_relocation);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::MissingDwoName(id) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_dwo_name);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
                 diag.set_arg("id", format!("0x{:08x}", id));
                 diag
             }
             thorin::Error::NoCompilationUnits => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_compilation_units);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_no_compilation_units);
                 diag
             }
             thorin::Error::NoDie => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_no_die);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_no_die);
                 diag
             }
             thorin::Error::TopLevelDieNotUnit => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_top_level_die_not_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit);
                 diag
             }
             thorin::Error::MissingRequiredSection(section) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_required_section);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_required_section);
                 diag.set_arg("section", section);
                 diag
             }
             thorin::Error::ParseUnitAbbreviations(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_abbreviations);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
                 diag
             }
             thorin::Error::ParseUnitAttribute(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_attribute);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute);
                 diag
             }
             thorin::Error::ParseUnitHeader(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_header);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_header);
                 diag
             }
             thorin::Error::ParseUnit(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit);
                 diag
             }
             thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_incompatible_index_version);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version);
                 diag.set_arg("section", section);
                 diag.set_arg("actual", actual);
                 diag.set_arg("format", format);
                 diag
             }
             thorin::Error::OffsetAtIndex(_, index) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_offset_at_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_offset_at_index);
                 diag.set_arg("index", index);
                 diag
             }
             thorin::Error::StrAtOffset(_, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_str_at_offset);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
                 diag.set_arg("offset", format!("0x{:08x}", offset));
                 diag
             }
             thorin::Error::ParseIndex(_, section) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_index);
                 diag.set_arg("section", section);
                 diag
             }
             thorin::Error::UnitNotInIndex(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_unit_not_in_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::RowNotInIndex(_, row) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_row_not_in_index);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_row_not_in_index);
                 diag.set_arg("row", row);
                 diag
             }
             thorin::Error::SectionNotInRow => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_section_not_in_row);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_section_not_in_row);
                 diag
             }
             thorin::Error::EmptyUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_empty_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_empty_unit);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::MultipleDebugInfoSection => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_info_section);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section);
                 diag
             }
             thorin::Error::MultipleDebugTypesSection => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_types_section);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section);
                 diag
             }
             thorin::Error::NotSplitUnit => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_split_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_not_split_unit);
                 diag
             }
             thorin::Error::DuplicateUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_duplicate_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::MissingReferencedUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_referenced_unit);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
                 diag.set_arg("unit", format!("0x{:08x}", unit));
                 diag
             }
             thorin::Error::NoOutputObjectCreated => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_not_output_object_created);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_not_output_object_created);
                 diag
             }
             thorin::Error::MixedInputEncodings => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_mixed_input_encodings);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings);
                 diag
             }
             thorin::Error::Io(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_io);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_io);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::ObjectRead(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_read);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_object_read);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::ObjectWrite(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_object_write);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_object_write);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::GimliRead(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_read);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_read);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::GimliWrite(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_write);
+                diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_write);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
@@ -335,7 +338,7 @@ pub struct LinkingFailed<'a> {
 
 impl IntoDiagnostic<'_> for LinkingFailed<'_> {
     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
+        let mut diag = handler.struct_err(fluent::codegen_ssa_linking_failed);
         diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
         diag.set_arg("exit_status", format!("{}", self.exit_status));
 
@@ -344,9 +347,9 @@ impl IntoDiagnostic<'_> for LinkingFailed<'_> {
         // Trying to match an error from OS linkers
         // which by now we have no way to translate.
         if self.escaped_output.contains("undefined reference to") {
-            diag.note(fluent::codegen_ssa::extern_funcs_not_found)
-                .note(fluent::codegen_ssa::specify_libraries_to_link)
-                .note(fluent::codegen_ssa::use_cargo_directive);
+            diag.note(fluent::codegen_ssa_extern_funcs_not_found)
+                .note(fluent::codegen_ssa_specify_libraries_to_link)
+                .note(fluent::codegen_ssa_use_cargo_directive);
         }
         diag
     }
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c6cb7a8b961..4b055076742 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -3,18 +3,18 @@ use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unstable_in_stable)]
+#[diag(const_eval_unstable_in_stable)]
 pub(crate) struct UnstableInStable {
     pub gate: String,
     #[primary_span]
     pub span: Span,
     #[suggestion(
-        const_eval::unstable_sugg,
+        unstable_sugg,
         code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
         applicability = "has-placeholders"
     )]
     #[suggestion(
-        const_eval::bypass_sugg,
+        bypass_sugg,
         code = "#[rustc_allow_const_fn_unstable({gate})]\n",
         applicability = "has-placeholders"
     )]
@@ -22,35 +22,35 @@ pub(crate) struct UnstableInStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::thread_local_access, code = "E0625")]
+#[diag(const_eval_thread_local_access, code = "E0625")]
 pub(crate) struct NonConstOpErr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::static_access, code = "E0013")]
+#[diag(const_eval_static_access, code = "E0013")]
 #[help]
 pub(crate) struct StaticAccessErr {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
-    #[help(const_eval::teach_help)]
+    #[note(teach_note)]
+    #[help(teach_help)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::raw_ptr_to_int)]
+#[diag(const_eval_raw_ptr_to_int)]
 #[note]
-#[note(const_eval::note2)]
+#[note(note2)]
 pub(crate) struct RawPtrToIntErr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::raw_ptr_comparison)]
+#[diag(const_eval_raw_ptr_comparison)]
 #[note]
 pub(crate) struct RawPtrComparisonErr {
     #[primary_span]
@@ -58,14 +58,14 @@ pub(crate) struct RawPtrComparisonErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::panic_non_str)]
+#[diag(const_eval_panic_non_str)]
 pub(crate) struct PanicNonStrErr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::mut_deref, code = "E0658")]
+#[diag(const_eval_mut_deref, code = "E0658")]
 pub(crate) struct MutDerefErr {
     #[primary_span]
     pub span: Span,
@@ -73,7 +73,7 @@ pub(crate) struct MutDerefErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::transient_mut_borrow, code = "E0658")]
+#[diag(const_eval_transient_mut_borrow, code = "E0658")]
 pub(crate) struct TransientMutBorrowErr {
     #[primary_span]
     pub span: Span,
@@ -81,7 +81,7 @@ pub(crate) struct TransientMutBorrowErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::transient_mut_borrow_raw, code = "E0658")]
+#[diag(const_eval_transient_mut_borrow_raw, code = "E0658")]
 pub(crate) struct TransientMutBorrowErrRaw {
     #[primary_span]
     pub span: Span,
@@ -89,7 +89,7 @@ pub(crate) struct TransientMutBorrowErrRaw {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::max_num_nodes_in_const)]
+#[diag(const_eval_max_num_nodes_in_const)]
 pub(crate) struct MaxNumNodesInConstErr {
     #[primary_span]
     pub span: Span,
@@ -97,7 +97,7 @@ pub(crate) struct MaxNumNodesInConstErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_fn_pointer_call)]
+#[diag(const_eval_unallowed_fn_pointer_call)]
 pub(crate) struct UnallowedFnPointerCall {
     #[primary_span]
     pub span: Span,
@@ -105,7 +105,7 @@ pub(crate) struct UnallowedFnPointerCall {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unstable_const_fn)]
+#[diag(const_eval_unstable_const_fn)]
 pub(crate) struct UnstableConstFn {
     #[primary_span]
     pub span: Span,
@@ -113,26 +113,26 @@ pub(crate) struct UnstableConstFn {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_mutable_refs, code = "E0764")]
+#[diag(const_eval_unallowed_mutable_refs, code = "E0764")]
 pub(crate) struct UnallowedMutableRefs {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")]
+#[diag(const_eval_unallowed_mutable_refs_raw, code = "E0764")]
 pub(crate) struct UnallowedMutableRefsRaw {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 #[derive(Diagnostic)]
-#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")]
+#[diag(const_eval_non_const_fmt_macro_call, code = "E0015")]
 pub(crate) struct NonConstFmtMacroCall {
     #[primary_span]
     pub span: Span,
@@ -140,7 +140,7 @@ pub(crate) struct NonConstFmtMacroCall {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::non_const_fn_call, code = "E0015")]
+#[diag(const_eval_non_const_fn_call, code = "E0015")]
 pub(crate) struct NonConstFnCall {
     #[primary_span]
     pub span: Span,
@@ -149,7 +149,7 @@ pub(crate) struct NonConstFnCall {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_op_in_const_context)]
+#[diag(const_eval_unallowed_op_in_const_context)]
 pub(crate) struct UnallowedOpInConstContext {
     #[primary_span]
     pub span: Span,
@@ -157,18 +157,18 @@ pub(crate) struct UnallowedOpInConstContext {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_heap_allocations, code = "E0010")]
+#[diag(const_eval_unallowed_heap_allocations, code = "E0010")]
 pub(crate) struct UnallowedHeapAllocations {
     #[primary_span]
     #[label]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::unallowed_inline_asm, code = "E0015")]
+#[diag(const_eval_unallowed_inline_asm, code = "E0015")]
 pub(crate) struct UnallowedInlineAsm {
     #[primary_span]
     pub span: Span,
@@ -176,7 +176,7 @@ pub(crate) struct UnallowedInlineAsm {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::interior_mutable_data_refer, code = "E0492")]
+#[diag(const_eval_interior_mutable_data_refer, code = "E0492")]
 pub(crate) struct InteriorMutableDataRefer {
     #[primary_span]
     #[label]
@@ -184,12 +184,12 @@ pub(crate) struct InteriorMutableDataRefer {
     #[help]
     pub opt_help: Option<()>,
     pub kind: ConstContext,
-    #[note(const_eval::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval::interior_mutability_borrow)]
+#[diag(const_eval_interior_mutability_borrow)]
 pub(crate) struct InteriorMutabilityBorrow {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 50a82aa0e72..57e40e168fa 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -35,7 +35,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 assert_eq!(discr.layout.ty, switch_ty);
 
                 // Branch to the `otherwise` case by default, if no match is found.
-                assert!(!targets.iter().is_empty());
                 let mut target_block = targets.otherwise();
 
                 for (const_int, target) in targets.iter() {
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 87b7c55bf7f..fbb129f9724 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -284,7 +284,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         this.fail(
                         location,
                         format!(
-                            "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}",
+                            "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
                             parent, f, ty, f_ty
                         )
                     )
diff --git a/compiler/rustc_data_structures/src/flock/linux.rs b/compiler/rustc_data_structures/src/flock/linux.rs
index bb3ecfbc370..9ed26e49006 100644
--- a/compiler/rustc_data_structures/src/flock/linux.rs
+++ b/compiler/rustc_data_structures/src/flock/linux.rs
@@ -14,12 +14,7 @@ pub struct Lock {
 
 impl Lock {
     pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
-        let file = OpenOptions::new()
-            .read(true)
-            .write(true)
-            .create(create)
-            .mode(libc::S_IRWXU as u32)
-            .open(p)?;
+        let file = OpenOptions::new().read(true).write(true).create(create).mode(0o600).open(p)?;
 
         let mut operation = if exclusive { libc::LOCK_EX } else { libc::LOCK_SH };
         if !wait {
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index 4fda3adb7b8..406f0270dcc 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -27,7 +27,7 @@ pub struct SsoHashSet<T> {
     map: SsoHashMap<T, ()>,
 }
 
-/// Adapter function used ot return
+/// Adapter function used to return
 /// result if SsoHashMap functions into
 /// result SsoHashSet should return.
 #[inline(always)]
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index f016c391fe7..cf616203842 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -1,5 +1,5 @@
 use crate::frozen::Frozen;
-use crate::fx::FxIndexSet;
+use crate::fx::{FxHashSet, FxIndexSet};
 use rustc_index::bit_set::BitMatrix;
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -16,7 +16,7 @@ pub struct TransitiveRelationBuilder<T> {
 
     // List of base edges in the graph. Require to compute transitive
     // closure.
-    edges: Vec<Edge>,
+    edges: FxHashSet<Edge>,
 }
 
 #[derive(Debug)]
@@ -52,10 +52,10 @@ impl<T: Eq + Hash> Default for TransitiveRelationBuilder<T> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
 struct Index(usize);
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 struct Edge {
     source: Index,
     target: Index,
@@ -99,9 +99,7 @@ impl<T: Eq + Hash + Copy> TransitiveRelationBuilder<T> {
         let a = self.add_index(a);
         let b = self.add_index(b);
         let edge = Edge { source: a, target: b };
-        if !self.edges.contains(&edge) {
-            self.edges.push(edge);
-        }
+        self.edges.insert(edge);
     }
 
     /// Compute the transitive closure derived from the edges, and converted to
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 7d5604fcabc..7edbb6f757c 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -35,7 +35,7 @@ use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, Tr
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::getopts;
 use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, DiagnosticOutput, Session};
+use rustc_session::{config, Session};
 use rustc_session::{early_error, early_error_no_abort, early_warn};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
@@ -147,19 +147,21 @@ pub struct RunCompiler<'a, 'b> {
     at_args: &'a [String],
     callbacks: &'b mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    emitter: Option<Box<dyn Write + Send>>,
     make_codegen_backend:
         Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
 }
 
 impl<'a, 'b> RunCompiler<'a, 'b> {
     pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
-        Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
+        Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
     }
 
     /// Set a custom codegen backend.
     ///
-    /// Used by cg_clif.
+    /// Has no uses within this repository, but is used by bjorn3 for "the
+    /// hotswapping branch of cg_clif" for "setting the codegen backend from a
+    /// custom driver where the custom codegen backend has arbitrary data."
+    /// (See #102759.)
     pub fn set_make_codegen_backend(
         &mut self,
         make_codegen_backend: Option<
@@ -170,17 +172,11 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
         self
     }
 
-    /// Emit diagnostics to the specified location.
-    ///
-    /// Used by RLS.
-    pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
-        self.emitter = emitter;
-        self
-    }
-
     /// Load files from sources other than the file system.
     ///
-    /// Used by RLS.
+    /// Has no uses within this repository, but may be used in the future by
+    /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
+    /// running rustc without having to save". (See #102759.)
     pub fn set_file_loader(
         &mut self,
         file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
@@ -191,27 +187,20 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
 
     /// Parse args and run the compiler.
     pub fn run(self) -> interface::Result<()> {
-        run_compiler(
-            self.at_args,
-            self.callbacks,
-            self.file_loader,
-            self.emitter,
-            self.make_codegen_backend,
-        )
+        run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
     }
 }
+
 fn run_compiler(
     at_args: &[String],
     callbacks: &mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    emitter: Option<Box<dyn Write + Send>>,
     make_codegen_backend: Option<
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
     let args = args::arg_expand_all(at_args);
 
-    let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
     let Some(matches) = handle_options(&args) else { return Ok(()) };
 
     let sopts = config::build_session_options(&matches);
@@ -233,7 +222,6 @@ fn run_compiler(
         output_file: ofile,
         output_dir: odir,
         file_loader,
-        diagnostic_output,
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs
index 289baf17773..c1bc1089114 100644
--- a/compiler/rustc_driver/src/session_diagnostics.rs
+++ b/compiler/rustc_driver/src/session_diagnostics.rs
@@ -1,39 +1,39 @@
 use rustc_macros::Diagnostic;
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_unable_to_read)]
+#[diag(driver_rlink_unable_to_read)]
 pub(crate) struct RlinkUnableToRead {
     pub err: std::io::Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_wrong_file_type)]
+#[diag(driver_rlink_wrong_file_type)]
 pub(crate) struct RLinkWrongFileType;
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_empty_version_number)]
+#[diag(driver_rlink_empty_version_number)]
 pub(crate) struct RLinkEmptyVersionNumber;
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_encoding_version_mismatch)]
+#[diag(driver_rlink_encoding_version_mismatch)]
 pub(crate) struct RLinkEncodingVersionMismatch {
     pub version_array: String,
     pub rlink_version: u32,
 }
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_rustc_version_mismatch)]
+#[diag(driver_rlink_rustc_version_mismatch)]
 pub(crate) struct RLinkRustcVersionMismatch<'a> {
     pub rustc_version: String,
     pub current_version: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(driver::rlink_no_a_file)]
+#[diag(driver_rlink_no_a_file)]
 pub(crate) struct RlinkNotAFile;
 
 #[derive(Diagnostic)]
-#[diag(driver::unpretty_dump_fail)]
+#[diag(driver_unpretty_dump_fail)]
 pub(crate) struct UnprettyDumpFail {
     pub path: String,
     pub err: String,
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
index 0d0388a039e..966a421bcf0 100644
--- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -34,6 +34,8 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo
 
 codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
 
+codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
+
 codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index c6a4ff6f0e0..357c6900a70 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -133,3 +133,7 @@ hir_analysis_extern_crate_not_idiomatic =
     .suggestion = convert it to a `{$msg_code}`
 
 hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+
+hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl
index 65371a28591..18b3408b06a 100644
--- a/compiler/rustc_error_messages/locales/en-US/infer.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl
@@ -164,7 +164,9 @@ infer_region_explanation = {$pref_kind ->
 }
 
 infer_mismatched_static_lifetime = incompatible lifetime on type
-infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
+infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
 infer_msl_introduces_static = introduces a `'static` lifetime requirement
 infer_msl_unmet_req = because this has an unmet lifetime requirement
 infer_msl_trait_note = this has an implicit `'static` lifetime requirement
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl
index 47127ea8e9c..e2277923072 100644
--- a/compiler/rustc_error_messages/locales/en-US/session.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/session.ftl
@@ -54,3 +54,7 @@ session_crate_name_empty = crate name must not be empty
 session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
 
 session_expr_parentheses_needed = parentheses are required to parse this as an expression
+
+session_skipping_const_checks = skipping const checks
+session_unleashed_feature_help_named = skipping check for `{$gate}` feature
+session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 518c59dba53..a63fc0ca285 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -567,6 +567,11 @@ impl Diagnostic {
         style: SuggestionStyle,
     ) -> &mut Self {
         assert!(!suggestion.is_empty());
+        debug_assert!(
+            !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())),
+            "Span must not be empty and have no suggestion"
+        );
+
         self.push_suggestion(CodeSuggestion {
             substitutions: vec![Substitution {
                 parts: suggestion
@@ -644,6 +649,10 @@ impl Diagnostic {
         applicability: Applicability,
         style: SuggestionStyle,
     ) -> &mut Self {
+        debug_assert!(
+            !(sp.is_empty() && suggestion.to_string().is_empty()),
+            "Span must not be empty and have no suggestion"
+        );
         self.push_suggestion(CodeSuggestion {
             substitutions: vec![Substitution {
                 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
@@ -684,6 +693,12 @@ impl Diagnostic {
     ) -> &mut Self {
         let mut suggestions: Vec<_> = suggestions.collect();
         suggestions.sort();
+
+        debug_assert!(
+            !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
+            "Span must not be empty and have no suggestion"
+        );
+
         let substitutions = suggestions
             .into_iter()
             .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
@@ -705,8 +720,18 @@ impl Diagnostic {
         suggestions: impl Iterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self {
+        let suggestions: Vec<_> = suggestions.collect();
+        debug_assert!(
+            !(suggestions
+                .iter()
+                .flat_map(|suggs| suggs)
+                .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())),
+            "Span must not be empty and have no suggestion"
+        );
+
         self.push_suggestion(CodeSuggestion {
             substitutions: suggestions
+                .into_iter()
                 .map(|sugg| Substitution {
                     parts: sugg
                         .into_iter()
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 860f24871bc..7640b2919f7 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,14 +1,14 @@
 use crate::{
     fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg,
 };
-use rustc_target::abi::TargetDataLayoutErrors;
-use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
-
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_hir as hir;
+use rustc_lint_defs::Level;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
+use rustc_target::abi::TargetDataLayoutErrors;
+use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
 use std::borrow::Cow;
 use std::fmt;
 use std::num::ParseIntError;
@@ -155,19 +155,34 @@ impl IntoDiagnosticArg for ast::token::TokenKind {
     }
 }
 
+impl IntoDiagnosticArg for Level {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Borrowed(match self {
+            Level::Allow => "-A",
+            Level::Warn => "-W",
+            Level::ForceWarn(_) => "--force-warn",
+            Level::Deny => "-D",
+            Level::Forbid => "-F",
+            Level::Expect(_) => {
+                unreachable!("lints with the level of `expect` should not run this code");
+            }
+        }))
+    }
+}
+
 impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
         let mut diag;
         match self {
             TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
-                diag = handler.struct_fatal(fluent::errors::target_invalid_address_space);
+                diag = handler.struct_fatal(fluent::errors_target_invalid_address_space);
                 diag.set_arg("addr_space", addr_space);
                 diag.set_arg("cause", cause);
                 diag.set_arg("err", err);
                 diag
             }
             TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
-                diag = handler.struct_fatal(fluent::errors::target_invalid_bits);
+                diag = handler.struct_fatal(fluent::errors_target_invalid_bits);
                 diag.set_arg("kind", kind);
                 diag.set_arg("bit", bit);
                 diag.set_arg("cause", cause);
@@ -175,30 +190,30 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
                 diag
             }
             TargetDataLayoutErrors::MissingAlignment { cause } => {
-                diag = handler.struct_fatal(fluent::errors::target_missing_alignment);
+                diag = handler.struct_fatal(fluent::errors_target_missing_alignment);
                 diag.set_arg("cause", cause);
                 diag
             }
             TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
-                diag = handler.struct_fatal(fluent::errors::target_invalid_alignment);
+                diag = handler.struct_fatal(fluent::errors_target_invalid_alignment);
                 diag.set_arg("cause", cause);
                 diag.set_arg("err", err);
                 diag
             }
             TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
-                diag = handler.struct_fatal(fluent::errors::target_inconsistent_architecture);
+                diag = handler.struct_fatal(fluent::errors_target_inconsistent_architecture);
                 diag.set_arg("dl", dl);
                 diag.set_arg("target", target);
                 diag
             }
             TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
-                diag = handler.struct_fatal(fluent::errors::target_inconsistent_pointer_width);
+                diag = handler.struct_fatal(fluent::errors_target_inconsistent_pointer_width);
                 diag.set_arg("pointer_size", pointer_size);
                 diag.set_arg("target", target);
                 diag
             }
             TargetDataLayoutErrors::InvalidBitsSize { err } => {
-                diag = handler.struct_fatal(fluent::errors::target_invalid_bits_size);
+                diag = handler.struct_fatal(fluent::errors_target_invalid_bits_size);
                 diag.set_arg("err", err);
                 diag
             }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 9fafbe4bd40..0963ea71f80 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -463,6 +463,9 @@ pub enum StashKey {
     UnderscoreForArrayLengths,
     EarlySyntaxWarning,
     CallIntoMethod,
+    /// When an invalid lifetime e.g. `'2` should be reinterpreted
+    /// as a char literal in the parser
+    LifetimeIsChar,
 }
 
 fn default_track_diagnostic(_: &Diagnostic) {}
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index cd8a525e062..052ca229f01 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -22,7 +22,7 @@ use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{FileName, Span, DUMMY_SP};
+use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
 use std::default::Default;
@@ -1228,8 +1228,9 @@ pub fn expr_to_spanned_string<'a>(
             ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
             ast::LitKind::ByteStr(_) => {
                 let mut err = cx.struct_span_err(l.span, err_msg);
+                let span = expr.span.shrink_to_lo();
                 err.span_suggestion(
-                    expr.span.shrink_to_lo(),
+                    span.with_hi(span.lo() + BytePos(1)),
                     "consider removing the leading `b`",
                     "",
                     Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index bd93f0717f5..d383f4832f6 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -3,28 +3,28 @@ use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(expand::expr_repeat_no_syntax_vars)]
+#[diag(expand_expr_repeat_no_syntax_vars)]
 pub(crate) struct NoSyntaxVarsExprRepeat {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::must_repeat_once)]
+#[diag(expand_must_repeat_once)]
 pub(crate) struct MustRepeatOnce {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::count_repetition_misplaced)]
+#[diag(expand_count_repetition_misplaced)]
 pub(crate) struct CountRepetitionMisplaced {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::meta_var_expr_unrecognized_var)]
+#[diag(expand_meta_var_expr_unrecognized_var)]
 pub(crate) struct MetaVarExprUnrecognizedVar {
     #[primary_span]
     pub span: Span,
@@ -32,7 +32,7 @@ pub(crate) struct MetaVarExprUnrecognizedVar {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::var_still_repeating)]
+#[diag(expand_var_still_repeating)]
 pub(crate) struct VarStillRepeating {
     #[primary_span]
     pub span: Span,
@@ -40,7 +40,7 @@ pub(crate) struct VarStillRepeating {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand::meta_var_dif_seq_matchers)]
+#[diag(expand_meta_var_dif_seq_matchers)]
 pub(crate) struct MetaVarsDifSeqMatchers {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 59f434b941e..15e9a8db3c6 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -937,13 +937,12 @@ pub fn ensure_complete_parse<'a>(
             kind_name,
         );
         err.note(&msg);
-        let semi_span = this.sess.source_map().next_point(span);
 
-        let semi_full_span = semi_span.to(this.sess.source_map().next_point(semi_span));
-        match this.sess.source_map().span_to_snippet(semi_full_span) {
+        let semi_span = this.sess.source_map().next_point(span);
+        match this.sess.source_map().span_to_snippet(semi_span) {
             Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
                 err.span_suggestion(
-                    semi_span,
+                    span.shrink_to_hi(),
                     "you might be missing a semicolon here",
                     ";",
                     Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 30aa4f0fa34..1e268542bcd 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -82,7 +82,7 @@ fn emit_frag_parse_err(
         );
         if !e.span.is_dummy() {
             // early end of macro arm (#52866)
-            e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
+            e.replace_span_with(parser.token.span.shrink_to_hi());
         }
     }
     if e.span.is_dummy() {
@@ -598,12 +598,12 @@ pub fn compile_declarative_macro(
 
 #[derive(Subdiagnostic)]
 enum ExplainDocComment {
-    #[label(expand::explain_doc_comment_inner)]
+    #[label(expand_explain_doc_comment_inner)]
     Inner {
         #[primary_span]
         span: Span,
     },
-    #[label(expand::explain_doc_comment_outer)]
+    #[label(expand_explain_doc_comment_outer)]
     Outer {
         #[primary_span]
         span: Span,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index ca12659695f..54bf5a2c34b 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -53,6 +53,8 @@ declare_features! (
     (accepted, abi_sysv64, "1.24.0", Some(36167), None),
     /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
     (accepted, adx_target_feature, "1.61.0", Some(44839), None),
+    /// Allows using `sym` operands in inline assembly.
+    (accepted, asm_sym, "CURRENT_RUSTC_VERSION", Some(93333), None),
     /// Allows the definition of associated constants in `trait` or `impl` blocks.
     (accepted, associated_consts, "1.20.0", Some(29646), None),
     /// Allows using associated `type`s in `trait`s.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 5ea433e6b3d..1b8d683b133 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -300,8 +300,6 @@ declare_features! (
     (active, asm_const, "1.58.0", Some(93332), None),
     /// Enables experimental inline assembly support for additional architectures.
     (active, asm_experimental_arch, "1.58.0", Some(93335), None),
-    /// Allows using `sym` operands in inline assembly.
-    (active, asm_sym, "1.58.0", Some(93333), None),
     /// Allows the `may_unwind` option in inline assembly.
     (active, asm_unwind, "1.58.0", Some(93334), None),
     /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 92d0fb1aec8..2ead3c2c8d4 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -296,20 +296,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // Lints:
     ungated!(
-        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(
-        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     gated!(
         expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk,
         lint_reasons, experimental!(expect)
     ),
     ungated!(
-        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(
-        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        DuplicatesOk, @only_local: true,
     ),
     ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
     gated!(
@@ -340,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_link, Normal, template!(Word), WarnFollowing),
-    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
+    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
     ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
@@ -382,7 +386,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true),
     ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true),
     ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
-    ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
+    ungated!(
+        target_feature, Normal, template!(List: r#"enable = "name""#),
+        DuplicatesOk, @only_local: true,
+    ),
     ungated!(track_caller, Normal, template!(Word), WarnFollowing),
     gated!(
         no_sanitize, Normal,
@@ -488,18 +495,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes: Stability, deprecation, and unsafe:
     // ==========================================================================
 
-    ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
+    ungated!(
+        feature, CrateLevel,
+        template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true,
+    ),
     // DuplicatesOk since it has its own validation
     ungated!(
-        stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
+        stable, Normal,
+        template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true,
     ),
     ungated!(
         unstable, Normal,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
     ),
     ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
-    ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
-    ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
+    ungated!(
+        rustc_const_stable, Normal,
+        template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true,
+    ),
     ungated!(
         rustc_default_body_unstable, Normal,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
@@ -517,6 +530,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
         "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
+    ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
     rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
     "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
     through unstable paths"),
@@ -732,7 +746,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
          for reserving for `for<T> From<!> for T` impl"
     ),
     rustc_attr!(
-        rustc_test_marker, Normal, template!(Word), WarnFollowing,
+        rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
         "the `#[rustc_test_marker]` attribute is used internally to track tests",
     ),
     rustc_attr!(
@@ -823,6 +837,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
 
+/// Whether this builtin attribute is only used in the local crate.
+/// If so, it is not encoded in the crate metadata.
 pub fn is_builtin_only_local(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
 }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 6e373e41b4c..a0350c26d82 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -582,7 +582,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         assoc_bindings
     }
 
-    pub(crate) fn create_substs_for_associated_item(
+    pub fn create_substs_for_associated_item(
         &self,
         span: Span,
         item_def_id: DefId,
@@ -3051,24 +3051,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .map_or(false, |s| s.trim_end().ends_with('<'));
 
             let is_global = poly_trait_ref.trait_ref.path.is_global();
-            let sugg = Vec::from_iter([
-                (
-                    self_ty.span.shrink_to_lo(),
-                    format!(
-                        "{}dyn {}",
-                        if needs_bracket { "<" } else { "" },
-                        if is_global { "(" } else { "" },
-                    ),
+
+            let mut sugg = Vec::from_iter([(
+                self_ty.span.shrink_to_lo(),
+                format!(
+                    "{}dyn {}",
+                    if needs_bracket { "<" } else { "" },
+                    if is_global { "(" } else { "" },
                 ),
-                (
+            )]);
+
+            if is_global || needs_bracket {
+                sugg.push((
                     self_ty.span.shrink_to_hi(),
                     format!(
                         "{}{}",
                         if is_global { ")" } else { "" },
                         if needs_bracket { ">" } else { "" },
                     ),
-                ),
-            ]);
+                ));
+            }
+
             if self_ty.span.edition() >= Edition::Edition2021 {
                 let msg = "trait objects must include the `dyn` keyword";
                 let label = "add `dyn` keyword before this trait";
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index c3583eeb430..a1faf802519 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,6 +1,5 @@
 use crate::check::intrinsicck::InlineAsmCtxt;
 
-use super::coercion::CoerceMany;
 use super::compare_method::check_type_bounds;
 use super::compare_method::{compare_impl_method, compare_ty_impl};
 use super::*;
@@ -10,10 +9,8 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
@@ -34,7 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 use std::ops::ControlFlow;
 
-pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
+pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
     match tcx.sess.target.is_abi_supported(abi) {
         Some(true) => (),
         Some(false) => {
@@ -69,313 +66,6 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
     }
 }
 
-/// Helper used for fns and closures. Does the grungy work of checking a function
-/// body and returns the function context used for that purpose, since in the case of a fn item
-/// there is still a bit more to do.
-///
-/// * ...
-/// * inherited: other fields inherited from the enclosing fn (if any)
-#[instrument(skip(inherited, body), level = "debug")]
-pub(super) fn check_fn<'a, 'tcx>(
-    inherited: &'a Inherited<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    fn_sig: ty::FnSig<'tcx>,
-    decl: &'tcx hir::FnDecl<'tcx>,
-    fn_id: hir::HirId,
-    body: &'tcx hir::Body<'tcx>,
-    can_be_generator: Option<hir::Movability>,
-    return_type_pre_known: bool,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
-    // Create the function context. This is either derived from scratch or,
-    // in the case of closures, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
-    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
-    fcx.return_type_pre_known = return_type_pre_known;
-
-    let tcx = fcx.tcx;
-    let hir = tcx.hir();
-
-    let declared_ret_ty = fn_sig.output();
-
-    let ret_ty =
-        fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
-            declared_ret_ty,
-            body.value.hir_id,
-            decl.output.span(),
-            param_env,
-        ));
-    // If we replaced declared_ret_ty with infer vars, then we must be inferring
-    // an opaque type, so set a flag so we can improve diagnostics.
-    fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
-
-    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
-
-    let span = body.value.span;
-
-    fn_maybe_err(tcx, span, fn_sig.abi);
-
-    if fn_sig.abi == Abi::RustCall {
-        let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
-        let err = || {
-            let item = match tcx.hir().get(fn_id) {
-                Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
-                Node::ImplItem(hir::ImplItem {
-                    kind: hir::ImplItemKind::Fn(header, ..), ..
-                }) => Some(header),
-                Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(header, ..),
-                    ..
-                }) => Some(header),
-                // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
-                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
-                node => bug!("Item being checked wasn't a function/closure: {:?}", node),
-            };
-
-            if let Some(header) = item {
-                tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
-            }
-        };
-
-        if fn_sig.inputs().len() != expected_args {
-            err()
-        } else {
-            // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
-            //   This will probably require wide-scale changes to support a TupleKind obligation
-            //   We can't resolve this without knowing the type of the param
-            if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
-                err()
-            }
-        }
-    }
-
-    if body.generator_kind.is_some() && can_be_generator.is_some() {
-        let yield_ty = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
-        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
-
-        // Resume type defaults to `()` if the generator has no argument.
-        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
-
-        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
-    }
-
-    GatherLocalsVisitor::new(&fcx).visit_body(body);
-
-    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
-    // (as it's created inside the body itself, not passed in from outside).
-    let maybe_va_list = if fn_sig.c_variadic {
-        let span = body.params.last().unwrap().span;
-        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
-        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
-
-        Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
-    } else {
-        None
-    };
-
-    // Add formal parameters.
-    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
-    let inputs_fn = fn_sig.inputs().iter().copied();
-    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
-        // Check the pattern.
-        let ty_span = try { inputs_hir?.get(idx)?.span };
-        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
-
-        // Check that argument is Sized.
-        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
-        // for simple cases like `fn foo(x: Trait)`,
-        // where we would error once on the parameter as a whole, and once on the binding `x`.
-        if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
-            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
-        }
-
-        fcx.write_ty(param.hir_id, param_ty);
-    }
-
-    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
-
-    fcx.in_tail_expr = true;
-    if let ty::Dynamic(..) = declared_ret_ty.kind() {
-        // FIXME: We need to verify that the return type is `Sized` after the return expression has
-        // been evaluated so that we have types available for all the nodes being returned, but that
-        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
-        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
-        // while keeping the current ordering we will ignore the tail expression's type because we
-        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
-        // because we will trigger "unreachable expression" lints unconditionally.
-        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
-        // case that a newcomer might make, returning a bare trait, and in that case we populate
-        // the tail expression's type so that the suggestion will be correct, but ignore all other
-        // possible cases.
-        fcx.check_expr(&body.value);
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-    } else {
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        fcx.check_return_expr(&body.value, false);
-    }
-    fcx.in_tail_expr = false;
-
-    // We insert the deferred_generator_interiors entry after visiting the body.
-    // This ensures that all nested generators appear before the entry of this generator.
-    // resolve_generator_interiors relies on this property.
-    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
-        let interior = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
-        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
-
-        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
-        Some(GeneratorTypes {
-            resume_ty,
-            yield_ty,
-            interior,
-            movability: can_be_generator.unwrap(),
-        })
-    } else {
-        None
-    };
-
-    // Finalize the return check by taking the LUB of the return types
-    // we saw and assigning it to the expected return type. This isn't
-    // really expected to fail, since the coercions would have failed
-    // earlier when trying to find a LUB.
-    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
-    let mut actual_return_ty = coercion.complete(&fcx);
-    debug!("actual_return_ty = {:?}", actual_return_ty);
-    if let ty::Dynamic(..) = declared_ret_ty.kind() {
-        // We have special-cased the case where the function is declared
-        // `-> dyn Foo` and we don't actually relate it to the
-        // `fcx.ret_coercion`, so just substitute a type variable.
-        actual_return_ty =
-            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
-        debug!("actual_return_ty replaced with {:?}", actual_return_ty);
-    }
-
-    // HACK(oli-obk, compiler-errors): We should be comparing this against
-    // `declared_ret_ty`, but then anything uninferred would be inferred to
-    // the opaque type itself. That again would cause writeback to assume
-    // we have a recursive call site and do the sadly stabilized fallback to `()`.
-    fcx.demand_suptype(span, ret_ty, actual_return_ty);
-
-    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
-    if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
-        && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
-    {
-        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
-    }
-
-    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
-    if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
-        && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
-    {
-        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
-    }
-
-    (fcx, gen_ty)
-}
-
-fn check_panic_info_fn(
-    tcx: TyCtxt<'_>,
-    fn_id: LocalDefId,
-    fn_sig: ty::FnSig<'_>,
-    decl: &hir::FnDecl<'_>,
-    declared_ret_ty: Ty<'_>,
-) {
-    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
-        tcx.sess.err("language item required, but not found: `panic_info`");
-        return;
-    };
-
-    if *declared_ret_ty.kind() != ty::Never {
-        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
-    }
-
-    let inputs = fn_sig.inputs();
-    if inputs.len() != 1 {
-        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
-        return;
-    }
-
-    let arg_is_panic_info = match *inputs[0].kind() {
-        ty::Ref(region, ty, mutbl) => match *ty.kind() {
-            ty::Adt(ref adt, _) => {
-                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
-            }
-            _ => false,
-        },
-        _ => false,
-    };
-
-    if !arg_is_panic_info {
-        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-    }
-
-    let DefKind::Fn = tcx.def_kind(fn_id) else {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should be a function");
-        return;
-    };
-
-    let generic_counts = tcx.generics_of(fn_id).own_counts();
-    if generic_counts.types != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should have no type parameters");
-    }
-    if generic_counts.consts != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should have no const parameters");
-    }
-}
-
-fn check_alloc_error_fn(
-    tcx: TyCtxt<'_>,
-    fn_id: LocalDefId,
-    fn_sig: ty::FnSig<'_>,
-    decl: &hir::FnDecl<'_>,
-    declared_ret_ty: Ty<'_>,
-) {
-    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
-        tcx.sess.err("language item required, but not found: `alloc_layout`");
-        return;
-    };
-
-    if *declared_ret_ty.kind() != ty::Never {
-        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
-    }
-
-    let inputs = fn_sig.inputs();
-    if inputs.len() != 1 {
-        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
-        return;
-    }
-
-    let arg_is_alloc_layout = match inputs[0].kind() {
-        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
-        _ => false,
-    };
-
-    if !arg_is_alloc_layout {
-        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-    }
-
-    let DefKind::Fn = tcx.def_kind(fn_id) else {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
-        return;
-    };
-
-    let generic_counts = tcx.generics_of(fn_id).own_counts();
-    if generic_counts.types != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
-    }
-    if generic_counts.consts != 0 {
-        let span = tcx.def_span(fn_id);
-        tcx.sess
-            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
-    }
-}
-
 fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 5e5dbedb4bd..3469ec4767b 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -465,30 +465,30 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
     let ocx = ObligationCtxt::new(infcx);
 
     let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
-    let impl_return_ty = ocx.normalize(
+    let impl_sig = ocx.normalize(
         norm_cause.clone(),
         param_env,
-        infcx
-            .replace_bound_vars_with_fresh_vars(
-                return_span,
-                infer::HigherRankedType,
-                tcx.fn_sig(impl_m.def_id),
-            )
-            .output(),
+        infcx.replace_bound_vars_with_fresh_vars(
+            return_span,
+            infer::HigherRankedType,
+            tcx.fn_sig(impl_m.def_id),
+        ),
     );
+    let impl_return_ty = impl_sig.output();
 
     let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
-    let unnormalized_trait_return_ty = tcx
+    let unnormalized_trait_sig = tcx
         .liberate_late_bound_regions(
             impl_m.def_id,
             tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
         )
-        .output()
         .fold_with(&mut collector);
-    let trait_return_ty =
-        ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
+    let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
+    let trait_return_ty = trait_sig.output();
 
-    let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
+    let wf_tys = FxHashSet::from_iter(
+        unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+    );
 
     match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
         Ok(infer::InferOk { value: (), obligations }) => {
@@ -521,6 +521,26 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
         }
     }
 
+    // Unify the whole function signature. We need to do this to fully infer
+    // the lifetimes of the return type, but do this after unifying just the
+    // return types, since we want to avoid duplicating errors from
+    // `compare_predicate_entailment`.
+    match infcx
+        .at(&cause, param_env)
+        .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
+    {
+        Ok(infer::InferOk { value: (), obligations }) => {
+            ocx.register_obligations(obligations);
+        }
+        Err(terr) => {
+            let guar = tcx.sess.delay_span_bug(
+                return_span,
+                format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+            );
+            return Err(guar);
+        }
+    }
+
     // Check that all obligations are satisfied by the implementation's
     // RPITs.
     let errors = ocx.select_all_or_error();
@@ -551,15 +571,40 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
                 let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
                 debug!(?id_substs, ?substs);
                 let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
-                    substs.iter().enumerate().map(|(index, arg)| (arg, id_substs[index])).collect();
+                    std::iter::zip(substs, id_substs).collect();
                 debug!(?map);
 
+                // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
+                // region substs that are synthesized during AST lowering. These are substs
+                // that are appended to the parent substs (trait and trait method). However,
+                // we're trying to infer the unsubstituted type value of the RPITIT inside
+                // the *impl*, so we can later use the impl's method substs to normalize
+                // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
+                //
+                // Due to the design of RPITITs, during AST lowering, we have no idea that
+                // an impl method corresponds to a trait method with RPITITs in it. Therefore,
+                // we don't have a list of early-bound region substs for the RPITIT in the impl.
+                // Since early region parameters are index-based, we can't just rebase these
+                // (trait method) early-bound region substs onto the impl, and there's no
+                // guarantee that the indices from the trait substs and impl substs line up.
+                // So to fix this, we subtract the number of trait substs and add the number of
+                // impl substs to *renumber* these early-bound regions to their corresponding
+                // indices in the impl's substitutions list.
+                //
+                // Also, we only need to account for a difference in trait and impl substs,
+                // since we previously enforce that the trait method and impl method have the
+                // same generics.
+                let num_trait_substs = trait_to_impl_substs.len();
+                let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
                 let ty = tcx.fold_regions(ty, |region, _| {
-                    if let ty::ReFree(_) = region.kind() {
-                        map[&region.into()].expect_region()
-                    } else {
-                        region
-                    }
+                    let ty::ReFree(_) = region.kind() else { return region; };
+                    let ty::ReEarlyBound(e) = map[&region.into()].expect_region().kind()
+                        else { bug!("expected ReFree to map to ReEarlyBound"); };
+                    tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+                        def_id: e.def_id,
+                        name: e.name,
+                        index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
+                    }))
                 });
                 debug!(%ty);
                 collected_tys.insert(def_id, ty);
@@ -619,10 +664,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
             });
             self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
             // Recurse into bounds
-            for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
-                let pred_span = pred.0.1;
-
-                let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs);
+            for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
                 let pred = pred.fold_with(self);
                 let pred = self.ocx.normalize(
                     ObligationCause::misc(self.span, self.body_id),
@@ -1707,15 +1749,10 @@ pub fn check_type_bounds<'tcx>(
 
     let obligations = tcx
         .bound_explicit_item_bounds(trait_ty.def_id)
-        .transpose_iter()
-        .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-        .map(|(bound, span)| {
-            debug!(?bound);
-            // this is where opaque type is found
-            let concrete_ty_bound = bound.subst(tcx, rebased_substs);
+        .subst_iter_copied(tcx, rebased_substs)
+        .map(|(concrete_ty_bound, span)| {
             debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-
-            traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
+            traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
         })
         .collect();
     debug!("check_type_bounds: item_bounds={:?}", obligations);
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index e5b212eb757..a74016e220e 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -184,13 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
             let p = p.kind();
             match (predicate.skip_binder(), p.skip_binder()) {
                 (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
-                    // Since struct predicates cannot have ~const, project the impl predicate
-                    // onto one that ignores the constness. This is equivalent to saying that
-                    // we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
-                    // in the impl.
-                    let non_const_a =
-                        ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
-                    relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
+                    relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
                 (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
                     relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
@@ -198,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
                 (
                     ty::PredicateKind::ConstEvaluatable(a),
                     ty::PredicateKind::ConstEvaluatable(b),
-                ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
+                ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
                 (
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 25228f424cd..a026f8033c8 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,117 +1,11 @@
-use hir::HirId;
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_index::vec::Idx;
-use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
 use rustc_session::lint;
 use rustc_span::{Symbol, DUMMY_SP};
-use rustc_target::abi::{Pointer, VariantIdx};
 use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
 
-use super::FnCtxt;
-
-/// If the type is `Option<T>`, it will return `T`, otherwise
-/// the type itself. Works on most `Option`-like types.
-fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    let ty::Adt(def, substs) = *ty.kind() else { return ty };
-
-    if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
-        let data_idx;
-
-        let one = VariantIdx::new(1);
-        let zero = VariantIdx::new(0);
-
-        if def.variant(zero).fields.is_empty() {
-            data_idx = one;
-        } else if def.variant(one).fields.is_empty() {
-            data_idx = zero;
-        } else {
-            return ty;
-        }
-
-        if def.variant(data_idx).fields.len() == 1 {
-            return def.variant(data_idx).fields[0].ty(tcx, substs);
-        }
-    }
-
-    ty
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
-        let tcx = self.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)
-        };
-        let from = normalize(from);
-        let to = normalize(to);
-        trace!(?from, ?to);
-
-        // Transmutes that are only changing lifetimes are always ok.
-        if from == to {
-            return;
-        }
-
-        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
-        let sk_from = skel(from);
-        let sk_to = skel(to);
-        trace!(?sk_from, ?sk_to);
-
-        // Check for same size using the skeletons.
-        if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
-            if sk_from.same_size(sk_to) {
-                return;
-            }
-
-            // Special-case transmuting from `typeof(function)` and
-            // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
-                struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
-                    .note(&format!("source type: {from}"))
-                    .note(&format!("target type: {to}"))
-                    .help("cast with `as` to a pointer instead")
-                    .emit();
-                return;
-            }
-        }
-
-        // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
-            Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
-            Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
-            Err(LayoutError::Unknown(bad)) => {
-                if bad == ty {
-                    "this type does not have a fixed size".to_owned()
-                } else {
-                    format!("size can vary because of {bad}")
-                }
-            }
-            Err(err) => err.to_string(),
-        };
-
-        let mut err = struct_span_err!(
-            tcx.sess,
-            span,
-            E0512,
-            "cannot transmute between types of different sizes, \
-                                        or dependently-sized types"
-        );
-        if from == to {
-            err.note(&format!("`{from}` does not have a fixed size"));
-        } else {
-            err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
-                .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
-        }
-        err.emit();
-    }
-}
-
 pub struct InlineAsmCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 331bd7e26c8..2e7b1025764 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -62,191 +62,45 @@ a type parameter).
 
 */
 
-pub mod _match;
-mod autoderef;
-mod callee;
-pub mod cast;
 mod check;
-mod closure;
-pub mod coercion;
 mod compare_method;
-pub mod demand;
-mod diverges;
 pub mod dropck;
-mod expectation;
-mod expr;
-mod fallback;
-mod fn_ctxt;
-mod gather_locals;
-mod generator_interior;
-mod inherited;
 pub mod intrinsic;
-mod intrinsicck;
-pub mod method;
-mod op;
-mod pat;
-mod place_op;
+pub mod intrinsicck;
 mod region;
-pub mod rvalue_scopes;
-mod upvar;
 pub mod wfcheck;
-pub mod writeback;
 
-use check::{check_abi, check_fn, check_mod_item_types};
-pub use diverges::Diverges;
-pub use expectation::Expectation;
-pub use fn_ctxt::*;
-pub use inherited::{Inherited, InheritedBuilder};
+pub use check::check_abi;
 
-use crate::astconv::AstConv;
-use crate::check::gather_locals::GatherLocalsVisitor;
+use check::check_mod_item_types;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
-};
+use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
 use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
-use rustc_session::config;
 use rustc_session::parse::feature_err;
-use rustc_session::Session;
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, BytePos, Span, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::cell::RefCell;
 use std::num::NonZeroU32;
 
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::coercion::DynamicCoerceMany;
 use self::compare_method::collect_trait_impl_trait_tys;
 use self::region::region_scope_tree;
-pub use self::Expectation::*;
-
-#[macro_export]
-macro_rules! type_error_struct {
-    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
-        let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
-
-        if $typ.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    })
-}
-
-/// The type of a local binding, including the revealed type for anon types.
-#[derive(Copy, Clone, Debug)]
-pub struct LocalTy<'tcx> {
-    decl_ty: Ty<'tcx>,
-    revealed_ty: Ty<'tcx>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Needs {
-    MutPlace,
-    None,
-}
-
-impl Needs {
-    fn maybe_mut_place(m: hir::Mutability) -> Self {
-        match m {
-            hir::Mutability::Mut => Needs::MutPlace,
-            hir::Mutability::Not => Needs::None,
-        }
-    }
-}
-
-#[derive(Copy, Clone)]
-pub struct UnsafetyState {
-    pub def: hir::HirId,
-    pub unsafety: hir::Unsafety,
-    from_fn: bool,
-}
-
-impl UnsafetyState {
-    pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
-        UnsafetyState { def, unsafety, from_fn: true }
-    }
-
-    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
-        use hir::BlockCheckMode;
-        match self.unsafety {
-            // If this unsafe, then if the outer function was already marked as
-            // unsafe we shouldn't attribute the unsafe'ness to the block. This
-            // way the block can be warned about instead of ignoring this
-            // extraneous block (functions are never warned about).
-            hir::Unsafety::Unsafe if self.from_fn => self,
-
-            unsafety => {
-                let (unsafety, def) = match blk.rules {
-                    BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
-                    BlockCheckMode::DefaultBlock => (unsafety, self.def),
-                };
-                UnsafetyState { def, unsafety, from_fn: false }
-            }
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum PlaceOp {
-    Deref,
-    Index,
-}
-
-pub struct BreakableCtxt<'tcx> {
-    may_break: bool,
-
-    // this is `null` for loops where break with a value is illegal,
-    // such as `while`, `for`, and `while let`
-    coerce: Option<DynamicCoerceMany<'tcx>>,
-}
-
-pub struct EnclosingBreakables<'tcx> {
-    stack: Vec<BreakableCtxt<'tcx>>,
-    by_id: HirIdMap<usize>,
-}
-
-impl<'tcx> EnclosingBreakables<'tcx> {
-    fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
-        self.opt_find_breakable(target_id).unwrap_or_else(|| {
-            bug!("could not find enclosing breakable with id {}", target_id);
-        })
-    }
-
-    fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
-        match self.by_id.get(&target_id) {
-            Some(ix) => Some(&mut self.stack[*ix]),
-            None => None,
-        }
-    }
-}
 
 pub fn provide(providers: &mut Providers) {
-    method::provide(providers);
     wfcheck::provide(providers);
     *providers = Providers {
-        typeck_item_bodies,
-        typeck_const_arg,
-        typeck,
-        diagnostic_only_typeck,
-        has_typeck_results,
         adt_destructor,
-        used_trait_imports,
         check_mod_item_types,
         region_scope_tree,
         collect_trait_impl_trait_tys,
@@ -259,259 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
     tcx.calculate_dtor(def_id, dropck::check_drop_impl)
 }
 
-/// If this `DefId` is a "primary tables entry", returns
-/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
-///
-/// If this function returns `Some`, then `typeck_results(def_id)` will
-/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
-/// may not succeed. In some cases where this function returns `None`
-/// (notably closures), `typeck_results(def_id)` would wind up
-/// redirecting to the owning function.
-fn primary_body_of(
-    tcx: TyCtxt<'_>,
-    id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
-    match tcx.hir().get(id) {
-        Node::Item(item) => match item.kind {
-            hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
-                Some((body, Some(ty), None))
-            }
-            hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
-            _ => None,
-        },
-        Node::TraitItem(item) => match item.kind {
-            hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
-            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                Some((body, None, Some(sig)))
-            }
-            _ => None,
-        },
-        Node::ImplItem(item) => match item.kind {
-            hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
-            hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
-            _ => None,
-        },
-        Node::AnonConst(constant) => Some((constant.body, None, None)),
-        _ => None,
-    }
-}
-
-fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    // Closures' typeck results come from their outermost function,
-    // as they are part of the same "inference environment".
-    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
-    if typeck_root_def_id != def_id {
-        return tcx.has_typeck_results(typeck_root_def_id);
-    }
-
-    if let Some(def_id) = def_id.as_local() {
-        let id = tcx.hir().local_def_id_to_hir_id(def_id);
-        primary_body_of(tcx, id).is_some()
-    } else {
-        false
-    }
-}
-
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
-    &*tcx.typeck(def_id).used_trait_imports
-}
-
-fn typeck_const_arg<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (did, param_did): (LocalDefId, DefId),
-) -> &ty::TypeckResults<'tcx> {
-    let fallback = move || tcx.type_of(param_did);
-    typeck_with_fallback(tcx, did, fallback)
-}
-
-fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
-    if let Some(param_did) = tcx.opt_const_param_of(def_id) {
-        tcx.typeck_const_arg((def_id, param_did))
-    } else {
-        let fallback = move || tcx.type_of(def_id.to_def_id());
-        typeck_with_fallback(tcx, def_id, fallback)
-    }
-}
-
-/// Used only to get `TypeckResults` for type inference during error recovery.
-/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
-fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
-    let fallback = move || {
-        let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
-        tcx.ty_error_with_message(span, "diagnostic only typeck table used")
-    };
-    typeck_with_fallback(tcx, def_id, fallback)
-}
-
-fn typeck_with_fallback<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-    fallback: impl Fn() -> Ty<'tcx> + 'tcx,
-) -> &'tcx ty::TypeckResults<'tcx> {
-    // Closures' typeck results come from their outermost function,
-    // as they are part of the same "inference environment".
-    let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
-    if typeck_root_def_id != def_id {
-        return tcx.typeck(typeck_root_def_id);
-    }
-
-    let id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let span = tcx.hir().span(id);
-
-    // Figure out what primary body this item has.
-    let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
-        span_bug!(span, "can't type-check body of {:?}", def_id);
-    });
-    let body = tcx.hir().body(body_id);
-
-    let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
-        let param_env = tcx.param_env(def_id);
-        let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
-            let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
-                let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
-            } else {
-                tcx.fn_sig(def_id)
-            };
-
-            check_abi(tcx, id, span, fn_sig.abi());
-
-            // Compute the function signature from point of view of inside the fn.
-            let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
-            let fn_sig = inh.normalize_associated_types_in(
-                body.value.span,
-                body_id.hir_id,
-                param_env,
-                fn_sig,
-            );
-            check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
-        } else {
-            let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-            let expected_type = body_ty
-                .and_then(|ty| match ty.kind {
-                    hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
-                    _ => None,
-                })
-                .unwrap_or_else(|| match tcx.hir().get(id) {
-                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
-                        Node::Expr(&hir::Expr {
-                            kind: hir::ExprKind::ConstBlock(ref anon_const),
-                            ..
-                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
-                            span,
-                        }),
-                        Node::Ty(&hir::Ty {
-                            kind: hir::TyKind::Typeof(ref anon_const), ..
-                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
-                            span,
-                        }),
-                        Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
-                        | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
-                            let operand_ty = asm
-                                .operands
-                                .iter()
-                                .filter_map(|(op, _op_sp)| match op {
-                                    hir::InlineAsmOperand::Const { anon_const }
-                                        if anon_const.hir_id == id =>
-                                    {
-                                        // Inline assembly constants must be integers.
-                                        Some(fcx.next_int_var())
-                                    }
-                                    hir::InlineAsmOperand::SymFn { anon_const }
-                                        if anon_const.hir_id == id =>
-                                    {
-                                        Some(fcx.next_ty_var(TypeVariableOrigin {
-                                            kind: TypeVariableOriginKind::MiscVariable,
-                                            span,
-                                        }))
-                                    }
-                                    _ => None,
-                                })
-                                .next();
-                            operand_ty.unwrap_or_else(fallback)
-                        }
-                        _ => fallback(),
-                    },
-                    _ => fallback(),
-                });
-
-            let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
-            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
-            // Gather locals in statics (because of block expressions).
-            GatherLocalsVisitor::new(&fcx).visit_body(body);
-
-            fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
-
-            fcx.write_ty(id, expected_type);
-
-            fcx
-        };
-
-        let fallback_has_occurred = fcx.type_inference_fallback();
-
-        // Even though coercion casts provide type hints, we check casts after fallback for
-        // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
-        fcx.check_casts();
-        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
-        // Closure and generator analysis may run after fallback
-        // because they don't constrain other type variables.
-        // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
-        let prev_constness = fcx.param_env.constness();
-        fcx.param_env = fcx.param_env.without_const();
-        fcx.closure_analyze(body);
-        fcx.param_env = fcx.param_env.with_constness(prev_constness);
-        assert!(fcx.deferred_call_resolutions.borrow().is_empty());
-        // Before the generator analysis, temporary scopes shall be marked to provide more
-        // precise information on types to be captured.
-        fcx.resolve_rvalue_scopes(def_id.to_def_id());
-        fcx.resolve_generator_interiors(def_id.to_def_id());
-
-        for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
-            let ty = fcx.normalize_ty(span, ty);
-            fcx.require_type_is_sized(ty, span, code);
-        }
-
-        fcx.select_all_obligations_or_error();
-
-        if !fcx.infcx.is_tainted_by_errors() {
-            fcx.check_transmutes();
-        }
-
-        fcx.check_asms();
-
-        fcx.infcx.skip_region_resolution();
-
-        fcx.resolve_type_vars_in_body(body)
-    });
-
-    // Consistency check our TypeckResults instance can hold all ItemLocalIds
-    // it will need to hold.
-    assert_eq!(typeck_results.hir_owner, id.owner);
-
-    typeck_results
-}
-
-/// When `check_fn` is invoked on a generator (i.e., a body that
-/// includes yield), it returns back some information about the yield
-/// points.
-struct GeneratorTypes<'tcx> {
-    /// Type of generator argument / values returned by `yield`.
-    resume_ty: Ty<'tcx>,
-
-    /// Type of value that is yielded.
-    yield_ty: Ty<'tcx>,
-
-    /// Types that are captured (see `GeneratorInterior` for more).
-    interior: Ty<'tcx>,
-
-    /// Indicates if the generator is movable or static (immovable).
-    movability: hir::Movability,
-}
-
 /// Given a `DefId` for an opaque type in return position, find its parent item's return
 /// expressions.
 fn get_owner_return_paths<'tcx>(
@@ -528,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
     })
 }
 
-// Forbid defining intrinsics in Rust code,
-// as they must always be defined by the compiler.
-fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
+/// Forbid defining intrinsics in Rust code,
+/// as they must always be defined by the compiler.
+// FIXME: Move this to a more appropriate place.
+pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
     if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
         tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
     }
@@ -824,6 +426,17 @@ fn fn_sig_suggestion<'tcx>(
     format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
 }
 
+pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+    Some(match ty.kind() {
+        ty::Bool => "true",
+        ty::Char => "'a'",
+        ty::Int(_) | ty::Uint(_) => "42",
+        ty::Float(_) => "3.14159",
+        ty::Error(_) | ty::Never => return None,
+        _ => "value",
+    })
+}
+
 /// Return placeholder code for the given associated item.
 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
 /// structured suggestion.
@@ -845,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
         ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
         ty::AssocKind::Const => {
             let ty = tcx.type_of(assoc.def_id);
-            let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
+            let val = ty_kind_suggestion(ty).unwrap_or("value");
             format!("const {}: {} = {};", assoc.name, ty, val)
         }
     }
@@ -896,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
     err.emit();
 }
 
-fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
-    struct_span_err!(
-        tcx.sess,
-        span,
-        E0533,
-        "expected unit struct, unit variant or constant, found {} `{}`",
-        res.descr(),
-        rustc_hir_pretty::qpath_to_string(qpath),
-    )
-    .emit();
-}
-
-/// Controls whether the arguments are tupled. This is used for the call
-/// operator.
-///
-/// Tupling means that all call-side arguments are packed into a tuple and
-/// passed as a single parameter. For example, if tupling is enabled, this
-/// function:
-/// ```
-/// fn f(x: (isize, isize)) {}
-/// ```
-/// Can be called as:
-/// ```ignore UNSOLVED (can this be done in user code?)
-/// # fn f(x: (isize, isize)) {}
-/// f(1, 2);
-/// ```
-/// Instead of:
-/// ```
-/// # fn f(x: (isize, isize)) {}
-/// f((1, 2));
-/// ```
-#[derive(Clone, Eq, PartialEq)]
-enum TupleArgumentsFlag {
-    DontTupleArguments,
-    TupleArguments,
-}
-
-fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
-    tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
-}
-
-fn fatally_break_rust(sess: &Session) {
-    let handler = sess.diagnostic();
-    handler.span_bug_no_panic(
-        MultiSpan::new(),
-        "It looks like you're trying to break rust; would you like some ICE?",
-    );
-    handler.note_without_error("the compiler expectedly panicked. this is a feature.");
-    handler.note_without_error(
-        "we would appreciate a joke overview: \
-         https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
-    );
-    handler.note_without_error(&format!(
-        "rustc {} running on {}",
-        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
-        config::host_triple(),
-    ));
-}
-
-fn potentially_plural_count(count: usize, word: &str) -> String {
+// FIXME: Consider moving this method to a more fitting place.
+pub fn potentially_plural_count(count: usize, word: &str) -> String {
     format!("{} {}{}", count, word, pluralize!(count))
 }
-
-fn has_expected_num_generic_args<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_did: Option<DefId>,
-    expected: usize,
-) -> bool {
-    trait_did.map_or(true, |trait_did| {
-        let generics = tcx.generics_of(trait_did);
-        generics.count() == expected + if generics.has_self { 1 } else { 0 }
-    })
-}
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b89db79bef8..ff32329e431 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -252,9 +252,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             ) => {
                 // For shortcircuiting operators, mark the RHS as a terminating
                 // scope since it only executes conditionally.
-                terminating(r.hir_id.local_id);
-            }
 
+                // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
+                // should live beyond the immediate expression
+                if !matches!(r.kind, hir::ExprKind::Let(_)) {
+                    terminating(r.hir_id.local_id);
+                }
+            }
             hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
                 terminating(then.hir_id.local_id);
                 terminating(otherwise.hir_id.local_id);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 0a8a1bec9b8..33ed3b96aa8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1101,8 +1101,6 @@ fn check_type_defn<'tcx, F>(
 
             // Explicit `enum` discriminant values must const-evaluate successfully.
             if let Some(discr_def_id) = variant.explicit_discr {
-                let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
-
                 let cause = traits::ObligationCause::new(
                     tcx.def_span(discr_def_id),
                     wfcx.body_id,
@@ -1112,10 +1110,7 @@ fn check_type_defn<'tcx, F>(
                     cause,
                     wfcx.param_env,
                     ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
-                        ty::UnevaluatedConst::new(
-                            ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
-                            discr_substs,
-                        ),
+                        ty::Const::from_anon_const(tcx, discr_def_id),
                     ))
                     .to_predicate(tcx),
                 ));
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index c634a57b0b5..130eb8005b0 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -148,12 +148,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
             // inherent impls without warning.
             SkipLeakCheck::Yes,
             overlap_mode,
-            |overlap| {
-                self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
-                false
-            },
-            || true,
-        );
+        )
+        .map_or(true, |overlap| {
+            self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
+            false
+        });
     }
 
     fn check_item(&mut self, id: hir::ItemId) {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 5c76016c662..66ca7d7aa08 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -100,13 +100,12 @@ pub fn provide(providers: &mut Providers) {
 /// It's also used for the bodies of items like structs where the body (the fields)
 /// are just signatures.
 ///
-/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// This is in contrast to `FnCtxt`, which is used to type-check bodies of
 /// functions, closures, and `const`s -- anywhere that expressions and statements show up.
 ///
 /// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
 /// while `FnCtxt` does do inference.
 ///
-/// [`FnCtxt`]: crate::check::FnCtxt
 /// [`InferCtxt`]: rustc_infer::infer::InferCtxt
 ///
 /// # Trait predicates
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index db8f8de68f2..2e84e1d0160 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -318,10 +318,10 @@ fn const_evaluatable_predicates_of<'tcx>(
         fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
             let def_id = self.tcx.hir().local_def_id(c.hir_id);
             let ct = ty::Const::from_anon_const(self.tcx, def_id);
-            if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
+            if let ty::ConstKind::Unevaluated(_) = ct.kind() {
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
-                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
                         .to_predicate(self.tcx),
                     span,
                 ));
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d891171b824..9457da32ce6 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,24 +1,13 @@
-//! Errors emitted by `hir_analysis`.
+//! Errors emitted by `rustc_hir_analysis`.
 
 use rustc_errors::IntoDiagnostic;
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
-use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")]
-pub struct FieldMultiplySpecifiedInInitializer {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(hir_analysis::previous_use_label)]
-    pub prev_span: Span,
-    pub ident: Ident,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")]
+#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
 pub struct UnrecognizedAtomicOperation<'a> {
     #[primary_span]
     #[label]
@@ -27,7 +16,7 @@ pub struct UnrecognizedAtomicOperation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
+#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
 pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
     #[primary_span]
     #[label]
@@ -38,7 +27,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::unrecognized_intrinsic_function, code = "E0093")]
+#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")]
 pub struct UnrecognizedIntrinsicFunction {
     #[primary_span]
     #[label]
@@ -47,19 +36,19 @@ pub struct UnrecognizedIntrinsicFunction {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
+#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
 pub struct LifetimesOrBoundsMismatchOnTrait {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(hir_analysis::generics_label)]
+    #[label(generics_label)]
     pub generics_span: Option<Span>,
     pub item_kind: &'static str,
     pub ident: Ident,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::drop_impl_on_wrong_item, code = "E0120")]
+#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
 pub struct DropImplOnWrongItem {
     #[primary_span]
     #[label]
@@ -67,18 +56,18 @@ pub struct DropImplOnWrongItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::field_already_declared, code = "E0124")]
+#[diag(hir_analysis_field_already_declared, code = "E0124")]
 pub struct FieldAlreadyDeclared {
     pub field_name: Ident,
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(hir_analysis::previous_decl_label)]
+    #[label(previous_decl_label)]
     pub prev_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::copy_impl_on_type_with_dtor, code = "E0184")]
+#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")]
 pub struct CopyImplOnTypeWithDtor {
     #[primary_span]
     #[label]
@@ -86,14 +75,14 @@ pub struct CopyImplOnTypeWithDtor {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::multiple_relaxed_default_bounds, code = "E0203")]
+#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
 pub struct MultipleRelaxedDefaultBounds {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::copy_impl_on_non_adt, code = "E0206")]
+#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")]
 pub struct CopyImplOnNonAdt {
     #[primary_span]
     #[label]
@@ -101,23 +90,23 @@ pub struct CopyImplOnNonAdt {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::trait_object_declared_with_no_traits, code = "E0224")]
+#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
-    #[label(hir_analysis::alias_span)]
+    #[label(alias_span)]
     pub trait_alias_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::ambiguous_lifetime_bound, code = "E0227")]
+#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")]
 pub struct AmbiguousLifetimeBound {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::assoc_type_binding_not_allowed, code = "E0229")]
+#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")]
 pub struct AssocTypeBindingNotAllowed {
     #[primary_span]
     #[label]
@@ -125,14 +114,7 @@ pub struct AssocTypeBindingNotAllowed {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")]
-pub struct FunctionalRecordUpdateOnNonStruct {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")]
+#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")]
 pub struct TypeofReservedKeywordUsed<'tcx> {
     pub ty: Ty<'tcx>,
     #[primary_span]
@@ -143,98 +125,19 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")]
-pub struct ReturnStmtOutsideOfFnBody {
-    #[primary_span]
-    pub span: Span,
-    #[label(hir_analysis::encl_body_label)]
-    pub encl_body_span: Option<Span>,
-    #[label(hir_analysis::encl_fn_label)]
-    pub encl_fn_span: Option<Span>,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")]
-pub struct YieldExprOutsideOfGenerator {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")]
-pub struct StructExprNonExhaustive {
-    #[primary_span]
-    pub span: Span,
-    pub what: &'static str,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")]
+#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")]
 pub struct ValueOfAssociatedStructAlreadySpecified {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(hir_analysis::previous_bound_label)]
+    #[label(previous_bound_label)]
     pub prev_span: Span,
     pub item_name: Ident,
     pub def_path: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")]
-pub struct AddressOfTemporaryTaken {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Subdiagnostic)]
-pub enum AddReturnTypeSuggestion {
-    #[suggestion(
-        hir_analysis::add_return_type_add,
-        code = "-> {found} ",
-        applicability = "machine-applicable"
-    )]
-    Add {
-        #[primary_span]
-        span: Span,
-        found: String,
-    },
-    #[suggestion(
-        hir_analysis::add_return_type_missing_here,
-        code = "-> _ ",
-        applicability = "has-placeholders"
-    )]
-    MissingHere {
-        #[primary_span]
-        span: Span,
-    },
-}
-
-#[derive(Subdiagnostic)]
-pub enum ExpectedReturnTypeLabel<'tcx> {
-    #[label(hir_analysis::expected_default_return_type)]
-    Unit {
-        #[primary_span]
-        span: Span,
-    },
-    #[label(hir_analysis::expected_return_type)]
-    Other {
-        #[primary_span]
-        span: Span,
-        expected: Ty<'tcx>,
-    },
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis::unconstrained_opaque_type)]
+#[diag(hir_analysis_unconstrained_opaque_type)]
 #[note]
 pub struct UnconstrainedOpaqueType {
     #[primary_span]
@@ -255,7 +158,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut err = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::hir_analysis::missing_type_params,
+            rustc_errors::fluent::hir_analysis_missing_type_params,
             error_code!(E0393),
         );
         err.set_arg("parameterCount", self.missing_type_params.len());
@@ -268,7 +171,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 .join(", "),
         );
 
-        err.span_label(self.def_span, rustc_errors::fluent::hir_analysis::label);
+        err.span_label(self.def_span, rustc_errors::fluent::label);
 
         let mut suggested = false;
         // Don't suggest setting the type params if there are some already: the order is
@@ -283,7 +186,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 // least we can clue them to the correct syntax `Iterator<Type>`.
                 err.span_suggestion(
                     self.span,
-                    rustc_errors::fluent::hir_analysis::suggestion,
+                    rustc_errors::fluent::suggestion,
                     format!(
                         "{}<{}>",
                         snippet,
@@ -299,16 +202,16 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
             }
         }
         if !suggested {
-            err.span_label(self.span, rustc_errors::fluent::hir_analysis::no_suggestion_label);
+            err.span_label(self.span, rustc_errors::fluent::no_suggestion_label);
         }
 
-        err.note(rustc_errors::fluent::hir_analysis::note);
+        err.note(rustc_errors::fluent::note);
         err
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::manual_implementation, code = "E0183")]
+#[diag(hir_analysis_manual_implementation, code = "E0183")]
 #[help]
 pub struct ManualImplementation {
     #[primary_span]
@@ -318,21 +221,21 @@ pub struct ManualImplementation {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::substs_on_overridden_impl)]
+#[diag(hir_analysis_substs_on_overridden_impl)]
 pub struct SubstsOnOverriddenImpl {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(hir_analysis::unused_extern_crate)]
+#[diag(hir_analysis_unused_extern_crate)]
 pub struct UnusedExternCrate {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(hir_analysis::extern_crate_not_idiomatic)]
+#[diag(hir_analysis_extern_crate_not_idiomatic)]
 pub struct ExternCrateNotIdiomatic {
     #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
     pub span: Span,
@@ -341,7 +244,7 @@ pub struct ExternCrateNotIdiomatic {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis::expected_used_symbol)]
+#[diag(hir_analysis_expected_used_symbol)]
 pub struct ExpectedUsedSymbol {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index b7d9fc8a2fe..dba505149de 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -82,20 +82,19 @@ extern crate rustc_middle;
 
 // These are used by Clippy.
 pub mod check;
-pub mod expr_use_visitor;
 
-mod astconv;
+pub mod astconv;
 mod bounds;
 mod check_unused;
 mod coherence;
-mod collect;
+// FIXME: This module shouldn't be public.
+pub mod collect;
 mod constrained_generic_params;
 mod errors;
 pub mod hir_wf_check;
 mod impl_wf_check;
-mod mem_categorization;
 mod outlives;
-mod structured_errors;
+pub mod structured_errors;
 mod variance;
 
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 729139adc2d..da27554a229 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1687,7 +1687,11 @@ impl<'a> State<'a> {
 
             let mut nonelided_generic_args: bool = false;
             let elide_lifetimes = generic_args.args.iter().all(|arg| match arg {
-                GenericArg::Lifetime(lt) => lt.is_elided(),
+                GenericArg::Lifetime(lt) if lt.is_elided() => true,
+                GenericArg::Lifetime(_) => {
+                    nonelided_generic_args = true;
+                    false
+                }
                 _ => {
                     nonelided_generic_args = true;
                     true
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
new file mode 100644
index 00000000000..093f9bb8448
--- /dev/null
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_hir_typeck"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_index = { path = "../rustc_index" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_pretty = { path = "../rustc_hir_pretty" }
+rustc_lint = { path = "../rustc_lint" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_hir_analysis/src/check/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 143508b785f..2b15d4dcd08 100644
--- a/compiler/rustc_hir_analysis/src/check/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,5 +1,5 @@
-use crate::check::coercion::{AsCoercionSite, CoerceMany};
-use crate::check::{Diverges, Expectation, FnCtxt, Needs};
+use crate::coercion::{AsCoercionSite, CoerceMany};
+use crate::{Diverges, Expectation, FnCtxt, Needs};
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -514,8 +514,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 for ty in [first_ty, second_ty] {
-                    for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() {
-                        let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs);
+                    for (pred, _) in self
+                        .tcx
+                        .bound_explicit_item_bounds(rpit_def_id)
+                        .subst_iter_copied(self.tcx, substs)
+                    {
                         let pred = match pred.kind().skip_binder() {
                             ty::PredicateKind::Trait(mut trait_pred) => {
                                 assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
diff --git a/compiler/rustc_hir_analysis/src/check/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 59c366ad7d7..59c366ad7d7 100644
--- a/compiler/rustc_hir_analysis/src/check/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
diff --git a/compiler/rustc_hir_analysis/src/check/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index f0a7c910906..1b33f2f02b8 100644
--- a/compiler/rustc_hir_analysis/src/check/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,8 +1,8 @@
 use super::method::probe::{IsSuggestion, Mode, ProbeScope};
 use super::method::MethodCallee;
-use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
-use crate::type_error_struct;
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
 
+use crate::type_error_struct;
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
 use rustc_hir as hir;
@@ -27,6 +27,7 @@ use rustc_span::Span;
 use rustc_target::spec::abi;
 use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 use std::iter;
diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 51abdd2e059..0e7576ecf8b 100644
--- a/compiler/rustc_hir_analysis/src/check/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -30,9 +30,7 @@
 
 use super::FnCtxt;
 
-use crate::hir::def_id::DefId;
 use crate::type_error_struct;
-use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_middle::mir::Mutability;
@@ -43,6 +41,7 @@ use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
 use rustc_session::lint;
 use rustc_session::Session;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -527,7 +526,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
-                use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
+                use rustc_hir_analysis::structured_errors::{
+                    SizedUnsizedCast, StructuredDiagnostic,
+                };
 
                 SizedUnsizedCast {
                     sess: &fcx.tcx.sess,
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
new file mode 100644
index 00000000000..7f76364e15a
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -0,0 +1,324 @@
+use crate::coercion::CoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use crate::{FnCtxt, Inherited};
+use crate::{GeneratorTypes, UnsafetyState};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
+use rustc_hir_analysis::check::fn_maybe_err;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::RegionVariableOrigin;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
+use std::cell::RefCell;
+
+/// Helper used for fns and closures. Does the grungy work of checking a function
+/// body and returns the function context used for that purpose, since in the case of a fn item
+/// there is still a bit more to do.
+///
+/// * ...
+/// * inherited: other fields inherited from the enclosing fn (if any)
+#[instrument(skip(inherited, body), level = "debug")]
+pub(super) fn check_fn<'a, 'tcx>(
+    inherited: &'a Inherited<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    fn_sig: ty::FnSig<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    fn_id: hir::HirId,
+    body: &'tcx hir::Body<'tcx>,
+    can_be_generator: Option<hir::Movability>,
+    return_type_pre_known: bool,
+) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
+    // Create the function context. This is either derived from scratch or,
+    // in the case of closures, based on the outer context.
+    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
+    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
+    fcx.return_type_pre_known = return_type_pre_known;
+
+    let tcx = fcx.tcx;
+    let hir = tcx.hir();
+
+    let declared_ret_ty = fn_sig.output();
+
+    let ret_ty =
+        fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
+            declared_ret_ty,
+            body.value.hir_id,
+            decl.output.span(),
+            param_env,
+        ));
+    // If we replaced declared_ret_ty with infer vars, then we must be inferring
+    // an opaque type, so set a flag so we can improve diagnostics.
+    fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
+
+    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
+
+    let span = body.value.span;
+
+    fn_maybe_err(tcx, span, fn_sig.abi);
+
+    if fn_sig.abi == Abi::RustCall {
+        let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
+
+        let err = || {
+            let item = match tcx.hir().get(fn_id) {
+                Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
+                Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(header, ..), ..
+                }) => Some(header),
+                Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(header, ..),
+                    ..
+                }) => Some(header),
+                // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
+                node => bug!("Item being checked wasn't a function/closure: {:?}", node),
+            };
+
+            if let Some(header) = item {
+                tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
+            }
+        };
+
+        if fn_sig.inputs().len() != expected_args {
+            err()
+        } else {
+            // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
+            //   This will probably require wide-scale changes to support a TupleKind obligation
+            //   We can't resolve this without knowing the type of the param
+            if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
+                err()
+            }
+        }
+    }
+
+    if body.generator_kind.is_some() && can_be_generator.is_some() {
+        let yield_ty = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+
+        // Resume type defaults to `()` if the generator has no argument.
+        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+
+        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
+    }
+
+    GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+    // (as it's created inside the body itself, not passed in from outside).
+    let maybe_va_list = if fn_sig.c_variadic {
+        let span = body.params.last().unwrap().span;
+        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
+
+        Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
+    } else {
+        None
+    };
+
+    // Add formal parameters.
+    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+    let inputs_fn = fn_sig.inputs().iter().copied();
+    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+        // Check the pattern.
+        let ty_span = try { inputs_hir?.get(idx)?.span };
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+
+        // Check that argument is Sized.
+        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
+        // for simple cases like `fn foo(x: Trait)`,
+        // where we would error once on the parameter as a whole, and once on the binding `x`.
+        if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
+            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+        }
+
+        fcx.write_ty(param.hir_id, param_ty);
+    }
+
+    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+
+    fcx.in_tail_expr = true;
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // FIXME: We need to verify that the return type is `Sized` after the return expression has
+        // been evaluated so that we have types available for all the nodes being returned, but that
+        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
+        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
+        // while keeping the current ordering we will ignore the tail expression's type because we
+        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
+        // because we will trigger "unreachable expression" lints unconditionally.
+        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
+        // case that a newcomer might make, returning a bare trait, and in that case we populate
+        // the tail expression's type so that the suggestion will be correct, but ignore all other
+        // possible cases.
+        fcx.check_expr(&body.value);
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+    } else {
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        fcx.check_return_expr(&body.value, false);
+    }
+    fcx.in_tail_expr = false;
+
+    // We insert the deferred_generator_interiors entry after visiting the body.
+    // This ensures that all nested generators appear before the entry of this generator.
+    // resolve_generator_interiors relies on this property.
+    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
+        let interior = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
+        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+
+        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
+        Some(GeneratorTypes {
+            resume_ty,
+            yield_ty,
+            interior,
+            movability: can_be_generator.unwrap(),
+        })
+    } else {
+        None
+    };
+
+    // Finalize the return check by taking the LUB of the return types
+    // we saw and assigning it to the expected return type. This isn't
+    // really expected to fail, since the coercions would have failed
+    // earlier when trying to find a LUB.
+    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
+    let mut actual_return_ty = coercion.complete(&fcx);
+    debug!("actual_return_ty = {:?}", actual_return_ty);
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // We have special-cased the case where the function is declared
+        // `-> dyn Foo` and we don't actually relate it to the
+        // `fcx.ret_coercion`, so just substitute a type variable.
+        actual_return_ty =
+            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
+        debug!("actual_return_ty replaced with {:?}", actual_return_ty);
+    }
+
+    // HACK(oli-obk, compiler-errors): We should be comparing this against
+    // `declared_ret_ty`, but then anything uninferred would be inferred to
+    // the opaque type itself. That again would cause writeback to assume
+    // we have a recursive call site and do the sadly stabilized fallback to `()`.
+    fcx.demand_suptype(span, ret_ty, actual_return_ty);
+
+    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
+    if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
+        && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
+    {
+        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
+    }
+
+    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+    if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
+        && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
+    {
+        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
+    }
+
+    (fcx, gen_ty)
+}
+
+fn check_panic_info_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+        tcx.sess.err("language item required, but not found: `panic_info`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+        return;
+    }
+
+    let arg_is_panic_info = match *inputs[0].kind() {
+        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+            ty::Adt(ref adt, _) => {
+                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+            }
+            _ => false,
+        },
+        _ => false,
+    };
+
+    if !arg_is_panic_info {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no const parameters");
+    }
+}
+
+fn check_alloc_error_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+        tcx.sess.err("language item required, but not found: `alloc_layout`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+        return;
+    }
+
+    let arg_is_alloc_layout = match inputs[0].kind() {
+        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+        _ => false,
+    };
+
+    if !arg_is_alloc_layout {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess
+            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 84ea06a460b..a5a45f75e0e 100644
--- a/compiler/rustc_hir_analysis/src/check/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -2,11 +2,11 @@
 
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
-use crate::astconv::AstConv;
 use hir::def::DefKind;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::infer::{InferOk, InferResult};
@@ -176,24 +176,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match *expected_ty.kind() {
             ty::Opaque(def_id, substs) => {
                 let bounds = self.tcx.bound_explicit_item_bounds(def_id);
-                let sig = bounds
-                    .transpose_iter()
-                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                    .find_map(|(pred, span)| match pred.0.kind().skip_binder() {
+                let sig =
+                    bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
+                        .kind()
+                        .skip_binder()
+                    {
                         ty::PredicateKind::Projection(proj_predicate) => self
                             .deduce_sig_from_projection(
-                                Some(span.0),
-                                pred.0
-                                    .kind()
-                                    .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)),
+                                Some(span),
+                                pred.kind().rebind(proj_predicate),
                             ),
                         _ => None,
                     });
 
                 let kind = bounds
-                    .transpose_iter()
-                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                    .filter_map(|(pred, _)| match pred.0.kind().skip_binder() {
+                    .0
+                    .iter()
+                    .filter_map(|(pred, _)| match pred.kind().skip_binder() {
                         ty::PredicateKind::Trait(tp) => {
                             self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
                         }
@@ -697,18 +696,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::Opaque(def_id, substs) => self
                 .tcx
                 .bound_explicit_item_bounds(def_id)
-                .transpose_iter()
-                .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
+                .subst_iter_copied(self.tcx, substs)
+                .find_map(|(p, s)| get_future_output(p, s))?,
             ty::Error(_) => return None,
             ty::Projection(proj)
                 if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
             {
                 self.tcx
                     .bound_explicit_item_bounds(proj.item_def_id)
-                    .transpose_iter()
-                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
-                    .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+                    .subst_iter_copied(self.tcx, proj.substs)
+                    .find_map(|(p, s)| get_future_output(p, s))?
             }
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index faa6c6d9356..86597a703e8 100644
--- a/compiler/rustc_hir_analysis/src/check/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -35,8 +35,7 @@
 //! // and are then unable to coerce `&7i32` to `&mut i32`.
 //! ```
 
-use crate::astconv::AstConv;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
@@ -44,6 +43,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Expr;
+use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
 use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index a5222c92331..2974ac97f23 100644
--- a/compiler/rustc_hir_analysis/src/check/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,21 +1,20 @@
-use crate::check::FnCtxt;
-use rustc_infer::infer::InferOk;
-use rustc_middle::middle::stability::EvalResult;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::ObligationCause;
-
+use crate::FnCtxt;
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
+use rustc_infer::infer::InferOk;
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCause;
 
 use super::method::probe;
 
diff --git a/compiler/rustc_hir_analysis/src/check/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs
index 963a93a95c2..963a93a95c2 100644
--- a/compiler/rustc_hir_analysis/src/check/diverges.rs
+++ b/compiler/rustc_hir_typeck/src/diverges.rs
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
new file mode 100644
index 00000000000..175037f9b3a
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -0,0 +1,126 @@
+//! Errors emitted by `rustc_hir_analysis`.
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_middle::ty::Ty;
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_field_multiply_specified_in_initializer, code = "E0062")]
+pub struct FieldMultiplySpecifiedInInitializer {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(previous_use_label)]
+    pub prev_span: Span,
+    pub ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_return_stmt_outside_of_fn_body, code = "E0572")]
+pub struct ReturnStmtOutsideOfFnBody {
+    #[primary_span]
+    pub span: Span,
+    #[label(encl_body_label)]
+    pub encl_body_span: Option<Span>,
+    #[label(encl_fn_label)]
+    pub encl_fn_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_yield_expr_outside_of_generator, code = "E0627")]
+pub struct YieldExprOutsideOfGenerator {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_struct_expr_non_exhaustive, code = "E0639")]
+pub struct StructExprNonExhaustive {
+    #[primary_span]
+    pub span: Span,
+    pub what: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_method_call_on_unknown_type, code = "E0699")]
+pub struct MethodCallOnUnknownType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_functional_record_update_on_non_struct, code = "E0436")]
+pub struct FunctionalRecordUpdateOnNonStruct {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_address_of_temporary_taken, code = "E0745")]
+pub struct AddressOfTemporaryTaken {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum AddReturnTypeSuggestion {
+    #[suggestion(
+        hir_analysis_add_return_type_add,
+        code = "-> {found} ",
+        applicability = "machine-applicable"
+    )]
+    Add {
+        #[primary_span]
+        span: Span,
+        found: String,
+    },
+    #[suggestion(
+        hir_analysis_add_return_type_missing_here,
+        code = "-> _ ",
+        applicability = "has-placeholders"
+    )]
+    MissingHere {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub enum ExpectedReturnTypeLabel<'tcx> {
+    #[label(hir_analysis_expected_default_return_type)]
+    Unit {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(hir_analysis_expected_return_type)]
+    Other {
+        #[primary_span]
+        span: Span,
+        expected: Ty<'tcx>,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_parentheses_in_range, code = "E0689")]
+pub struct MissingParentheseInRange {
+    #[primary_span]
+    #[label(hir_analysis_missing_parentheses_in_range)]
+    pub span: Span,
+    pub ty_str: String,
+    pub method_name: String,
+    #[subdiagnostic]
+    pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion_verbose(
+    hir_analysis_add_missing_parentheses_in_range,
+    applicability = "maybe-incorrect"
+)]
+pub struct AddMissingParenthesesInRange {
+    pub func_name: String,
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/check/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index e9e81034477..e9e81034477 100644
--- a/compiler/rustc_hir_analysis/src/check/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 71c6da862c9..41b00fda03e 100644
--- a/compiler/rustc_hir_analysis/src/check/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2,23 +2,22 @@
 //!
 //! See `mod.rs` for more context on type checking in general.
 
-use crate::astconv::AstConv as _;
-use crate::check::cast;
-use crate::check::coercion::CoerceMany;
-use crate::check::fatally_break_rust;
-use crate::check::method::SelfSource;
-use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
-use crate::check::{
-    report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
-    TupleArgumentsFlag::DontTupleArguments,
-};
+use crate::cast;
+use crate::coercion::CoerceMany;
+use crate::coercion::DynamicCoerceMany;
+use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use crate::errors::{
     FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
     YieldExprOutsideOfGenerator,
 };
+use crate::fatally_break_rust;
+use crate::method::SelfSource;
 use crate::type_error_struct;
-
-use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
+use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
+use crate::{
+    report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
+    TupleArgumentsFlag::DontTupleArguments,
+};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -32,6 +31,8 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Closure, ExprKind, HirId, QPath};
+use rustc_hir_analysis::astconv::AstConv as _;
+use rustc_hir_analysis::check::ty_kind_suggestion;
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -1130,11 +1131,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
-        self.check_lhs_assignable(lhs, "E0070", span, |err| {
-            let rhs_ty = self.check_expr(&rhs);
-            suggest_deref_binop(err, rhs_ty);
-        });
-
         // This is (basically) inlined `check_expr_coercable_to_type`, but we want
         // to suggest an additional fixup here in `suggest_deref_binop`.
         let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
@@ -1145,6 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             diag.emit();
         }
 
+        self.check_lhs_assignable(lhs, "E0070", span, |err| {
+            if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) {
+                suggest_deref_binop(err, rhs_ty);
+            }
+        });
+
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
         if lhs_ty.references_error() || rhs_ty.references_error() {
@@ -1361,7 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Create a new function context.
         let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
-        crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+        crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
 
         let ty = fcx.check_expr_with_expectation(&body.value, expected);
         fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
@@ -2884,14 +2886,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 }
-
-pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
-    Some(match ty.kind() {
-        ty::Bool => "true",
-        ty::Char => "'a'",
-        ty::Int(_) | ty::Uint(_) => "42",
-        ty::Float(_) => "3.14159",
-        ty::Error(_) | ty::Never => return None,
-        _ => "value",
-    })
-}
diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 039c653e5bc..fce2a5888ba 100644
--- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -89,15 +89,6 @@ enum ConsumeMode {
     Move,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum MutateMode {
-    Init,
-    /// Example: `x = y`
-    JustWrite,
-    /// Example: `x += y`
-    WriteAndRead,
-}
-
 /// The ExprUseVisitor type
 ///
 /// This is the code that actually walks the tree.
diff --git a/compiler/rustc_hir_analysis/src/check/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 474d5651bbe..747ecb036b2 100644
--- a/compiler/rustc_hir_analysis/src/check/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,4 +1,4 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use rustc_data_structures::{
     fx::{FxHashMap, FxHashSet},
     graph::WithSuccessors,
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index d140c3a0989..6a1cffe3e60 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,12 +1,7 @@
-use crate::astconv::{
-    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
-    GenericArgCountResult, IsMethodCall, PathSeg,
-};
-use crate::check::callee::{self, DeferredCallResolution};
-use crate::check::method::{self, MethodCallee, SelfSource};
-use crate::check::rvalue_scopes;
-use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
-
+use crate::callee::{self, DeferredCallResolution};
+use crate::method::{self, MethodCallee, SelfSource};
+use crate::rvalue_scopes;
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@@ -15,6 +10,10 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::astconv::{
+    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+    GenericArgCountResult, IsMethodCall, PathSeg,
+};
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::{InferOk, InferResult};
@@ -603,9 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
         for (body_id, interior, kind) in generators.drain(..) {
             self.select_obligations_where_possible(false, |_| {});
-            crate::check::generator_interior::resolve_interior(
-                self, def_id, body_id, interior, kind,
-            );
+            crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index fc83994caf5..fc83994caf5 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 285db90a9df..08a3cbccfb0 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,19 +1,13 @@
-use crate::astconv::AstConv;
-use crate::check::coercion::CoerceMany;
-use crate::check::fn_ctxt::arg_matrix::{
-    ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
+use crate::coercion::CoerceMany;
+use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
+use crate::gather_locals::Declaration;
+use crate::method::MethodCallee;
+use crate::Expectation::*;
+use crate::TupleArgumentsFlag::*;
+use crate::{
+    struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
+    TupleArgumentsFlag,
 };
-use crate::check::gather_locals::Declaration;
-use crate::check::intrinsicck::InlineAsmCtxt;
-use crate::check::method::MethodCallee;
-use crate::check::Expectation::*;
-use crate::check::TupleArgumentsFlag::*;
-use crate::check::{
-    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
-    LocalTy, Needs, TupleArgumentsFlag,
-};
-use crate::structured_errors::StructuredDiagnostic;
-
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
@@ -21,6 +15,10 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{ExprKind, Node, QPath};
+use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
+use rustc_hir_analysis::check::potentially_plural_count;
+use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -391,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ty: Ty<'tcx>,
                     cast_ty: &str,
                 ) {
-                    use crate::structured_errors::MissingCastForVariadicArg;
+                    use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
 
                     MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
                 }
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 51f4cb7e0eb..0c600daf445 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -6,12 +6,11 @@ mod suggestions;
 pub use _impl::*;
 pub use suggestions::*;
 
-use crate::astconv::AstConv;
-use crate::check::coercion::DynamicCoerceMany;
-use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
-
+use crate::coercion::DynamicCoerceMany;
+use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer;
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -36,7 +35,7 @@ use std::ops::Deref;
 ///
 /// See [`ItemCtxt`]'s docs for more.
 ///
-/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
 /// [`InferCtxt`]: infer::InferCtxt
 pub struct FnCtxt<'a, 'tcx> {
     pub(super) body_id: hir::HirId,
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 7a40def177a..cd2e41aff0f 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,8 +1,6 @@
 use super::FnCtxt;
-use crate::astconv::AstConv;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 
-use hir::def_id::DefId;
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
@@ -11,6 +9,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
+use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
@@ -19,6 +18,7 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -90,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if ty.is_suggestable(self.tcx, false) {
                                 format!("/* {ty} */")
                             } else {
-                                "".to_string()
+                                "/* value */".to_string()
                             }
                         })
                         .collect::<Vec<_>>()
@@ -102,10 +102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let msg = match def_id_or_name {
                 DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
-                    DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
-                    DefKind::Ctor(CtorOf::Variant, _) => {
-                        "instantiate this tuple variant".to_string()
-                    }
+                    DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
+                    DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
                     kind => format!("call this {}", kind.descr(def_id)),
                 },
                 DefIdOrName::Name(name) => format!("call this {name}"),
@@ -1209,8 +1207,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 }
-
-pub enum DefIdOrName {
-    DefId(DefId),
-    Name(&'static str),
-}
diff --git a/compiler/rustc_hir_analysis/src/check/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 8f34a970f6f..9a096f24fac 100644
--- a/compiler/rustc_hir_analysis/src/check/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -1,9 +1,10 @@
-use crate::check::{FnCtxt, LocalTy, UserType};
+use crate::{FnCtxt, LocalTy};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::PatKind;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::Ty;
+use rustc_middle::ty::UserType;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 122ad7009cb..122ad7009cb 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e1c..139d17d2e1c 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
index c0a0bfe8e1c..c0a0bfe8e1c 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index 518cd734236..4f3bdfbe758 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -14,7 +14,7 @@
 
 use self::cfg_build::build_control_flow_graph;
 use self::record_consumed_borrow::find_consumed_and_borrowed;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use hir::def_id::DefId;
 use hir::{Body, HirId, HirIdMap, Node};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index 2f68b57a019..bfe95852aa7 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -1,13 +1,16 @@
 use super::TrackedValue;
 use crate::{
-    check::FnCtxt,
     expr_use_visitor::{self, ExprUseVisitor},
+    FnCtxt,
 };
 use hir::{def_id::DefId, Body, HirId, HirIdMap};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
 use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::{
+    hir::place::{PlaceBase, Projection, ProjectionKind},
+    ty::TypeVisitable,
+};
 
 pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -198,11 +201,13 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
 
         // If the type being assigned needs dropped, then the mutation counts as a borrow
         // since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
-        //
-        // FIXME(drop-tracking): We need to be more responsible about inference
-        // variables here, since `needs_drop` is a "raw" type query, i.e. it
-        // basically requires types to have been fully resolved.
-        if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
+        let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
+        if ty.needs_infer() {
+            self.tcx.sess.delay_span_bug(
+                self.tcx.hir().span(assignee_place.hir_id),
+                &format!("inference variables in {ty}"),
+            );
+        } else if ty.needs_drop(self.tcx, self.param_env) {
             self.places
                 .borrowed
                 .insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 898419b5b23..b7dd599cd43 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -377,15 +377,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
 
         let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
-        let may_need_drop = |ty: Ty<'tcx>| {
-            // Avoid ICEs in needs_drop.
-            let ty = self.fcx.resolve_vars_if_possible(ty);
-            let ty = self.fcx.tcx.erase_regions(ty);
-            if ty.needs_infer() {
-                return true;
-            }
-            ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
-        };
 
         // Typically, the value produced by an expression is consumed by its parent in some way,
         // so we only have to check if the parent contains a yield (note that the parent may, for
@@ -403,9 +394,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // src/test/ui/generator/drop-tracking-parent-expression.rs.
         let scope = if self.drop_ranges.is_borrowed_temporary(expr)
             || ty.map_or(true, |ty| {
-                let needs_drop = may_need_drop(ty);
-                debug!(?needs_drop, ?ty);
-                needs_drop
+                // Avoid ICEs in needs_drop.
+                let ty = self.fcx.resolve_vars_if_possible(ty);
+                let ty = self.fcx.tcx.erase_regions(ty);
+                if ty.needs_infer() {
+                    self.fcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(expr.span, &format!("inference variables in {ty}"));
+                    true
+                } else {
+                    ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
+                }
             }) {
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
         } else {
diff --git a/compiler/rustc_hir_analysis/src/check/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 0fb7651b3a1..0fb7651b3a1 100644
--- a/compiler/rustc_hir_analysis/src/check/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
new file mode 100644
index 00000000000..9812d96fcc3
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -0,0 +1,108 @@
+use hir::HirId;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_index::vec::Idx;
+use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::{Pointer, VariantIdx};
+
+use super::FnCtxt;
+
+/// If the type is `Option<T>`, it will return `T`, otherwise
+/// the type itself. Works on most `Option`-like types.
+fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+    let ty::Adt(def, substs) = *ty.kind() else { return ty };
+
+    if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
+        let data_idx;
+
+        let one = VariantIdx::new(1);
+        let zero = VariantIdx::new(0);
+
+        if def.variant(zero).fields.is_empty() {
+            data_idx = one;
+        } else if def.variant(one).fields.is_empty() {
+            data_idx = zero;
+        } else {
+            return ty;
+        }
+
+        if def.variant(data_idx).fields.len() == 1 {
+            return def.variant(data_idx).fields[0].ty(tcx, substs);
+        }
+    }
+
+    ty
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
+        let tcx = self.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)
+        };
+        let from = normalize(from);
+        let to = normalize(to);
+        trace!(?from, ?to);
+
+        // Transmutes that are only changing lifetimes are always ok.
+        if from == to {
+            return;
+        }
+
+        let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
+        let sk_from = skel(from);
+        let sk_to = skel(to);
+        trace!(?sk_from, ?sk_to);
+
+        // Check for same size using the skeletons.
+        if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
+            if sk_from.same_size(sk_to) {
+                return;
+            }
+
+            // Special-case transmuting from `typeof(function)` and
+            // `Option<typeof(function)>` to present a clearer error.
+            let from = unpack_option_like(tcx, from);
+            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
+                struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
+                    .note(&format!("source type: {from}"))
+                    .note(&format!("target type: {to}"))
+                    .help("cast with `as` to a pointer instead")
+                    .emit();
+                return;
+            }
+        }
+
+        // Try to display a sensible error with as much information as possible.
+        let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
+            Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
+            Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+            Err(LayoutError::Unknown(bad)) => {
+                if bad == ty {
+                    "this type does not have a fixed size".to_owned()
+                } else {
+                    format!("size can vary because of {bad}")
+                }
+            }
+            Err(err) => err.to_string(),
+        };
+
+        let mut err = struct_span_err!(
+            tcx.sess,
+            span,
+            E0512,
+            "cannot transmute between types of different sizes, \
+                                        or dependently-sized types"
+        );
+        if from == to {
+            err.note(&format!("`{from}` does not have a fixed size"));
+        } else {
+            err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
+                .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+        }
+        err.emit();
+    }
+}
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
new file mode 100644
index 00000000000..e862d577573
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -0,0 +1,507 @@
+#![feature(if_let_guard)]
+#![feature(let_chains)]
+#![feature(try_blocks)]
+#![feature(never_type)]
+#![feature(min_specialization)]
+#![feature(control_flow_enum)]
+#![feature(drain_filter)]
+#![allow(rustc::potential_query_instability)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+
+#[macro_use]
+extern crate rustc_middle;
+
+mod _match;
+mod autoderef;
+mod callee;
+// Used by clippy;
+pub mod cast;
+mod check;
+mod closure;
+mod coercion;
+mod demand;
+mod diverges;
+mod errors;
+mod expectation;
+mod expr;
+// Used by clippy;
+pub mod expr_use_visitor;
+mod fallback;
+mod fn_ctxt;
+mod gather_locals;
+mod generator_interior;
+mod inherited;
+mod intrinsicck;
+mod mem_categorization;
+mod method;
+mod op;
+mod pat;
+mod place_op;
+mod rvalue_scopes;
+mod upvar;
+mod writeback;
+
+pub use diverges::Diverges;
+pub use expectation::Expectation;
+pub use fn_ctxt::*;
+pub use inherited::{Inherited, InheritedBuilder};
+
+use crate::check::check_fn;
+use crate::coercion::DynamicCoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{HirIdMap, Node};
+use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::check::check_abi;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::traits;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config;
+use rustc_session::Session;
+use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::Span;
+
+#[macro_export]
+macro_rules! type_error_struct {
+    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
+        let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
+
+        if $typ.references_error() {
+            err.downgrade_to_delayed_bug();
+        }
+
+        err
+    })
+}
+
+/// The type of a local binding, including the revealed type for anon types.
+#[derive(Copy, Clone, Debug)]
+pub struct LocalTy<'tcx> {
+    decl_ty: Ty<'tcx>,
+    revealed_ty: Ty<'tcx>,
+}
+
+#[derive(Copy, Clone)]
+pub struct UnsafetyState {
+    pub def: hir::HirId,
+    pub unsafety: hir::Unsafety,
+    from_fn: bool,
+}
+
+impl UnsafetyState {
+    pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
+        UnsafetyState { def, unsafety, from_fn: true }
+    }
+
+    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
+        use hir::BlockCheckMode;
+        match self.unsafety {
+            // If this unsafe, then if the outer function was already marked as
+            // unsafe we shouldn't attribute the unsafe'ness to the block. This
+            // way the block can be warned about instead of ignoring this
+            // extraneous block (functions are never warned about).
+            hir::Unsafety::Unsafe if self.from_fn => self,
+
+            unsafety => {
+                let (unsafety, def) = match blk.rules {
+                    BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
+                    BlockCheckMode::DefaultBlock => (unsafety, self.def),
+                };
+                UnsafetyState { def, unsafety, from_fn: false }
+            }
+        }
+    }
+}
+
+/// If this `DefId` is a "primary tables entry", returns
+/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
+///
+/// If this function returns `Some`, then `typeck_results(def_id)` will
+/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
+/// may not succeed. In some cases where this function returns `None`
+/// (notably closures), `typeck_results(def_id)` would wind up
+/// redirecting to the owning function.
+fn primary_body_of(
+    tcx: TyCtxt<'_>,
+    id: hir::HirId,
+) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
+    match tcx.hir().get(id) {
+        Node::Item(item) => match item.kind {
+            hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
+                Some((body, Some(ty), None))
+            }
+            hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
+            _ => None,
+        },
+        Node::TraitItem(item) => match item.kind {
+            hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+                Some((body, None, Some(sig)))
+            }
+            _ => None,
+        },
+        Node::ImplItem(item) => match item.kind {
+            hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
+            hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
+            _ => None,
+        },
+        Node::AnonConst(constant) => Some((constant.body, None, None)),
+        _ => None,
+    }
+}
+
+fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // Closures' typeck results come from their outermost function,
+    // as they are part of the same "inference environment".
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+    if typeck_root_def_id != def_id {
+        return tcx.has_typeck_results(typeck_root_def_id);
+    }
+
+    if let Some(def_id) = def_id.as_local() {
+        let id = tcx.hir().local_def_id_to_hir_id(def_id);
+        primary_body_of(tcx, id).is_some()
+    } else {
+        false
+    }
+}
+
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
+    &*tcx.typeck(def_id).used_trait_imports
+}
+
+fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
+    tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
+}
+
+fn typeck_const_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (did, param_did): (LocalDefId, DefId),
+) -> &ty::TypeckResults<'tcx> {
+    let fallback = move || tcx.type_of(param_did);
+    typeck_with_fallback(tcx, did, fallback)
+}
+
+fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+    if let Some(param_did) = tcx.opt_const_param_of(def_id) {
+        tcx.typeck_const_arg((def_id, param_did))
+    } else {
+        let fallback = move || tcx.type_of(def_id.to_def_id());
+        typeck_with_fallback(tcx, def_id, fallback)
+    }
+}
+
+/// Used only to get `TypeckResults` for type inference during error recovery.
+/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
+fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+    let fallback = move || {
+        let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
+        tcx.ty_error_with_message(span, "diagnostic only typeck table used")
+    };
+    typeck_with_fallback(tcx, def_id, fallback)
+}
+
+fn typeck_with_fallback<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    fallback: impl Fn() -> Ty<'tcx> + 'tcx,
+) -> &'tcx ty::TypeckResults<'tcx> {
+    // Closures' typeck results come from their outermost function,
+    // as they are part of the same "inference environment".
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+    if typeck_root_def_id != def_id {
+        return tcx.typeck(typeck_root_def_id);
+    }
+
+    let id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let span = tcx.hir().span(id);
+
+    // Figure out what primary body this item has.
+    let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
+        span_bug!(span, "can't type-check body of {:?}", def_id);
+    });
+    let body = tcx.hir().body(body_id);
+
+    let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
+        let param_env = tcx.param_env(def_id);
+        let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+            let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
+                let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
+            } else {
+                tcx.fn_sig(def_id)
+            };
+
+            check_abi(tcx, id, span, fn_sig.abi());
+
+            // Compute the function signature from point of view of inside the fn.
+            let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
+            let fn_sig = inh.normalize_associated_types_in(
+                body.value.span,
+                body_id.hir_id,
+                param_env,
+                fn_sig,
+            );
+            check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
+        } else {
+            let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+            let expected_type = body_ty
+                .and_then(|ty| match ty.kind {
+                    hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
+                    _ => None,
+                })
+                .unwrap_or_else(|| match tcx.hir().get(id) {
+                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+                        Node::Expr(&hir::Expr {
+                            kind: hir::ExprKind::ConstBlock(ref anon_const),
+                            ..
+                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span,
+                        }),
+                        Node::Ty(&hir::Ty {
+                            kind: hir::TyKind::Typeof(ref anon_const), ..
+                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span,
+                        }),
+                        Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
+                        | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
+                            let operand_ty = asm
+                                .operands
+                                .iter()
+                                .filter_map(|(op, _op_sp)| match op {
+                                    hir::InlineAsmOperand::Const { anon_const }
+                                        if anon_const.hir_id == id =>
+                                    {
+                                        // Inline assembly constants must be integers.
+                                        Some(fcx.next_int_var())
+                                    }
+                                    hir::InlineAsmOperand::SymFn { anon_const }
+                                        if anon_const.hir_id == id =>
+                                    {
+                                        Some(fcx.next_ty_var(TypeVariableOrigin {
+                                            kind: TypeVariableOriginKind::MiscVariable,
+                                            span,
+                                        }))
+                                    }
+                                    _ => None,
+                                })
+                                .next();
+                            operand_ty.unwrap_or_else(fallback)
+                        }
+                        _ => fallback(),
+                    },
+                    _ => fallback(),
+                });
+
+            let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
+            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+            // Gather locals in statics (because of block expressions).
+            GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+            fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
+
+            fcx.write_ty(id, expected_type);
+
+            fcx
+        };
+
+        let fallback_has_occurred = fcx.type_inference_fallback();
+
+        // Even though coercion casts provide type hints, we check casts after fallback for
+        // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+        fcx.check_casts();
+        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+        // Closure and generator analysis may run after fallback
+        // because they don't constrain other type variables.
+        // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
+        let prev_constness = fcx.param_env.constness();
+        fcx.param_env = fcx.param_env.without_const();
+        fcx.closure_analyze(body);
+        fcx.param_env = fcx.param_env.with_constness(prev_constness);
+        assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+        // Before the generator analysis, temporary scopes shall be marked to provide more
+        // precise information on types to be captured.
+        fcx.resolve_rvalue_scopes(def_id.to_def_id());
+        fcx.resolve_generator_interiors(def_id.to_def_id());
+
+        for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+            let ty = fcx.normalize_ty(span, ty);
+            fcx.require_type_is_sized(ty, span, code);
+        }
+
+        fcx.select_all_obligations_or_error();
+
+        if !fcx.infcx.is_tainted_by_errors() {
+            fcx.check_transmutes();
+        }
+
+        fcx.check_asms();
+
+        fcx.infcx.skip_region_resolution();
+
+        fcx.resolve_type_vars_in_body(body)
+    });
+
+    // Consistency check our TypeckResults instance can hold all ItemLocalIds
+    // it will need to hold.
+    assert_eq!(typeck_results.hir_owner, id.owner);
+
+    typeck_results
+}
+
+/// When `check_fn` is invoked on a generator (i.e., a body that
+/// includes yield), it returns back some information about the yield
+/// points.
+struct GeneratorTypes<'tcx> {
+    /// Type of generator argument / values returned by `yield`.
+    resume_ty: Ty<'tcx>,
+
+    /// Type of value that is yielded.
+    yield_ty: Ty<'tcx>,
+
+    /// Types that are captured (see `GeneratorInterior` for more).
+    interior: Ty<'tcx>,
+
+    /// Indicates if the generator is movable or static (immovable).
+    movability: hir::Movability,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Needs {
+    MutPlace,
+    None,
+}
+
+impl Needs {
+    fn maybe_mut_place(m: hir::Mutability) -> Self {
+        match m {
+            hir::Mutability::Mut => Needs::MutPlace,
+            hir::Mutability::Not => Needs::None,
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum PlaceOp {
+    Deref,
+    Index,
+}
+
+pub struct BreakableCtxt<'tcx> {
+    may_break: bool,
+
+    // this is `null` for loops where break with a value is illegal,
+    // such as `while`, `for`, and `while let`
+    coerce: Option<DynamicCoerceMany<'tcx>>,
+}
+
+pub struct EnclosingBreakables<'tcx> {
+    stack: Vec<BreakableCtxt<'tcx>>,
+    by_id: HirIdMap<usize>,
+}
+
+impl<'tcx> EnclosingBreakables<'tcx> {
+    fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
+        self.opt_find_breakable(target_id).unwrap_or_else(|| {
+            bug!("could not find enclosing breakable with id {}", target_id);
+        })
+    }
+
+    fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
+        match self.by_id.get(&target_id) {
+            Some(ix) => Some(&mut self.stack[*ix]),
+            None => None,
+        }
+    }
+}
+
+fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
+    struct_span_err!(
+        tcx.sess,
+        span,
+        E0533,
+        "expected unit struct, unit variant or constant, found {} `{}`",
+        res.descr(),
+        rustc_hir_pretty::qpath_to_string(qpath),
+    )
+    .emit();
+}
+
+/// Controls whether the arguments are tupled. This is used for the call
+/// operator.
+///
+/// Tupling means that all call-side arguments are packed into a tuple and
+/// passed as a single parameter. For example, if tupling is enabled, this
+/// function:
+/// ```
+/// fn f(x: (isize, isize)) {}
+/// ```
+/// Can be called as:
+/// ```ignore UNSOLVED (can this be done in user code?)
+/// # fn f(x: (isize, isize)) {}
+/// f(1, 2);
+/// ```
+/// Instead of:
+/// ```
+/// # fn f(x: (isize, isize)) {}
+/// f((1, 2));
+/// ```
+#[derive(Clone, Eq, PartialEq)]
+enum TupleArgumentsFlag {
+    DontTupleArguments,
+    TupleArguments,
+}
+
+fn fatally_break_rust(sess: &Session) {
+    let handler = sess.diagnostic();
+    handler.span_bug_no_panic(
+        MultiSpan::new(),
+        "It looks like you're trying to break rust; would you like some ICE?",
+    );
+    handler.note_without_error("the compiler expectedly panicked. this is a feature.");
+    handler.note_without_error(
+        "we would appreciate a joke overview: \
+         https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
+    );
+    handler.note_without_error(&format!(
+        "rustc {} running on {}",
+        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+        config::host_triple(),
+    ));
+}
+
+fn has_expected_num_generic_args<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_did: Option<DefId>,
+    expected: usize,
+) -> bool {
+    trait_did.map_or(true, |trait_did| {
+        let generics = tcx.generics_of(trait_did);
+        generics.count() == expected + if generics.has_self { 1 } else { 0 }
+    })
+}
+
+pub fn provide(providers: &mut Providers) {
+    method::provide(providers);
+    *providers = Providers {
+        typeck_item_bodies,
+        typeck_const_arg,
+        typeck,
+        diagnostic_only_typeck,
+        has_typeck_results,
+        used_trait_imports,
+        ..*providers
+    };
+}
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 362f1c34300..362f1c34300 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
diff --git a/compiler/rustc_hir_analysis/src/check/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 30731cbd03d..be4ea998622 100644
--- a/compiler/rustc_hir_analysis/src/check/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -1,10 +1,10 @@
 use super::{probe, MethodCallee};
 
-use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
-use crate::check::{callee, FnCtxt};
+use crate::{callee, FnCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
+use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
diff --git a/compiler/rustc_hir_analysis/src/check/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 3fe9bea2299..a1278edefbb 100644
--- a/compiler/rustc_hir_analysis/src/check/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -10,14 +10,14 @@ mod suggest;
 pub use self::suggest::SelfSource;
 pub use self::MethodError::*;
 
-use crate::check::{Expectation, FnCtxt};
-use crate::ObligationCause;
+use crate::{Expectation, FnCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{self, InferOk};
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
 use rustc_span::symbol::Ident;
diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index ca4cdf5a0d0..3c98a2aa3ab 100644
--- a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -1,3 +1,7 @@
+use crate::{
+    method::probe::{self, Pick},
+    FnCtxt,
+};
 use hir::def_id::DefId;
 use hir::HirId;
 use hir::ItemKind;
@@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 
-use crate::check::{
-    method::probe::{self, Pick},
-    FnCtxt,
-};
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(super) fn lint_dot_call_from_2018(
         &self,
diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index ba078ad0abb..74cf2ac32aa 100644
--- a/compiler/rustc_hir_analysis/src/check/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,14 +3,12 @@ use super::CandidateSource;
 use super::MethodError;
 use super::NoMatchData;
 
-use crate::check::FnCtxt;
 use crate::errors::MethodCallOnUnknownType;
-use crate::hir::def::DefKind;
-use crate::hir::def_id::DefId;
-
+use crate::FnCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def::Namespace;
 use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
@@ -23,6 +21,7 @@ use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_session::lint;
+use rustc_span::def_id::DefId;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{
     find_best_match_for_name_with_substrings, lev_distance_with_substrings,
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e276c4f7d84..f4351bfa84a 100644
--- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1,7 +1,8 @@
 //! Give useful errors and suggestions to users when an item can't be
 //! found or is otherwise invalid.
 
-use crate::check::FnCtxt;
+use crate::errors;
+use crate::FnCtxt;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
@@ -271,7 +272,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 };
 
-                if self.suggest_constraining_numerical_ty(
+                if self.suggest_wrapping_range_with_parens(
+                    tcx, actual, source, span, item_name, &ty_str,
+                ) || self.suggest_constraining_numerical_ty(
                     tcx, actual, source, span, item_kind, item_name, &ty_str,
                 ) {
                     return None;
@@ -1202,6 +1205,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    /// Suggest possible range with adding parentheses, for example:
+    /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
+    fn suggest_wrapping_range_with_parens(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        actual: Ty<'tcx>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        item_name: Ident,
+        ty_str: &str,
+    ) -> bool {
+        if let SelfSource::MethodCall(expr) = source {
+            for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
+                if let Node::Expr(parent_expr) = parent {
+                    let lang_item = match parent_expr.kind {
+                        ExprKind::Struct(ref qpath, _, _) => match **qpath {
+                            QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
+                            QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
+                            QPath::LangItem(LangItem::RangeToInclusive, ..) => {
+                                Some(LangItem::RangeToInclusive)
+                            }
+                            _ => None,
+                        },
+                        ExprKind::Call(ref func, _) => match func.kind {
+                            // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                            ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
+                                Some(LangItem::RangeInclusiveStruct)
+                            }
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+
+                    if lang_item.is_none() {
+                        continue;
+                    }
+
+                    let span_included = match parent_expr.kind {
+                        hir::ExprKind::Struct(_, eps, _) => {
+                            eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+                        }
+                        // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                        hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
+                        _ => false,
+                    };
+
+                    if !span_included {
+                        continue;
+                    }
+
+                    let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
+                    let range_ty =
+                        self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
+
+                    let pick = self.probe_for_name(
+                        span,
+                        Mode::MethodCall,
+                        item_name,
+                        IsSuggestion(true),
+                        range_ty,
+                        expr.hir_id,
+                        ProbeScope::AllTraits,
+                    );
+                    if pick.is_ok() {
+                        let range_span = parent_expr.span.with_hi(expr.span.hi());
+                        tcx.sess.emit_err(errors::MissingParentheseInRange {
+                            span,
+                            ty_str: ty_str.to_string(),
+                            method_name: item_name.as_str().to_string(),
+                            add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
+                                func_name: item_name.name.as_str().to_string(),
+                                left: range_span.shrink_to_lo(),
+                                right: range_span.shrink_to_hi(),
+                            }),
+                        });
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
+
     fn suggest_constraining_numerical_ty(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -1264,7 +1350,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // If this is a floating point literal that ends with '.',
                     // get rid of it to stop this from becoming a member access.
                     let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
-
                     err.span_suggestion(
                         lit.span,
                         &format!(
diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 5e498a92ec2..89573997693 100644
--- a/compiler/rustc_hir_analysis/src/check/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -2,7 +2,7 @@
 
 use super::method::MethodCallee;
 use super::{has_expected_num_generic_args, FnCtxt};
-use crate::check::Expectation;
+use crate::Expectation;
 use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
 use rustc_hir as hir;
diff --git a/compiler/rustc_hir_analysis/src/check/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 178326cfdc4..ea90da4a6dc 100644
--- a/compiler/rustc_hir_analysis/src/check/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,6 +1,5 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use rustc_ast as ast;
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
diff --git a/compiler/rustc_hir_analysis/src/check/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 2e0f37eba23..ba8cf6926f3 100644
--- a/compiler/rustc_hir_analysis/src/check/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,5 +1,5 @@
-use crate::check::method::MethodCallee;
-use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
+use crate::method::MethodCallee;
+use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
diff --git a/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 22c9e796107..22c9e796107 100644
--- a/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
diff --git a/compiler/rustc_hir_analysis/src/check/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4dea40829f6..4dea40829f6 100644
--- a/compiler/rustc_hir_analysis/src/check/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index e3e4a934ab5..1e26daa9c2c 100644
--- a/compiler/rustc_hir_analysis/src/check/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -2,7 +2,7 @@
 // unresolved type variables and replaces "ty_var" types with their
 // substitutions.
 
-use crate::check::FnCtxt;
+use crate::FnCtxt;
 use hir::def_id::LocalDefId;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
@@ -564,6 +564,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 opaque_type_key,
                 self.fcx.infcx.tcx,
                 true,
+                decl.origin,
             );
 
             self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 500900d3d4a..2131d19068e 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -18,19 +18,19 @@ use crate::infer::error_reporting::{
 pub mod note_and_explain;
 
 #[derive(Diagnostic)]
-#[diag(infer::opaque_hidden_type)]
+#[diag(infer_opaque_hidden_type)]
 pub struct OpaqueHiddenTypeDiag {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[note(infer::opaque_type)]
+    #[note(opaque_type)]
     pub opaque_type: Span,
-    #[note(infer::hidden_type)]
+    #[note(hidden_type)]
     pub hidden_type: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
+#[diag(infer_type_annotations_needed, code = "E0282")]
 pub struct AnnotationRequired<'a> {
     #[primary_span]
     pub span: Span,
@@ -48,7 +48,7 @@ pub struct AnnotationRequired<'a> {
 
 // Copy of `AnnotationRequired` for E0283
 #[derive(Diagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
+#[diag(infer_type_annotations_needed, code = "E0283")]
 pub struct AmbigousImpl<'a> {
     #[primary_span]
     pub span: Span,
@@ -66,7 +66,7 @@ pub struct AmbigousImpl<'a> {
 
 // Copy of `AnnotationRequired` for E0284
 #[derive(Diagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
+#[diag(infer_type_annotations_needed, code = "E0284")]
 pub struct AmbigousReturn<'a> {
     #[primary_span]
     pub span: Span,
@@ -83,7 +83,7 @@ pub struct AmbigousReturn<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
+#[diag(infer_need_type_info_in_generator, code = "E0698")]
 pub struct NeedTypeInfoInGenerator<'a> {
     #[primary_span]
     pub span: Span,
@@ -94,7 +94,7 @@ pub struct NeedTypeInfoInGenerator<'a> {
 
 // Used when a better one isn't available
 #[derive(Subdiagnostic)]
-#[label(infer::label_bad)]
+#[label(infer_label_bad)]
 pub struct InferenceBadError<'a> {
     #[primary_span]
     pub span: Span,
@@ -110,7 +110,7 @@ pub struct InferenceBadError<'a> {
 #[derive(Subdiagnostic)]
 pub enum SourceKindSubdiag<'a> {
     #[suggestion_verbose(
-        infer::source_kind_subdiag_let,
+        infer_source_kind_subdiag_let,
         code = ": {type_name}",
         applicability = "has-placeholders"
     )]
@@ -125,7 +125,7 @@ pub enum SourceKindSubdiag<'a> {
         prefix: &'a str,
         arg_name: String,
     },
-    #[label(infer::source_kind_subdiag_generic_label)]
+    #[label(infer_source_kind_subdiag_generic_label)]
     GenericLabel {
         #[primary_span]
         span: Span,
@@ -136,7 +136,7 @@ pub enum SourceKindSubdiag<'a> {
         parent_name: String,
     },
     #[suggestion_verbose(
-        infer::source_kind_subdiag_generic_suggestion,
+        infer_source_kind_subdiag_generic_suggestion,
         code = "::<{args}>",
         applicability = "has-placeholders"
     )]
@@ -151,7 +151,7 @@ pub enum SourceKindSubdiag<'a> {
 #[derive(Subdiagnostic)]
 pub enum SourceKindMultiSuggestion<'a> {
     #[multipart_suggestion_verbose(
-        infer::source_kind_fully_qualified,
+        infer_source_kind_fully_qualified,
         applicability = "has-placeholders"
     )]
     FullyQualified {
@@ -164,7 +164,7 @@ pub enum SourceKindMultiSuggestion<'a> {
         successor_pos: &'a str,
     },
     #[multipart_suggestion_verbose(
-        infer::source_kind_closure_return,
+        infer_source_kind_closure_return,
         applicability = "has-placeholders"
     )]
     ClosureReturn {
@@ -260,7 +260,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
                 requirement,
                 expected_found: Some((expected, found)),
             } => {
-                label_or_note(span, fluent::infer::subtype);
+                label_or_note(span, fluent::infer_subtype);
                 diag.set_arg("requirement", requirement);
 
                 diag.note_expected_found(&"", expected, &"", found);
@@ -269,7 +269,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> {
                 // FIXME: this really should be handled at some earlier stage. Our
                 // handling of region checking when type errors are present is
                 // *terrible*.
-                label_or_note(span, fluent::infer::subtype_2);
+                label_or_note(span, fluent::infer_subtype_2);
                 diag.set_arg("requirement", requirement);
             }
         };
@@ -300,9 +300,9 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
     {
         match self {
             LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
-                diag.span_label(param_span, fluent::infer::declared_different);
-                diag.span_label(ret_span, fluent::infer::nothing);
-                diag.span_label(span, fluent::infer::data_returned);
+                diag.span_label(param_span, fluent::infer_declared_different);
+                diag.span_label(ret_span, fluent::infer_nothing);
+                diag.span_label(span, fluent::infer_data_returned);
                 diag.set_arg("label_var1_exists", label_var1.is_some());
                 diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
             }
@@ -315,13 +315,13 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
                 sub: label_var2,
             } => {
                 if hir_equal {
-                    diag.span_label(ty_sup, fluent::infer::declared_multiple);
-                    diag.span_label(ty_sub, fluent::infer::nothing);
-                    diag.span_label(span, fluent::infer::data_lifetime_flow);
+                    diag.span_label(ty_sup, fluent::infer_declared_multiple);
+                    diag.span_label(ty_sub, fluent::infer_nothing);
+                    diag.span_label(span, fluent::infer_data_lifetime_flow);
                 } else {
-                    diag.span_label(ty_sup, fluent::infer::types_declared_different);
-                    diag.span_label(ty_sub, fluent::infer::nothing);
-                    diag.span_label(span, fluent::infer::data_flows);
+                    diag.span_label(ty_sup, fluent::infer_types_declared_different);
+                    diag.span_label(ty_sub, fluent::infer_nothing);
+                    diag.span_label(span, fluent::infer_data_flows);
                     diag.set_arg("label_var1_exists", label_var1.is_some());
                     diag.set_arg(
                         "label_var1",
@@ -419,7 +419,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
             }
 
             diag.multipart_suggestion(
-                fluent::infer::lifetime_param_suggestion,
+                fluent::infer_lifetime_param_suggestion,
                 suggestions,
                 Applicability::MaybeIncorrect,
             );
@@ -427,13 +427,13 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
             true
         };
         if mk_suggestion() && self.add_note {
-            diag.note(fluent::infer::lifetime_param_suggestion_elided);
+            diag.note(fluent::infer_lifetime_param_suggestion_elided);
         }
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::lifetime_mismatch, code = "E0623")]
+#[diag(infer_lifetime_mismatch, code = "E0623")]
 pub struct LifetimeMismatch<'a> {
     #[primary_span]
     pub span: Span,
@@ -454,56 +454,43 @@ impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
     {
         self.unmet_requirements
-            .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
-        diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
+            .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
+        diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
     }
 }
 
-pub struct ImplNote {
-    pub impl_span: Option<Span>,
-}
-
-impl AddToDiagnostic for ImplNote {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self.impl_span {
-            Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
-            None => diag.note(fluent::infer::msl_impl_note),
-        };
-    }
-}
-
-pub enum TraitSubdiag {
-    Note { span: Span },
-    Sugg { span: Span },
+// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
+#[derive(Subdiagnostic)]
+pub enum DoesNotOutliveStaticFromImpl {
+    #[note(infer_does_not_outlive_static_from_impl)]
+    Spanned {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(infer_does_not_outlive_static_from_impl)]
+    Unspanned,
 }
 
-// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
-impl AddToDiagnostic for TraitSubdiag {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        match self {
-            TraitSubdiag::Note { span } => {
-                diag.span_note(span, "this has an implicit `'static` lifetime requirement");
-            }
-            TraitSubdiag::Sugg { span } => {
-                diag.span_suggestion_verbose(
-                    span,
-                    "consider relaxing the implicit `'static` requirement",
-                    " + '_".to_owned(),
-                    rustc_errors::Applicability::MaybeIncorrect,
-                );
-            }
-        }
-    }
+#[derive(Subdiagnostic)]
+pub enum ImplicitStaticLifetimeSubdiag {
+    #[note(infer_implicit_static_lifetime_note)]
+    Note {
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion_verbose(
+        infer_implicit_static_lifetime_suggestion,
+        code = " + '_",
+        applicability = "maybe-incorrect"
+    )]
+    Sugg {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 #[derive(Diagnostic)]
-#[diag(infer::mismatched_static_lifetime)]
+#[diag(infer_mismatched_static_lifetime)]
 pub struct MismatchedStaticLifetime<'a> {
     #[primary_span]
     pub cause_span: Span,
@@ -512,7 +499,7 @@ pub struct MismatchedStaticLifetime<'a> {
     #[subdiagnostic]
     pub expl: Option<note_and_explain::RegionExplanation<'a>>,
     #[subdiagnostic]
-    pub impl_note: ImplNote,
-    #[subdiagnostic]
-    pub trait_subdiags: Vec<TraitSubdiag>,
+    pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
+    #[subdiagnostic(eager)]
+    pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
 }
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 201a3c7100c..6a29d85627a 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -166,9 +166,9 @@ impl AddToDiagnostic for RegionExplanation<'_> {
         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
     {
         if let Some(span) = self.desc.span {
-            diag.span_note(span, fluent::infer::region_explanation);
+            diag.span_note(span, fluent::infer_region_explanation);
         } else {
-            diag.note(fluent::infer::region_explanation);
+            diag.note(fluent::infer_region_explanation);
         }
         self.desc.add_to(diag);
         diag.set_arg("pref_kind", self.prefix);
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index eb0135d76f1..608b5cc8756 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -632,7 +632,7 @@ impl<'tcx> InferCtxt<'tcx> {
 /// creates query region constraints.
 pub fn make_query_region_constraints<'tcx>(
     tcx: TyCtxt<'tcx>,
-    outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
+    outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory)>,
     region_constraints: &RegionConstraintData<'tcx>,
 ) -> QueryRegionConstraints<'tcx> {
     let RegionConstraintData { constraints, verifys, givens, member_constraints } =
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index ddeeaa9618e..9ff703e521f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -338,8 +338,7 @@ impl<'tcx> InferCtxt<'tcx> {
 
             let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
 
-            for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
-                let predicate = predicate.subst(self.tcx, substs);
+            for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) {
                 let output = predicate
                     .kind()
                     .map_bound(|kind| match kind {
@@ -2272,6 +2271,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
             }
             FailureCode::Error0308(failure_str) => {
+                fn escape_literal(s: &str) -> String {
+                    let mut escaped = String::with_capacity(s.len());
+                    let mut chrs = s.chars().peekable();
+                    while let Some(first) = chrs.next() {
+                        match (first, chrs.peek()) {
+                            ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
+                                escaped.push('\\');
+                                escaped.push(delim);
+                                chrs.next();
+                            }
+                            ('"' | '\'', _) => {
+                                escaped.push('\\');
+                                escaped.push(first)
+                            }
+                            (c, _) => escaped.push(c),
+                        };
+                    }
+                    escaped
+                }
                 let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
                 if let Some((expected, found)) = trace.values.ty() {
                     match (expected.kind(), found.kind()) {
@@ -2293,7 +2311,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 err.span_suggestion(
                                     span,
                                     "if you meant to write a `char` literal, use single quotes",
-                                    format!("'{}'", code),
+                                    format!("'{}'", escape_literal(code)),
                                     Applicability::MachineApplicable,
                                 );
                             }
@@ -2308,7 +2326,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     err.span_suggestion(
                                         span,
                                         "if you meant to write a `str` literal, use double quotes",
-                                        format!("\"{}\"", code),
+                                        format!("\"{}\"", escape_literal(code)),
                                         Applicability::MachineApplicable,
                                     );
                                 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index f4b3ded53b0..7b3178e610f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -902,11 +902,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
             // impl is currently the `DefId` of `Output` in the trait definition
             // which makes this somewhat difficult and prevents us from just
             // using `self.path_inferred_subst_iter` here.
-            hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) => {
-                if let Some(ty) = self.opt_node_type(expr.hir_id) {
-                    if let ty::Adt(_, substs) = ty.kind() {
-                        return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
-                    }
+            hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
+            // FIXME(TaKO8Ki): Ideally we should support this. For that
+            // we have to map back from the self type to the
+            // type alias though. That's difficult.
+            //
+            // See the `need_type_info/issue-103053.rs` test for
+            // a example.
+            if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+                if let Some(ty) = self.opt_node_type(expr.hir_id)
+                    && let ty::Adt(_, substs) = ty.kind()
+                {
+                    return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
                 }
             }
             hir::ExprKind::MethodCall(segment, ..) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 1410e2b63b0..c5f2a1a3f7d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -2,7 +2,9 @@
 //! to hold.
 
 use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
-use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
+use crate::errors::{
+    DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
+};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
@@ -56,7 +58,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             note_and_explain::SuffixKind::Continues,
         );
         let mut impl_span = None;
-        let mut trait_subdiags = Vec::new();
+        let mut implicit_static_lifetimes = Vec::new();
         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
@@ -90,10 +92,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 // Otherwise, point at all implicit static lifetimes
 
                 for span in &traits {
-                    trait_subdiags.push(TraitSubdiag::Note { span: *span });
+                    implicit_static_lifetimes
+                        .push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
                     // It would be nice to put this immediately under the above note, but they get
                     // pushed to the end.
-                    trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
+                    implicit_static_lifetimes
+                        .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
                 }
             }
         } else {
@@ -105,8 +109,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             cause_span: cause.span,
             unmet_lifetime_reqs: multispan_subdiag,
             expl,
-            impl_note: ImplNote { impl_span },
-            trait_subdiags,
+            does_not_outlive_static_from_impl: impl_span
+                .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
+                .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
+            implicit_static_lifetimes,
         };
         let reported = self.tcx().sess.emit_err(err);
         Some(reported)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index a04245a23a2..41b115f3377 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -19,26 +19,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 expected_found: self.values_str(trace.values),
             }
             .add_to_diagnostic(err),
-            infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow }
-                .add_to_diagnostic(err),
+            infer::Reborrow(span) => {
+                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
+            }
             infer::ReborrowUpvar(span, ref upvar_id) => {
                 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::reborrow,
+                    msg: fluent::infer_reborrow,
                     name: &var_name.to_string(),
                     continues: false,
                 }
                 .add_to_diagnostic(err);
             }
             infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound }
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
                     .add_to_diagnostic(err);
             }
             infer::DataBorrowed(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::data_borrowed,
+                    msg: fluent::infer_data_borrowed,
                     name: &self.ty_to_string(ty),
                     continues: false,
                 }
@@ -47,7 +48,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::ReferenceOutlivesReferent(ty, span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::reference_outlives_referent,
+                    msg: fluent::infer_reference_outlives_referent,
                     name: &self.ty_to_string(ty),
                     continues: false,
                 }
@@ -56,22 +57,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::RelateParamBound(span, ty, opt_span) => {
                 RegionOriginNote::WithName {
                     span,
-                    msg: fluent::infer::relate_param_bound,
+                    msg: fluent::infer_relate_param_bound,
                     name: &self.ty_to_string(ty),
                     continues: opt_span.is_some(),
                 }
                 .add_to_diagnostic(err);
                 if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 }
+                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
                         .add_to_diagnostic(err);
                 }
             }
             infer::RelateRegionParamBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound }
+                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
                     .add_to_diagnostic(err);
             }
             infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation }
+                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
                     .add_to_diagnostic(err);
             }
             infer::CheckAssociatedTypeBounds { ref parent, .. } => {
@@ -80,7 +81,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::AscribeUserTypeProvePredicate(span) => {
                 RegionOriginNote::Plain {
                     span,
-                    msg: fluent::infer::ascribe_user_type_prove_predicate,
+                    msg: fluent::infer_ascribe_user_type_prove_predicate,
                 }
                 .add_to_diagnostic(err);
             }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 167ef279104..2732c92ecd3 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -425,7 +425,7 @@ pub enum SubregionOrigin<'tcx> {
 static_assert_size!(SubregionOrigin<'_>, 32);
 
 impl<'tcx> SubregionOrigin<'tcx> {
-    pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
+    pub fn to_constraint_category(&self) -> ConstraintCategory {
         match self {
             Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(),
             Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span),
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 77e8f72aefa..0a4ecc4c033 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,6 +1,7 @@
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
 use crate::traits;
+use hir::def::DefKind;
 use hir::def_id::{DefId, LocalDefId};
 use hir::{HirId, OpaqueTyOrigin};
 use rustc_data_structures::sync::Lrc;
@@ -543,16 +544,18 @@ impl<'tcx> InferCtxt<'tcx> {
 
         let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
 
-        for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
-            debug!(?predicate);
-            let predicate = predicate.subst(tcx, substs);
-
+        for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
             let predicate = predicate.fold_with(&mut BottomUpFolder {
                 tcx,
                 ty_op: |ty| match *ty.kind() {
                     // We can't normalize associated types from `rustc_infer`,
                     // but we can eagerly register inference variables for them.
-                    ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+                    // FIXME(RPITIT): Don't replace RPITITs with inference vars.
+                    ty::Projection(projection_ty)
+                        if !projection_ty.has_escaping_bound_vars()
+                            && tcx.def_kind(projection_ty.item_def_id)
+                                != DefKind::ImplTraitPlaceholder =>
+                    {
                         self.infer_projection(
                             param_env,
                             projection_ty,
@@ -568,6 +571,12 @@ impl<'tcx> InferCtxt<'tcx> {
                     {
                         hidden_ty
                     }
+                    // FIXME(RPITIT): This can go away when we move to associated types
+                    ty::Projection(proj)
+                        if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
+                    {
+                        hidden_ty
+                    }
                     _ => ty,
                 },
                 lt_op: |lt| lt,
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 6ca884799aa..5ebf80b7b74 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -210,7 +210,7 @@ pub trait TypeOutlivesDelegate<'tcx> {
         origin: SubregionOrigin<'tcx>,
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
-        constraint_category: ConstraintCategory<'tcx>,
+        constraint_category: ConstraintCategory,
     );
 
     fn push_verify(
@@ -259,7 +259,7 @@ where
         origin: infer::SubregionOrigin<'tcx>,
         ty: Ty<'tcx>,
         region: ty::Region<'tcx>,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) {
         assert!(!ty.has_escaping_bound_vars());
 
@@ -273,7 +273,7 @@ where
         origin: infer::SubregionOrigin<'tcx>,
         components: &[Component<'tcx>],
         region: ty::Region<'tcx>,
-        category: ConstraintCategory<'tcx>,
+        category: ConstraintCategory,
     ) {
         for component in components.iter() {
             let origin = origin.clone();
@@ -529,7 +529,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> {
         origin: SubregionOrigin<'tcx>,
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
-        _constraint_category: ConstraintCategory<'tcx>,
+        _constraint_category: ConstraintCategory,
     ) {
         self.sub_regions(origin, a, b)
     }
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 069f9600091..4db4ff2388d 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,6 +1,5 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::mir;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
@@ -48,10 +47,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
             ct.super_fold_with(self)
         }
     }
-
-    fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        constant.super_fold_with(self)
-    }
 }
 
 /// The opportunistic region resolver opportunistically resolves regions
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index f0cb861c782..6a4c5b4d373 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" }
 rustc_monomorphize = { path = "../rustc_monomorphize" }
 rustc_passes = { path = "../rustc_passes" }
 rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_typeck = { path = "../rustc_hir_typeck" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_plugin_impl = { path = "../rustc_plugin_impl" }
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 097640f26c1..f5135c78dc8 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -5,7 +5,7 @@ use std::io;
 use std::path::Path;
 
 #[derive(Diagnostic)]
-#[diag(interface::ferris_identifier)]
+#[diag(interface_ferris_identifier)]
 pub struct FerrisIdentifier {
     #[primary_span]
     pub spans: Vec<Span>,
@@ -14,7 +14,7 @@ pub struct FerrisIdentifier {
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::emoji_identifier)]
+#[diag(interface_emoji_identifier)]
 pub struct EmojiIdentifier {
     #[primary_span]
     pub spans: Vec<Span>,
@@ -22,67 +22,67 @@ pub struct EmojiIdentifier {
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::mixed_bin_crate)]
+#[diag(interface_mixed_bin_crate)]
 pub struct MixedBinCrate;
 
 #[derive(Diagnostic)]
-#[diag(interface::mixed_proc_macro_crate)]
+#[diag(interface_mixed_proc_macro_crate)]
 pub struct MixedProcMacroCrate;
 
 #[derive(Diagnostic)]
-#[diag(interface::proc_macro_doc_without_arg)]
+#[diag(interface_proc_macro_doc_without_arg)]
 pub struct ProcMacroDocWithoutArg;
 
 #[derive(Diagnostic)]
-#[diag(interface::error_writing_dependencies)]
+#[diag(interface_error_writing_dependencies)]
 pub struct ErrorWritingDependencies<'a> {
     pub path: &'a Path,
     pub error: io::Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::input_file_would_be_overwritten)]
+#[diag(interface_input_file_would_be_overwritten)]
 pub struct InputFileWouldBeOverWritten<'a> {
     pub path: &'a Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::generated_file_conflicts_with_directory)]
+#[diag(interface_generated_file_conflicts_with_directory)]
 pub struct GeneratedFileConflictsWithDirectory<'a> {
     pub input_path: &'a Path,
     pub dir_path: &'a Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::temps_dir_error)]
+#[diag(interface_temps_dir_error)]
 pub struct TempsDirError;
 
 #[derive(Diagnostic)]
-#[diag(interface::out_dir_error)]
+#[diag(interface_out_dir_error)]
 pub struct OutDirError;
 
 #[derive(Diagnostic)]
-#[diag(interface::cant_emit_mir)]
+#[diag(interface_cant_emit_mir)]
 pub struct CantEmitMIR {
     pub error: io::Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::rustc_error_fatal)]
+#[diag(interface_rustc_error_fatal)]
 pub struct RustcErrorFatal {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::rustc_error_unexpected_annotation)]
+#[diag(interface_rustc_error_unexpected_annotation)]
 pub struct RustcErrorUnexpectedAnnotation {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(interface::failed_writing_file)]
+#[diag(interface_failed_writing_file)]
 pub struct FailedWritingFile<'a> {
     pub path: &'a Path,
     pub error: io::Error,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 949bd02ad68..89aaa0b95e4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -17,7 +17,7 @@ use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilena
 use rustc_session::early_error;
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
-use rustc_session::{DiagnosticOutput, Session};
+use rustc_session::Session;
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use std::path::PathBuf;
@@ -25,7 +25,10 @@ use std::result;
 
 pub type Result<T> = result::Result<T, ErrorGuaranteed>;
 
-/// Represents a compiler session.
+/// Represents a compiler session. Note that every `Compiler` contains a
+/// `Session`, but `Compiler` also contains some things that cannot be in
+/// `Session`, due to `Session` being in a crate that has many fewer
+/// dependencies than this crate.
 ///
 /// Can be used to run `rustc_interface` queries.
 /// Created by passing [`Config`] to [`run_compiler`].
@@ -247,7 +250,6 @@ pub struct Config {
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<PathBuf>,
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
-    pub diagnostic_output: DiagnosticOutput,
 
     pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
 
@@ -276,59 +278,6 @@ pub struct Config {
     pub registry: Registry,
 }
 
-pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
-    crate::callbacks::setup_callbacks();
-
-    let registry = &config.registry;
-    let (mut sess, codegen_backend) = util::create_session(
-        config.opts,
-        config.crate_cfg,
-        config.crate_check_cfg,
-        config.diagnostic_output,
-        config.file_loader,
-        config.input_path.clone(),
-        config.lint_caps,
-        config.make_codegen_backend,
-        registry.clone(),
-    );
-
-    if let Some(parse_sess_created) = config.parse_sess_created {
-        parse_sess_created(
-            &mut Lrc::get_mut(&mut sess)
-                .expect("create_session() should never share the returned session")
-                .parse_sess,
-        );
-    }
-
-    let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
-
-    let compiler = Compiler {
-        sess,
-        codegen_backend,
-        input: config.input,
-        input_path: config.input_path,
-        output_dir: config.output_dir,
-        output_file: config.output_file,
-        temps_dir,
-        register_lints: config.register_lints,
-        override_queries: config.override_queries,
-    };
-
-    rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
-        let r = {
-            let _sess_abort_error = OnDrop(|| {
-                compiler.sess.finish_diagnostics(registry);
-            });
-
-            f(&compiler)
-        };
-
-        let prof = compiler.sess.prof.clone();
-        prof.generic_activity("drop_compiler").run(move || drop(compiler));
-        r
-    })
-}
-
 // JUSTIFICATION: before session exists, only config
 #[allow(rustc::bad_opt_access)]
 pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
@@ -336,7 +285,53 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     util::run_in_thread_pool_with_globals(
         config.opts.edition,
         config.opts.unstable_opts.threads,
-        || create_compiler_and_run(config, f),
+        || {
+            crate::callbacks::setup_callbacks();
+
+            let registry = &config.registry;
+            let (mut sess, codegen_backend) = util::create_session(
+                config.opts,
+                config.crate_cfg,
+                config.crate_check_cfg,
+                config.file_loader,
+                config.input_path.clone(),
+                config.lint_caps,
+                config.make_codegen_backend,
+                registry.clone(),
+            );
+
+            if let Some(parse_sess_created) = config.parse_sess_created {
+                parse_sess_created(&mut sess.parse_sess);
+            }
+
+            let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+
+            let compiler = Compiler {
+                sess: Lrc::new(sess),
+                codegen_backend: Lrc::new(codegen_backend),
+                input: config.input,
+                input_path: config.input_path,
+                output_dir: config.output_dir,
+                output_file: config.output_file,
+                temps_dir,
+                register_lints: config.register_lints,
+                override_queries: config.override_queries,
+            };
+
+            rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
+                let r = {
+                    let _sess_abort_error = OnDrop(|| {
+                        compiler.sess.finish_diagnostics(registry);
+                    });
+
+                    f(&compiler)
+                };
+
+                let prof = compiler.sess.prof.clone();
+                prof.generic_activity("drop_compiler").run(move || drop(compiler));
+                r
+            })
+        },
     )
 }
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 8fd4224ca38..a47c3e3253e 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -736,6 +736,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     rustc_monomorphize::provide(providers);
     rustc_privacy::provide(providers);
     rustc_hir_analysis::provide(providers);
+    rustc_hir_typeck::provide(providers);
     ty::provide(providers);
     traits::provide(providers);
     rustc_passes::provide(providers);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d64cdcdbaa9..eb8e65a6d59 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -17,7 +17,7 @@ use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, Switc
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
+use rustc_session::{build_session, getopts, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
@@ -40,16 +40,7 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options
 fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
     let registry = registry::Registry::new(&[]);
     let (sessopts, cfg) = build_session_options_and_crate_config(matches);
-    let sess = build_session(
-        sessopts,
-        None,
-        None,
-        registry,
-        DiagnosticOutput::Default,
-        Default::default(),
-        None,
-        None,
-    );
+    let sess = build_session(sessopts, None, None, registry, Default::default(), None, None);
     (sess, cfg)
 }
 
@@ -657,6 +648,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(dump_mir_dir, String::from("abc"));
     untracked!(dump_mir_exclude_pass_number, true);
     untracked!(dump_mir_graphviz, true);
+    untracked!(dylib_lto, true);
     untracked!(emit_stack_sizes, true);
     untracked!(future_incompat_test, true);
     untracked!(hir_stats, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f7e70d355cf..519b8a7fc7c 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -3,22 +3,15 @@ use libloading::Library;
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-#[cfg(parallel_compiler)]
-use rustc_data_structures::jobserver;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
-#[cfg(parallel_compiler)]
-use rustc_middle::ty::tls;
 use rustc_parse::validate_attr;
-#[cfg(parallel_compiler)]
-use rustc_query_impl::{QueryContext, QueryCtxt};
 use rustc_session as session;
 use rustc_session::config::CheckCfg;
 use rustc_session::config::{self, CrateType};
 use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
 use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::CrateConfig;
-use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
+use rustc_session::{early_error, filesearch, output, Session};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::FileLoader;
@@ -26,8 +19,6 @@ use rustc_span::symbol::{sym, Symbol};
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::mem;
-#[cfg(not(parallel_compiler))]
-use std::panic;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::OnceLock;
@@ -65,7 +56,6 @@ pub fn create_session(
     sopts: config::Options,
     cfg: FxHashSet<(String, Option<String>)>,
     check_cfg: CheckCfg,
-    diagnostic_output: DiagnosticOutput,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     input_path: Option<PathBuf>,
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -73,7 +63,7 @@ pub fn create_session(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
     descriptions: Registry,
-) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
+) -> (Session, Box<dyn CodegenBackend>) {
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
     } else {
@@ -104,7 +94,6 @@ pub fn create_session(
         input_path,
         bundle,
         descriptions,
-        diagnostic_output,
         lint_caps,
         file_loader,
         target_override,
@@ -121,7 +110,7 @@ pub fn create_session(
     sess.parse_sess.config = cfg;
     sess.parse_sess.check_config = check_cfg;
 
-    (Lrc::new(sess), Lrc::new(codegen_backend))
+    (sess, codegen_backend)
 }
 
 const STACK_SIZE: usize = 8 * 1024 * 1024;
@@ -132,79 +121,86 @@ fn get_stack_size() -> Option<usize> {
     env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
 }
 
-/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
-/// for `'static` bounds.
-#[cfg(not(parallel_compiler))]
-fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
-    // SAFETY: join() is called immediately, so any closure captures are still
-    // alive.
-    match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
-        Ok(v) => v,
-        Err(e) => panic::resume_unwind(e),
-    }
-}
-
 #[cfg(not(parallel_compiler))]
-pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     _threads: usize,
     f: F,
 ) -> R {
-    let mut cfg = thread::Builder::new().name("rustc".to_string());
-
+    // The "thread pool" is a single spawned thread in the non-parallel
+    // compiler. We run on a spawned thread instead of the main thread (a) to
+    // provide control over the stack size, and (b) to increase similarity with
+    // the parallel compiler, in particular to ensure there is no accidental
+    // sharing of data between the main thread and the compilation thread
+    // (which might cause problems for the parallel compiler).
+    let mut builder = thread::Builder::new().name("rustc".to_string());
     if let Some(size) = get_stack_size() {
-        cfg = cfg.stack_size(size);
+        builder = builder.stack_size(size);
     }
 
-    let main_handler = move || rustc_span::create_session_globals_then(edition, f);
-
-    scoped_thread(cfg, main_handler)
-}
-
-/// Creates a new thread and forwards information in thread locals to it.
-/// The new thread runs the deadlock handler.
-/// Must only be called when a deadlock is about to happen.
-#[cfg(parallel_compiler)]
-unsafe fn handle_deadlock() {
-    let registry = rustc_rayon_core::Registry::current();
-
-    let query_map = tls::with(|tcx| {
-        QueryCtxt::from_tcx(tcx)
-            .try_collect_active_jobs()
-            .expect("active jobs shouldn't be locked in deadlock handler")
-    });
-    thread::spawn(move || rustc_query_impl::deadlock(query_map, &registry));
+    // We build the session globals and run `f` on the spawned thread, because
+    // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
+    thread::scope(|s| {
+        // `unwrap` is ok here because `spawn_scoped` only panics if the thread
+        // name contains null bytes.
+        let r = builder
+            .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f))
+            .unwrap()
+            .join();
+
+        match r {
+            Ok(v) => v,
+            Err(e) => std::panic::resume_unwind(e),
+        }
+    })
 }
 
 #[cfg(parallel_compiler)]
-pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     threads: usize,
     f: F,
 ) -> R {
-    let mut config = rayon::ThreadPoolBuilder::new()
+    use rustc_data_structures::jobserver;
+    use rustc_middle::ty::tls;
+    use rustc_query_impl::{deadlock, QueryContext, QueryCtxt};
+
+    let mut builder = rayon::ThreadPoolBuilder::new()
         .thread_name(|_| "rustc".to_string())
         .acquire_thread_handler(jobserver::acquire_thread)
         .release_thread_handler(jobserver::release_thread)
         .num_threads(threads)
-        .deadlock_handler(|| unsafe { handle_deadlock() });
-
+        .deadlock_handler(|| {
+            // On deadlock, creates a new thread and forwards information in thread
+            // locals to it. The new thread runs the deadlock handler.
+            let query_map = tls::with(|tcx| {
+                QueryCtxt::from_tcx(tcx)
+                    .try_collect_active_jobs()
+                    .expect("active jobs shouldn't be locked in deadlock handler")
+            });
+            let registry = rustc_rayon_core::Registry::current();
+            thread::spawn(move || deadlock(query_map, &registry));
+        });
     if let Some(size) = get_stack_size() {
-        config = config.stack_size(size);
+        builder = builder.stack_size(size);
     }
 
-    let with_pool = move |pool: &rayon::ThreadPool| pool.install(f);
-
+    // We create the session globals on the main thread, then create the thread
+    // pool. Upon creation, each worker thread created gets a copy of the
+    // session globals in TLS. This is possible because `SessionGlobals` impls
+    // `Send` in the parallel compiler.
     rustc_span::create_session_globals_then(edition, || {
         rustc_span::with_session_globals(|session_globals| {
-            // The main handler runs for each Rayon worker thread and sets up
-            // the thread local rustc uses. `session_globals` is captured and set
-            // on the new threads.
-            let main_handler = move |thread: rayon::ThreadBuilder| {
-                rustc_span::set_session_globals_then(session_globals, || thread.run())
-            };
-
-            config.build_scoped(main_handler, with_pool).unwrap()
+            builder
+                .build_scoped(
+                    // Initialize each new worker thread when created.
+                    move |thread: rayon::ThreadBuilder| {
+                        rustc_span::set_session_globals_then(session_globals, || thread.run())
+                    },
+                    // Run `f` on the first thread in the thread pool.
+                    move |pool: &rayon::ThreadPool| pool.install(f),
+                )
+                .unwrap()
         })
     })
 }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index bd6b637f76f..abebc533cc1 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -121,25 +121,25 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
             cx.struct_span_lint(
                 ARRAY_INTO_ITER,
                 call.ident.span,
-                fluent::lint::array_into_iter,
+                fluent::lint_array_into_iter,
                 |diag| {
                     diag.set_arg("target", target);
                     diag.span_suggestion(
                         call.ident.span,
-                        fluent::lint::use_iter_suggestion,
+                        fluent::use_iter_suggestion,
                         "iter",
                         Applicability::MachineApplicable,
                     );
                     if self.for_expr_span == expr.span {
                         diag.span_suggestion(
                             receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                            fluent::lint::remove_into_iter_suggestion,
+                            fluent::remove_into_iter_suggestion,
                             "",
                             Applicability::MaybeIncorrect,
                         );
                     } else if receiver_ty.is_array() {
                         diag.multipart_suggestion(
-                            fluent::lint::use_explicit_into_iter_suggestion,
+                            fluent::use_explicit_into_iter_suggestion,
                             vec![
                                 (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
                                 (
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 886e25f2d78..53c49105134 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -106,11 +106,11 @@ impl EarlyLintPass for WhileTrue {
             cx.struct_span_lint(
                             WHILE_TRUE,
                             condition_span,
-                fluent::lint::builtin_while_true,
+                fluent::lint_builtin_while_true,
                             |lint| {
                     lint.span_suggestion_short(
                         condition_span,
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         format!(
                             "{}loop",
                             label.map_or_else(String::new, |label| format!(
@@ -160,7 +160,7 @@ impl BoxPointers {
                     cx.struct_span_lint(
                         BOX_POINTERS,
                         span,
-                        fluent::lint::builtin_box_pointers,
+                        fluent::lint_builtin_box_pointers,
                         |lint| lint.set_arg("ty", ty),
                     );
                 }
@@ -264,13 +264,13 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
                         cx.struct_span_lint(
                             NON_SHORTHAND_FIELD_PATTERNS,
                             fieldpat.span,
-                            fluent::lint::builtin_non_shorthand_field_patterns,
+                            fluent::lint_builtin_non_shorthand_field_patterns,
                             |lint| {
                                 let suggested_ident =
                                     format!("{}{}", binding_annot.prefix_str(), ident);
                                 lint.set_arg("ident", ident.clone()).span_suggestion(
                                     fieldpat.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     suggested_ident,
                                     Applicability::MachineApplicable,
                                 )
@@ -335,7 +335,7 @@ impl UnsafeCode {
         msg: DiagnosticMessage,
     ) {
         self.report_unsafe(cx, span, msg, |lint| {
-            lint.note(fluent::lint::builtin_overridden_symbol_name)
+            lint.note(fluent::lint_builtin_overridden_symbol_name)
         })
     }
 
@@ -346,7 +346,7 @@ impl UnsafeCode {
         msg: DiagnosticMessage,
     ) {
         self.report_unsafe(cx, span, msg, |lint| {
-            lint.note(fluent::lint::builtin_overridden_symbol_section)
+            lint.note(fluent::lint_builtin_overridden_symbol_section)
         })
     }
 }
@@ -354,12 +354,9 @@ impl UnsafeCode {
 impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         if attr.has_name(sym::allow_internal_unsafe) {
-            self.report_unsafe(
-                cx,
-                attr.span,
-                fluent::lint::builtin_allow_internal_unsafe,
-                |lint| lint,
-            );
+            self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| {
+                lint
+            });
         }
     }
 
@@ -367,7 +364,7 @@ impl EarlyLintPass for UnsafeCode {
         if let ast::ExprKind::Block(ref blk, _) = e.kind {
             // Don't warn about generated blocks; that'll just pollute the output.
             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
-                self.report_unsafe(cx, blk.span, fluent::lint::builtin_unsafe_block, |lint| lint);
+                self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint);
             }
         }
     }
@@ -375,11 +372,11 @@ impl EarlyLintPass for UnsafeCode {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
             ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
-                self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_trait, |lint| lint)
+                self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint)
             }
 
             ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
-                self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_impl, |lint| lint)
+                self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint)
             }
 
             ast::ItemKind::Fn(..) => {
@@ -387,7 +384,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_no_mangle_fn,
+                        fluent::lint_builtin_no_mangle_fn,
                     );
                 }
 
@@ -395,7 +392,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_export_name_fn,
+                        fluent::lint_builtin_export_name_fn,
                     );
                 }
 
@@ -403,7 +400,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_section(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_link_section_fn,
+                        fluent::lint_builtin_link_section_fn,
                     );
                 }
             }
@@ -413,7 +410,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_no_mangle_static,
+                        fluent::lint_builtin_no_mangle_static,
                     );
                 }
 
@@ -421,7 +418,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_export_name_static,
+                        fluent::lint_builtin_export_name_static,
                     );
                 }
 
@@ -429,7 +426,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_section(
                         cx,
                         attr.span,
-                        fluent::lint::builtin_link_section_static,
+                        fluent::lint_builtin_link_section_static,
                     );
                 }
             }
@@ -444,14 +441,14 @@ impl EarlyLintPass for UnsafeCode {
                 self.report_overridden_symbol_name(
                     cx,
                     attr.span,
-                    fluent::lint::builtin_no_mangle_method,
+                    fluent::lint_builtin_no_mangle_method,
                 );
             }
             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
                 self.report_overridden_symbol_name(
                     cx,
                     attr.span,
-                    fluent::lint::builtin_export_name_method,
+                    fluent::lint_builtin_export_name_method,
                 );
             }
         }
@@ -469,9 +466,9 @@ impl EarlyLintPass for UnsafeCode {
         {
             let msg = match ctxt {
                 FnCtxt::Foreign => return,
-                FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
-                FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
-                FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
+                FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn,
+                FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method,
+                FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method,
             };
             self.report_unsafe(cx, span, msg, |lint| lint);
         }
@@ -577,7 +574,7 @@ impl MissingDoc {
             cx.struct_span_lint(
                 MISSING_DOCS,
                 cx.tcx.def_span(def_id),
-                fluent::lint::builtin_missing_doc,
+                fluent::lint_builtin_missing_doc,
                 |lint| lint.set_arg("article", article).set_arg("desc", desc),
             );
         }
@@ -769,7 +766,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             cx.struct_span_lint(
                 MISSING_COPY_IMPLEMENTATIONS,
                 item.span,
-                fluent::lint::builtin_missing_copy_impl,
+                fluent::lint_builtin_missing_copy_impl,
                 |lint| lint,
             )
         }
@@ -848,7 +845,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             cx.struct_span_lint(
                 MISSING_DEBUG_IMPLEMENTATIONS,
                 item.span,
-                fluent::lint::builtin_missing_debug_impl,
+                fluent::lint_builtin_missing_debug_impl,
                 |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
             );
         }
@@ -928,11 +925,11 @@ impl EarlyLintPass for AnonymousParameters {
                         cx.struct_span_lint(
                             ANONYMOUS_PARAMETERS,
                             arg.pat.span,
-                            fluent::lint::builtin_anonymous_params,
+                            fluent::lint_builtin_anonymous_params,
                             |lint| {
                                 lint.span_suggestion(
                                     arg.pat.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     format!("_: {}", ty_snip),
                                     appl,
                                 )
@@ -976,7 +973,7 @@ impl EarlyLintPass for DeprecatedAttr {
                     cx.struct_span_lint(
                         DEPRECATED,
                         attr.span,
-                        fluent::lint::builtin_deprecated_attr_link,
+                        fluent::lint_builtin_deprecated_attr_link,
                         |lint| {
                             lint.set_arg("name", name)
                                 .set_arg("reason", reason)
@@ -984,7 +981,7 @@ impl EarlyLintPass for DeprecatedAttr {
                                 .span_suggestion_short(
                                     attr.span,
                                     suggestion.map(|s| s.into()).unwrap_or(
-                                        fluent::lint::builtin_deprecated_attr_default_suggestion,
+                                        fluent::lint_builtin_deprecated_attr_default_suggestion,
                                     ),
                                     "",
                                     Applicability::MachineApplicable,
@@ -999,12 +996,12 @@ impl EarlyLintPass for DeprecatedAttr {
             cx.struct_span_lint(
                 DEPRECATED,
                 attr.span,
-                fluent::lint::builtin_deprecated_attr_used,
+                fluent::lint_builtin_deprecated_attr_used,
                 |lint| {
                     lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
                         .span_suggestion_short(
                             attr.span,
-                            fluent::lint::builtin_deprecated_attr_default_suggestion,
+                            fluent::lint_builtin_deprecated_attr_default_suggestion,
                             "",
                             Applicability::MachineApplicable,
                         )
@@ -1039,14 +1036,14 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
             cx.struct_span_lint(
                 UNUSED_DOC_COMMENTS,
                 span,
-                fluent::lint::builtin_unused_doc_comment,
+                fluent::lint_builtin_unused_doc_comment,
                 |lint| {
-                    lint.set_arg("kind", node_kind).span_label(node_span, fluent::lint::label).help(
+                    lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help(
                         match attr.kind {
                             AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
-                                fluent::lint::plain_help
+                                fluent::plain_help
                             }
-                            AttrKind::DocComment(CommentKind::Block, _) => fluent::lint::block_help,
+                            AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help,
                         },
                     )
                 },
@@ -1167,11 +1164,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                         cx.struct_span_lint(
                             NO_MANGLE_GENERIC_ITEMS,
                             span,
-                            fluent::lint::builtin_no_mangle_generic,
+                            fluent::lint_builtin_no_mangle_generic,
                             |lint| {
                                 lint.span_suggestion_short(
                                     no_mangle_attr.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     "",
                                     // Use of `#[no_mangle]` suggests FFI intent; correct
                                     // fix may be to monomorphize source by hand
@@ -1197,7 +1194,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                     cx.struct_span_lint(
                         NO_MANGLE_CONST_ITEMS,
                         it.span,
-                        fluent::lint::builtin_const_no_mangle,
+                        fluent::lint_builtin_const_no_mangle,
                         |lint| {
                             // account for "pub const" (#45562)
                             let start = cx
@@ -1211,7 +1208,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                             let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
                             lint.span_suggestion(
                                 const_span,
-                                fluent::lint::suggestion,
+                                fluent::suggestion,
                                 "pub static",
                                 Applicability::MachineApplicable,
                             )
@@ -1279,7 +1276,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
                 cx.struct_span_lint(
                     MUTABLE_TRANSMUTES,
                     expr.span,
-                    fluent::lint::builtin_mutable_transmutes,
+                    fluent::lint_builtin_mutable_transmutes,
                     |lint| lint,
                 );
             }
@@ -1332,7 +1329,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
                     cx.struct_span_lint(
                         UNSTABLE_FEATURES,
                         item.span(),
-                        fluent::lint::builtin_unstable_features,
+                        fluent::lint_builtin_unstable_features,
                         |lint| lint,
                     );
                 }
@@ -1396,18 +1393,13 @@ impl UnreachablePub {
             cx.struct_span_lint(
                 UNREACHABLE_PUB,
                 def_span,
-                fluent::lint::builtin_unreachable_pub,
+                fluent::lint_builtin_unreachable_pub,
                 |lint| {
                     lint.set_arg("what", what);
 
-                    lint.span_suggestion(
-                        vis_span,
-                        fluent::lint::suggestion,
-                        "pub(crate)",
-                        applicability,
-                    );
+                    lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability);
                     if exportable {
-                        lint.help(fluent::lint::help);
+                        lint.help(fluent::help);
                     }
                     lint
                 },
@@ -1498,7 +1490,7 @@ impl TypeAliasBounds {
         impl Visitor<'_> for WalkAssocTypes<'_> {
             fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
-                    self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
+                    self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
                 }
                 intravisit::walk_qpath(self, qpath, id)
             }
@@ -1541,11 +1533,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
 
         let mut suggested_changing_assoc_types = false;
         if !where_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_where_clause, |lint| {
+            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| {
                 lint.set_span(where_spans);
                 lint.span_suggestion(
                     type_alias_generics.where_clause_span,
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     "",
                     Applicability::MachineApplicable,
                 );
@@ -1558,10 +1550,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
         }
 
         if !inline_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_generic_bounds, |lint| {
+            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| {
                 lint.set_span(inline_spans);
                 lint.multipart_suggestion(
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     inline_sugg,
                     Applicability::MachineApplicable,
                 );
@@ -1670,7 +1662,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     cx.struct_span_lint(
                         TRIVIAL_BOUNDS,
                         span,
-                        fluent::lint::builtin_trivial_bounds,
+                        fluent::lint_builtin_trivial_bounds,
                         |lint| {
                             lint.set_arg("predicate_kind_name", predicate_kind_name)
                                 .set_arg("predicate", predicate)
@@ -1775,8 +1767,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
         };
 
         if let Some((start, end, join)) = endpoints {
-            let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
-            let suggestion = fluent::lint::suggestion;
+            let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns;
+            let suggestion = fluent::suggestion;
             if parenthesise {
                 self.node_id = Some(pat.id);
                 let end = expr_to_string(&end);
@@ -1899,7 +1891,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
             cx.struct_span_lint(
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
-                fluent::lint::builtin_unnameable_test_items,
+                fluent::lint_builtin_unnameable_test_items,
                 |lint| lint,
             );
         }
@@ -2020,11 +2012,11 @@ impl KeywordIdents {
         cx.struct_span_lint(
             KEYWORD_IDENTS,
             ident.span,
-            fluent::lint::builtin_keyword_idents,
+            fluent::lint_builtin_keyword_idents,
             |lint| {
                 lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
                     ident.span,
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     format!("r#{}", ident),
                     Applicability::MachineApplicable,
                 )
@@ -2283,10 +2275,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                 cx.struct_span_lint(
                     EXPLICIT_OUTLIVES_REQUIREMENTS,
                     lint_spans.clone(),
-                    fluent::lint::builtin_explicit_outlives,
+                    fluent::lint_builtin_explicit_outlives,
                     |lint| {
                         lint.set_arg("count", bound_count).multipart_suggestion(
-                            fluent::lint::suggestion,
+                            fluent::suggestion,
                             lint_spans
                                 .into_iter()
                                 .map(|span| (span, String::new()))
@@ -2344,17 +2336,17 @@ impl EarlyLintPass for IncompleteFeatures {
                 cx.struct_span_lint(
                     INCOMPLETE_FEATURES,
                     span,
-                    fluent::lint::builtin_incomplete_features,
+                    fluent::lint_builtin_incomplete_features,
                     |lint| {
                         lint.set_arg("name", name);
                         if let Some(n) =
                             rustc_feature::find_feature_issue(name, GateIssue::Language)
                         {
                             lint.set_arg("n", n);
-                            lint.note(fluent::lint::note);
+                            lint.note(fluent::note);
                         }
                         if HAS_MIN_FEATURES.contains(&name) {
-                            lint.help(fluent::lint::help);
+                            lint.help(fluent::help);
                         }
                         lint
                     },
@@ -2467,42 +2459,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             None
         }
 
-        /// Determines whether the given type is inhabited. `None` means that we don't know.
-        fn ty_inhabited<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<bool> {
-            use rustc_type_ir::sty::TyKind::*;
-            if !cx.tcx.type_uninhabited_from(cx.param_env.and(ty)).is_empty() {
-                // This is definitely uninhabited from some module.
-                return Some(false);
-            }
-            match ty.kind() {
-                Never => Some(false),
-                Int(_) | Uint(_) | Float(_) | Bool | Char | RawPtr(_) => Some(true),
-                // Fallback for more complicated types. (Note that `&!` might be considered
-                // uninhabited so references are "complicated", too.)
-                _ => None,
-            }
-        }
-        /// Determines whether a product type formed from a list of types is inhabited.
-        fn tys_inhabited<'tcx>(
-            cx: &LateContext<'tcx>,
-            tys: impl Iterator<Item = Ty<'tcx>>,
-        ) -> Option<bool> {
-            let mut definitely_inhabited = true; // with no fields, we are definitely inhabited.
-            for ty in tys {
-                match ty_inhabited(cx, ty) {
-                    // If any type is uninhabited, the product is uninhabited.
-                    Some(false) => return Some(false),
-                    // Otherwise go searching for a `None`.
-                    None => {
-                        // We don't know.
-                        definitely_inhabited = false;
-                    }
-                    Some(true) => {}
-                }
-            }
-            if definitely_inhabited { Some(true) } else { None }
-        }
-
         fn variant_find_init_error<'tcx>(
             cx: &LateContext<'tcx>,
             variant: &VariantDef,
@@ -2570,7 +2526,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         // return `Bound::Excluded`.  (And we have tests checking that we
                         // handle the attribute correctly.)
                         // We don't add a span since users cannot declare such types anyway.
-                        (Bound::Included(lo), _) if lo > 0 => {
+                        (Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => {
+                            return Some((format!("`{}` must be non-null", ty), None));
+                        }
+                        (Bound::Included(lo), Bound::Unbounded) if 0 < lo => {
                             return Some((format!("`{}` must be non-null", ty), None));
                         }
                         (Bound::Included(_), _) | (_, Bound::Included(_))
@@ -2599,11 +2558,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                     // And now, enums.
                     let span = cx.tcx.def_span(adt_def.did());
                     let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
-                        let inhabited = tys_inhabited(
-                            cx,
-                            variant.fields.iter().map(|field| field.ty(cx.tcx, substs)),
-                        );
-                        let definitely_inhabited = match inhabited {
+                        let definitely_inhabited = match variant
+                            .inhabited_predicate(cx.tcx, *adt_def)
+                            .subst(cx.tcx, substs)
+                            .apply_any_module(cx.tcx, cx.param_env)
+                        {
                             // Entirely skip uninhbaited variants.
                             Some(false) => return None,
                             // Forward the others, but remember which ones are definitely inhabited.
@@ -3051,9 +3010,9 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
                     // Finally, emit the diagnostic.
 
                     let msg = if orig.get_name() == this_fi.ident.name {
-                        fluent::lint::builtin_clashing_extern_same_name
+                        fluent::lint_builtin_clashing_extern_same_name
                     } else {
-                        fluent::lint::builtin_clashing_extern_diff_name
+                        fluent::lint_builtin_clashing_extern_diff_name
                     };
                     tcx.struct_span_lint_hir(
                         CLASHING_EXTERN_DECLARATIONS,
@@ -3068,14 +3027,8 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
 
                             lint.set_arg("this_fi", this_fi.ident.name)
                                 .set_arg("orig", orig.get_name())
-                                .span_label(
-                                    get_relevant_span(orig_fi),
-                                    fluent::lint::previous_decl_label,
-                                )
-                                .span_label(
-                                    get_relevant_span(this_fi),
-                                    fluent::lint::mismatch_label,
-                                )
+                                .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label)
+                                .span_label(get_relevant_span(this_fi), fluent::mismatch_label)
                                 // FIXME(davidtwco): translatable expected/found
                                 .note_expected_found(&"", expected_str, &"", found_str)
                         },
@@ -3161,8 +3114,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
                 cx.struct_span_lint(
                     DEREF_NULLPTR,
                     expr.span,
-                    fluent::lint::builtin_deref_nullptr,
-                    |lint| lint.span_label(expr.span, fluent::lint::label),
+                    fluent::lint_builtin_deref_nullptr,
+                    |lint| lint.span_label(expr.span, fluent::label),
                 );
             }
         }
@@ -3176,6 +3129,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![feature(asm_experimental_arch)]
     /// use std::arch::asm;
     ///
     /// fn main() {
@@ -3273,7 +3227,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                     cx.lookup_with_diagnostics(
                             NAMED_ASM_LABELS,
                             Some(target_spans),
-                            fluent::lint::builtin_asm_labels,
+                            fluent::lint_builtin_asm_labels,
                             |lint| lint,
                             BuiltinLintDiagnostics::NamedAsmLabel(
                                 "only local labels of the form `<number>:` should be used in inline asm"
@@ -3376,8 +3330,8 @@ impl EarlyLintPass for UnexpectedCfgs {
                     cx.lookup(
                         UNEXPECTED_CFGS,
                         None::<MultiSpan>,
-                        fluent::lint::builtin_unexpected_cli_config_name,
-                        |diag| diag.help(fluent::lint::help).set_arg("name", name),
+                        fluent::lint_builtin_unexpected_cli_config_name,
+                        |diag| diag.help(fluent::help).set_arg("name", name),
                     );
                 }
             }
@@ -3387,9 +3341,9 @@ impl EarlyLintPass for UnexpectedCfgs {
                         cx.lookup(
                             UNEXPECTED_CFGS,
                             None::<MultiSpan>,
-                            fluent::lint::builtin_unexpected_cli_config_value,
+                            fluent::lint_builtin_unexpected_cli_config_value,
                             |diag| {
-                                diag.help(fluent::lint::help)
+                                diag.help(fluent::help)
                                     .set_arg("name", name)
                                     .set_arg("value", value)
                             },
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 74e35afc87d..63a11877333 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -574,6 +574,11 @@ pub trait LintContext: Sized {
     fn sess(&self) -> &Session;
     fn lints(&self) -> &LintStore;
 
+    /// Emit a lint at the appropriate level, with an optional associated span and an existing diagnostic.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn lookup_with_diagnostics(
         &self,
         lint: &'static Lint,
@@ -872,6 +877,11 @@ pub trait LintContext: Sized {
 
     // FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
     // set the span in their `decorate` function (preferably using set_span).
+    /// Emit a lint at the appropriate level, with an optional associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -893,6 +903,11 @@ pub trait LintContext: Sized {
         self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag));
     }
 
+    /// Emit a lint at the appropriate level, with an associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn struct_span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -914,6 +929,10 @@ pub trait LintContext: Sized {
     }
 
     /// Emit a lint at the appropriate level, with no associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     fn lint(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index e8d307814b9..f9d7466228a 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -53,8 +53,8 @@ fn enforce_mem_discriminant(
         cx.struct_span_lint(
             ENUM_INTRINSICS_NON_ENUMS,
             expr_span,
-            fluent::lint::enum_intrinsics_mem_discriminant,
-            |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::lint::note),
+            fluent::lint_enum_intrinsics_mem_discriminant,
+            |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note),
         );
     }
 }
@@ -65,8 +65,8 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp
         cx.struct_span_lint(
             ENUM_INTRINSICS_NON_ENUMS,
             span,
-            fluent::lint::enum_intrinsics_mem_variant,
-            |lint| lint.set_arg("ty_param", ty_param).note(fluent::lint::note),
+            fluent::lint_enum_intrinsics_mem_variant,
+            |lint| lint.set_arg("ty_param", ty_param).note(fluent::note),
         );
     }
 }
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 97d012fb611..a49d1bdacc2 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -7,7 +7,7 @@ use rustc_session::lint::Level;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(lint::overruled_attribute, code = "E0453")]
+#[diag(lint_overruled_attribute, code = "E0453")]
 pub struct OverruledAttribute {
     #[primary_span]
     pub span: Span,
@@ -32,24 +32,24 @@ impl AddToDiagnostic for OverruledAttributeSub {
     {
         match self {
             OverruledAttributeSub::DefaultSource { id } => {
-                diag.note(fluent::lint::default_source);
+                diag.note(fluent::lint_default_source);
                 diag.set_arg("id", id);
             }
             OverruledAttributeSub::NodeSource { span, reason } => {
-                diag.span_label(span, fluent::lint::node_source);
+                diag.span_label(span, fluent::lint_node_source);
                 if let Some(rationale) = reason {
                     diag.note(rationale.as_str());
                 }
             }
             OverruledAttributeSub::CommandLineSource => {
-                diag.note(fluent::lint::command_line_source);
+                diag.note(fluent::lint_command_line_source);
             }
         }
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::malformed_attribute, code = "E0452")]
+#[diag(lint_malformed_attribute, code = "E0452")]
 pub struct MalformedAttribute {
     #[primary_span]
     pub span: Span,
@@ -59,16 +59,16 @@ pub struct MalformedAttribute {
 
 #[derive(Subdiagnostic)]
 pub enum MalformedAttributeSub {
-    #[label(lint::bad_attribute_argument)]
+    #[label(lint_bad_attribute_argument)]
     BadAttributeArgument(#[primary_span] Span),
-    #[label(lint::reason_must_be_string_literal)]
+    #[label(lint_reason_must_be_string_literal)]
     ReasonMustBeStringLiteral(#[primary_span] Span),
-    #[label(lint::reason_must_come_last)]
+    #[label(lint_reason_must_come_last)]
     ReasonMustComeLast(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")]
+#[diag(lint_unknown_tool_in_scoped_lint, code = "E0710")]
 pub struct UnknownToolInScopedLint {
     #[primary_span]
     pub span: Option<Span>,
@@ -79,7 +79,7 @@ pub struct UnknownToolInScopedLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
+#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
 pub struct BuiltinEllpisisInclusiveRangePatterns {
     #[primary_span]
     pub span: Span,
@@ -88,36 +88,15 @@ pub struct BuiltinEllpisisInclusiveRangePatterns {
     pub replace: String,
 }
 
+#[derive(Subdiagnostic)]
+#[note(lint_requested_level)]
 pub struct RequestedLevel {
     pub level: Level,
     pub lint_name: String,
 }
 
-impl AddToDiagnostic for RequestedLevel {
-    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
-    where
-        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
-    {
-        diag.note(fluent::lint::requested_level);
-        diag.set_arg(
-            "level",
-            match self.level {
-                Level::Allow => "-A",
-                Level::Warn => "-W",
-                Level::ForceWarn(_) => "--force-warn",
-                Level::Deny => "-D",
-                Level::Forbid => "-F",
-                Level::Expect(_) => {
-                    unreachable!("lints with the level of `expect` should not run this code");
-                }
-            },
-        );
-        diag.set_arg("lint_name", self.lint_name);
-    }
-}
-
 #[derive(Diagnostic)]
-#[diag(lint::unsupported_group, code = "E0602")]
+#[diag(lint_unsupported_group, code = "E0602")]
 pub struct UnsupportedGroup {
     pub lint_group: String,
 }
@@ -133,10 +112,10 @@ impl IntoDiagnostic<'_> for CheckNameUnknown {
         self,
         handler: &Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::lint::check_name_unknown);
+        let mut diag = handler.struct_err(fluent::lint_check_name_unknown);
         diag.code(rustc_errors::error_code!(E0602));
         if let Some(suggestion) = self.suggestion {
-            diag.help(fluent::lint::help);
+            diag.help(fluent::help);
             diag.set_arg("suggestion", suggestion);
         }
         diag.set_arg("lint_name", self.lint_name);
@@ -146,7 +125,7 @@ impl IntoDiagnostic<'_> for CheckNameUnknown {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::check_name_unknown_tool, code = "E0602")]
+#[diag(lint_check_name_unknown_tool, code = "E0602")]
 pub struct CheckNameUnknownTool {
     pub tool_name: Symbol,
     #[subdiagnostic]
@@ -154,7 +133,7 @@ pub struct CheckNameUnknownTool {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::check_name_warning)]
+#[diag(lint_check_name_warning)]
 pub struct CheckNameWarning {
     pub msg: String,
     #[subdiagnostic]
@@ -162,7 +141,7 @@ pub struct CheckNameWarning {
 }
 
 #[derive(Diagnostic)]
-#[diag(lint::check_name_deprecated)]
+#[diag(lint_check_name_deprecated)]
 pub struct CheckNameDeprecated {
     pub lint_name: String,
     pub new_name: String,
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 4c3c39734dd..cf8f31bcbd0 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -45,14 +45,14 @@ fn emit_unfulfilled_expectation_lint(
         builtin::UNFULFILLED_LINT_EXPECTATIONS,
         hir_id,
         expectation.emission_span,
-        fluent::lint::expectation,
+        fluent::lint_expectation,
         |lint| {
             if let Some(rationale) = expectation.reason {
                 lint.note(rationale.as_str());
             }
 
             if expectation.is_unfulfilled_lint_expectations {
-                lint.note(fluent::lint::note);
+                lint.note(fluent::note);
             }
 
             lint
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index 42557068bd3..7e884e990ce 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -63,12 +63,12 @@ impl HiddenUnicodeCodepoints {
         cx.struct_span_lint(
             TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
             span,
-            fluent::lint::hidden_unicode_codepoints,
+            fluent::lint_hidden_unicode_codepoints,
             |lint| {
                 lint.set_arg("label", label);
                 lint.set_arg("count", spans.len());
-                lint.span_label(span, fluent::lint::label);
-                lint.note(fluent::lint::note);
+                lint.span_label(span, fluent::label);
+                lint.note(fluent::note);
                 if point_at_inner_spans {
                     for (c, span) in &spans {
                         lint.span_label(*span, format!("{:?}", c));
@@ -76,13 +76,13 @@ impl HiddenUnicodeCodepoints {
                 }
                 if point_at_inner_spans && !spans.is_empty() {
                     lint.multipart_suggestion_with_style(
-                        fluent::lint::suggestion_remove,
+                        fluent::suggestion_remove,
                         spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
                         Applicability::MachineApplicable,
                         SuggestionStyle::HideCodeAlways,
                     );
                     lint.multipart_suggestion(
-                        fluent::lint::suggestion_escape,
+                        fluent::suggestion_escape,
                         spans
                             .into_iter()
                             .map(|(c, span)| {
@@ -104,8 +104,8 @@ impl HiddenUnicodeCodepoints {
                             .collect::<Vec<String>>()
                             .join(", "),
                     );
-                    lint.note(fluent::lint::suggestion_remove);
-                    lint.note(fluent::lint::no_suggestion_note_escape);
+                    lint.note(fluent::suggestion_remove);
+                    lint.note(fluent::no_suggestion_note_escape);
                 }
                 lint
             },
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 8f5e38fdbcc..11e4650cb4b 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -37,11 +37,11 @@ impl LateLintPass<'_> for DefaultHashTypes {
         cx.struct_span_lint(
             DEFAULT_HASH_TYPES,
             path.span,
-            fluent::lint::default_hash_types,
+            fluent::lint_default_hash_types,
             |lint| {
                 lint.set_arg("preferred", replace)
                     .set_arg("used", cx.tcx.item_name(def_id))
-                    .note(fluent::lint::note)
+                    .note(fluent::note)
             },
         );
     }
@@ -86,8 +86,8 @@ impl LateLintPass<'_> for QueryStability {
                 cx.struct_span_lint(
                     POTENTIAL_QUERY_INSTABILITY,
                     span,
-                    fluent::lint::query_instability,
-                    |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::lint::note),
+                    fluent::lint_query_instability,
+                    |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note),
                 )
             }
         }
@@ -126,11 +126,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
             let span = path.span.with_hi(
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
             );
-            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint::tykind_kind, |lint| {
+            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| {
                 lint
                     .span_suggestion(
                         span,
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         "ty",
                         Applicability::MaybeIncorrect, // ty maybe needs an import
                     )
@@ -193,10 +193,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                             cx.struct_span_lint(
                                 USAGE_OF_TY_TYKIND,
                                 path.span,
-                                fluent::lint::tykind_kind,
+                                fluent::lint_tykind_kind,
                                 |lint| lint.span_suggestion(
                                     span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     "ty",
                                     Applicability::MaybeIncorrect, // ty maybe needs an import
                                 )
@@ -205,18 +205,18 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                         None => cx.struct_span_lint(
                             USAGE_OF_TY_TYKIND,
                             path.span,
-                            fluent::lint::tykind,
-                            |lint| lint.help(fluent::lint::help)
+                            fluent::lint_tykind,
+                            |lint| lint.help(fluent::help)
                         )
                     }
                 } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
                     if path.segments.len() > 1 {
-                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint::ty_qualified, |lint| {
+                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| {
                             lint
                                 .set_arg("ty", t.clone())
                                 .span_suggestion(
                                     path.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     t,
                                     // The import probably needs to be changed
                                     Applicability::MaybeIncorrect,
@@ -310,8 +310,8 @@ impl EarlyLintPass for LintPassImpl {
                         cx.struct_span_lint(
                             LINT_PASS_IMPL_WITHOUT_MACRO,
                             lint_pass.path.span,
-                            fluent::lint::lintpass_by_hand,
-                            |lint| lint.help(fluent::lint::help),
+                            fluent::lint_lintpass_by_hand,
+                            |lint| lint.help(fluent::help),
                         )
                     }
                 }
@@ -351,8 +351,8 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
                         cx.struct_span_lint(
                             EXISTING_DOC_KEYWORD,
                             attr.span,
-                            fluent::lint::non_existant_doc_keyword,
-                            |lint| lint.set_arg("keyword", v).help(fluent::lint::help),
+                            fluent::lint_non_existant_doc_keyword,
+                            |lint| lint.set_arg("keyword", v).help(fluent::help),
                         );
                     }
                 }
@@ -414,7 +414,7 @@ impl LateLintPass<'_> for Diagnostics {
             cx.struct_span_lint(
                 DIAGNOSTIC_OUTSIDE_OF_IMPL,
                 span,
-                fluent::lint::diag_out_of_impl,
+                fluent::lint_diag_out_of_impl,
                 |lint| lint,
             )
         }
@@ -435,7 +435,7 @@ impl LateLintPass<'_> for Diagnostics {
             cx.struct_span_lint(
                 UNTRANSLATABLE_DIAGNOSTIC,
                 span,
-                fluent::lint::untranslatable_diag,
+                fluent::lint_untranslatable_diag,
                 |lint| lint,
             )
         }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index be1d7d98aa6..db0a3419e6a 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -960,7 +960,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                                         sp,
                                         "did you mean",
                                         suggestion,
-                                        Applicability::MachineApplicable,
+                                        Applicability::MaybeIncorrect,
                                     );
                                 }
                                 lint
@@ -1069,6 +1069,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
 
     /// Used to emit a lint-related diagnostic based on the current state of
     /// this lint context.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     pub(crate) fn struct_lint(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index 313119637bc..e2d7d5b49f6 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -93,12 +93,12 @@ fn lint_cstring_as_ptr(
                     cx.struct_span_lint(
                         TEMPORARY_CSTRING_AS_PTR,
                         as_ptr_span,
-                        fluent::lint::cstring_ptr,
+                        fluent::lint_cstring_ptr,
                         |diag| {
-                            diag.span_label(as_ptr_span, fluent::lint::as_ptr_label)
-                                .span_label(unwrap.span, fluent::lint::unwrap_label)
-                                .note(fluent::lint::note)
-                                .help(fluent::lint::help)
+                            diag.span_label(as_ptr_span, fluent::as_ptr_label)
+                                .span_label(unwrap.span, fluent::unwrap_label)
+                                .note(fluent::note)
+                                .help(fluent::help)
                         },
                     );
                 }
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index b2626efb6d7..dea9506acb2 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -183,7 +183,7 @@ impl EarlyLintPass for NonAsciiIdents {
             cx.struct_span_lint(
                 NON_ASCII_IDENTS,
                 sp,
-                fluent::lint::identifier_non_ascii_char,
+                fluent::lint_identifier_non_ascii_char,
                 |lint| lint,
             );
             if check_uncommon_codepoints
@@ -192,7 +192,7 @@ impl EarlyLintPass for NonAsciiIdents {
                 cx.struct_span_lint(
                     UNCOMMON_CODEPOINTS,
                     sp,
-                    fluent::lint::identifier_uncommon_codepoints,
+                    fluent::lint_identifier_uncommon_codepoints,
                     |lint| lint,
                 )
             }
@@ -225,11 +225,11 @@ impl EarlyLintPass for NonAsciiIdents {
                             cx.struct_span_lint(
                                 CONFUSABLE_IDENTS,
                                 sp,
-                                fluent::lint::confusable_identifier_pair,
+                                fluent::lint_confusable_identifier_pair,
                                 |lint| {
                                     lint.set_arg("existing_sym", *existing_symbol)
                                         .set_arg("sym", symbol)
-                                        .span_label(*existing_span, fluent::lint::label)
+                                        .span_label(*existing_span, fluent::label)
                                 },
                             );
                         }
@@ -334,7 +334,7 @@ impl EarlyLintPass for NonAsciiIdents {
                     cx.struct_span_lint(
                         MIXED_SCRIPT_CONFUSABLES,
                         sp,
-                        fluent::lint::mixed_script_confusables,
+                        fluent::lint_mixed_script_confusables,
                         |lint| {
                             let mut includes = String::new();
                             for (idx, ch) in ch_list.into_iter().enumerate() {
@@ -346,8 +346,8 @@ impl EarlyLintPass for NonAsciiIdents {
                             }
                             lint.set_arg("set", script_set.to_string())
                                 .set_arg("includes", includes)
-                                .note(fluent::lint::includes_note)
-                                .note(fluent::lint::note)
+                                .note(fluent::includes_note)
+                                .note(fluent::note)
                         },
                     );
                 }
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 886b686e5e8..6ad2e0294b9 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -119,20 +119,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
         arg_span = expn.call_site;
     }
 
-    cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint::non_fmt_panic, |lint| {
+    cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
         lint.set_arg("name", symbol);
-        lint.note(fluent::lint::note);
-        lint.note(fluent::lint::more_info_note);
+        lint.note(fluent::note);
+        lint.note(fluent::more_info_note);
         if !is_arg_inside_call(arg_span, span) {
             // No clue where this argument is coming from.
             return lint;
         }
         if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
             // A case of `panic!(format!(..))`.
-            lint.note(fluent::lint::supports_fmt_note);
+            lint.note(fluent::supports_fmt_note);
             if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
                 lint.multipart_suggestion(
-                    fluent::lint::supports_fmt_suggestion,
+                    fluent::supports_fmt_suggestion,
                     vec![
                         (arg_span.until(open.shrink_to_hi()), "".into()),
                         (close.until(arg_span.shrink_to_hi()), "".into()),
@@ -178,7 +178,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
             if suggest_display {
                 lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    fluent::lint::display_suggestion,
+                    fluent::display_suggestion,
                     "\"{}\", ",
                     fmt_applicability,
                 );
@@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 lint.set_arg("ty", ty);
                 lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    fluent::lint::debug_suggestion,
+                    fluent::debug_suggestion,
                     "\"{:?}\", ",
                     fmt_applicability,
                 );
@@ -196,7 +196,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 if let Some((open, close, del)) = find_delimiters(cx, span) {
                     lint.set_arg("already_suggested", suggest_display || suggest_debug);
                     lint.multipart_suggestion(
-                        fluent::lint::panic_suggestion,
+                        fluent::panic_suggestion,
                         if del == '(' {
                             vec![(span.until(open), "std::panic::panic_any".into())]
                         } else {
@@ -254,30 +254,25 @@ fn check_panic_str<'tcx>(
                 .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
                 .collect(),
         };
-        cx.struct_span_lint(
-            NON_FMT_PANICS,
-            arg_spans,
-            fluent::lint::non_fmt_panic_unused,
-            |lint| {
-                lint.set_arg("count", n_arguments);
-                lint.note(fluent::lint::note);
-                if is_arg_inside_call(arg.span, span) {
-                    lint.span_suggestion(
-                        arg.span.shrink_to_hi(),
-                        fluent::lint::add_args_suggestion,
-                        ", ...",
-                        Applicability::HasPlaceholders,
-                    );
-                    lint.span_suggestion(
-                        arg.span.shrink_to_lo(),
-                        fluent::lint::add_fmt_suggestion,
-                        "\"{}\", ",
-                        Applicability::MachineApplicable,
-                    );
-                }
-                lint
-            },
-        );
+        cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| {
+            lint.set_arg("count", n_arguments);
+            lint.note(fluent::note);
+            if is_arg_inside_call(arg.span, span) {
+                lint.span_suggestion(
+                    arg.span.shrink_to_hi(),
+                    fluent::add_args_suggestion,
+                    ", ...",
+                    Applicability::HasPlaceholders,
+                );
+                lint.span_suggestion(
+                    arg.span.shrink_to_lo(),
+                    fluent::add_fmt_suggestion,
+                    "\"{}\", ",
+                    Applicability::MachineApplicable,
+                );
+            }
+            lint
+        });
     } else {
         let brace_spans: Option<Vec<_>> =
             snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
@@ -290,14 +285,14 @@ fn check_panic_str<'tcx>(
         cx.struct_span_lint(
             NON_FMT_PANICS,
             brace_spans.unwrap_or_else(|| vec![span]),
-            fluent::lint::non_fmt_panic_braces,
+            fluent::lint_non_fmt_panic_braces,
             |lint| {
                 lint.set_arg("count", count);
-                lint.note(fluent::lint::note);
+                lint.note(fluent::note);
                 if is_arg_inside_call(arg.span, span) {
                     lint.span_suggestion(
                         arg.span.shrink_to_lo(),
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         "\"{}\", ",
                         Applicability::MachineApplicable,
                     );
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 6b32e78b910..7e50801f80c 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -139,7 +139,7 @@ impl NonCamelCaseTypes {
             cx.struct_span_lint(
                 NON_CAMEL_CASE_TYPES,
                 ident.span,
-                fluent::lint::non_camel_case_type,
+                fluent::lint_non_camel_case_type,
                 |lint| {
                     let cc = to_camel_case(name);
                     // We cannot provide meaningful suggestions
@@ -147,12 +147,12 @@ impl NonCamelCaseTypes {
                     if *name != cc {
                         lint.span_suggestion(
                             ident.span,
-                            fluent::lint::suggestion,
+                            fluent::suggestion,
                             to_camel_case(name),
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        lint.span_label(ident.span, fluent::lint::label);
+                        lint.span_label(ident.span, fluent::label);
                     }
 
                     lint.set_arg("sort", sort);
@@ -284,7 +284,7 @@ impl NonSnakeCase {
         let name = ident.name.as_str();
 
         if !is_snake_case(name) {
-            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint::non_snake_case, |lint| {
+            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| {
                 let sc = NonSnakeCase::to_snake_case(name);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Uppercase Letter".
@@ -298,13 +298,13 @@ impl NonSnakeCase {
                             // Instead, recommend renaming the identifier entirely or, if permitted,
                             // escaping it to create a raw identifier.
                             if sc_ident.name.can_be_raw() {
-                                (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
+                                (fluent::rename_or_convert_suggestion, sc_ident.to_string())
                             } else {
-                                lint.note(fluent::lint::cannot_convert_note);
-                                (fluent::lint::rename_suggestion, String::new())
+                                lint.note(fluent::cannot_convert_note);
+                                (fluent::rename_suggestion, String::new())
                             }
                         } else {
-                            (fluent::lint::convert_suggestion, sc.clone())
+                            (fluent::convert_suggestion, sc.clone())
                         };
 
                         lint.span_suggestion(
@@ -314,10 +314,10 @@ impl NonSnakeCase {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        lint.help(fluent::lint::help);
+                        lint.help(fluent::help);
                     }
                 } else {
-                    lint.span_label(ident.span, fluent::lint::label);
+                    lint.span_label(ident.span, fluent::label);
                 }
 
                 lint.set_arg("sort", sort);
@@ -484,7 +484,7 @@ impl NonUpperCaseGlobals {
             cx.struct_span_lint(
                 NON_UPPER_CASE_GLOBALS,
                 ident.span,
-                fluent::lint::non_upper_case_global,
+                fluent::lint_non_upper_case_global,
                 |lint| {
                     let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
                     // We cannot provide meaningful suggestions
@@ -492,12 +492,12 @@ impl NonUpperCaseGlobals {
                     if *name != uc {
                         lint.span_suggestion(
                             ident.span,
-                            fluent::lint::suggestion,
+                            fluent::suggestion,
                             uc,
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        lint.span_label(ident.span, fluent::lint::label);
+                        lint.span_label(ident.span, fluent::label);
                     }
 
                     lint.set_arg("sort", sort);
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 9a62afd3caf..2ef425a1093 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -85,11 +85,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         }
         let expr_span = expr.span;
         let span = expr_span.with_lo(receiver.span.hi());
-        cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint::noop_method_call, |lint| {
+        cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| {
             lint.set_arg("method", call.ident.name)
                 .set_arg("receiver_ty", receiver_ty)
-                .span_label(span, fluent::lint::label)
-                .note(fluent::lint::note)
+                .span_label(span, fluent::label)
+                .note(fluent::note)
         });
     }
 }
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 81b9f55e703..7f6f4a0abb4 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -91,14 +91,12 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             // For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
             // e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
             // with `impl Send: OtherTrait`.
-            for assoc_pred_and_span in
-                cx.tcx.bound_explicit_item_bounds(proj.projection_ty.item_def_id).transpose_iter()
+            for (assoc_pred, assoc_pred_span) in cx
+                .tcx
+                .bound_explicit_item_bounds(proj.projection_ty.item_def_id)
+                .subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
             {
-                let assoc_pred_span = assoc_pred_and_span.0.1;
-                let assoc_pred = assoc_pred_and_span
-                    .map_bound(|(pred, _)| *pred)
-                    .subst(cx.tcx, &proj.projection_ty.substs)
-                    .fold_with(proj_replacer);
+                let assoc_pred = assoc_pred.fold_with(proj_replacer);
                 let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
                     continue;
                 };
@@ -141,11 +139,11 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint::opaque_hidden_inferred_bound)]
+#[diag(lint_opaque_hidden_inferred_bound)]
 struct OpaqueHiddenInferredBoundLint<'tcx> {
     ty: Ty<'tcx>,
     proj_ty: Ty<'tcx>,
-    #[label(lint::specifically)]
+    #[label(specifically)]
     assoc_pred_span: Span,
     #[subdiagnostic]
     add_bound: Option<AddBound<'tcx>>,
@@ -153,7 +151,7 @@ struct OpaqueHiddenInferredBoundLint<'tcx> {
 
 #[derive(Subdiagnostic)]
 #[suggestion_verbose(
-    lint::opaque_hidden_inferred_bound_sugg,
+    lint_opaque_hidden_inferred_bound_sugg,
     applicability = "machine-applicable",
     code = " + {trait_ref}"
 )]
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 349399b5964..01bface718a 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -32,11 +32,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
                     cx.struct_span_lint(
                         PASS_BY_VALUE,
                         ty.span,
-                        fluent::lint::pass_by_value,
+                        fluent::lint_pass_by_value,
                         |lint| {
                             lint.set_arg("ty", t.clone()).span_suggestion(
                                 ty.span,
-                                fluent::lint::suggestion,
+                                fluent::suggestion,
                                 t,
                                 // Changing type of function argument
                                 Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 46c84550e9f..3521de7fc08 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -51,11 +51,11 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
         cx.struct_span_lint(
             REDUNDANT_SEMICOLONS,
             span,
-            fluent::lint::redundant_semicolons,
+            fluent::lint_redundant_semicolons,
             |lint| {
                 lint.set_arg("multiple", multiple).span_suggestion(
                     span,
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     "",
                     Applicability::MaybeIncorrect,
                 )
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 078465bdce6..a118dda8b40 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                 cx.struct_span_lint(
                     DROP_BOUNDS,
                     span,
-                    fluent::lint::drop_trait_constraints,
+                    fluent::lint_drop_trait_constraints,
                     |lint| {
                         lint.set_arg("predicate", predicate)
                             .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
             if cx.tcx.lang_items().drop_trait() == def_id
                 && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
             {
-                cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint::drop_glue, |lint| {
+                cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| {
                     lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
                 });
             }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b6009bd800a..7c99bb2790f 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -116,8 +116,8 @@ impl TypeLimits {
     }
 }
 
-/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
-/// Returns `true` iff the lint was overridden.
+/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`).
+/// Returns `true` iff the lint was emitted.
 fn lint_overflowing_range_endpoint<'tcx>(
     cx: &LateContext<'tcx>,
     lit: &hir::Lit,
@@ -140,44 +140,46 @@ fn lint_overflowing_range_endpoint<'tcx>(
         return false;
     }
 
-    let mut overwritten = false;
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
     // overflowing and only by 1.
-    if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max
-        && let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span)
-    {
-        cx.struct_span_lint(
-            OVERFLOWING_LITERALS,
-            struct_expr.span,
-            fluent::lint::range_endpoint_out_of_range,
-            |lint| {
-                use ast::{LitIntType, LitKind};
-
-                lint.set_arg("ty", ty);
-
-                // We need to preserve the literal's suffix,
-                // as it may determine typing information.
-                let suffix = match lit.node {
-                    LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
-                    LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
-                    LitKind::Int(_, LitIntType::Unsuffixed) => "",
-                    _ => bug!(),
-                };
-                let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
-                lint.span_suggestion(
-                    struct_expr.span,
-                    fluent::lint::suggestion,
-                    suggestion,
-                    Applicability::MachineApplicable,
-                );
-                overwritten = true;
+    if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
+        return false;
+    };
+    let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
 
-                lint
-            },
-        );
-    }
-    overwritten
+    cx.struct_span_lint(
+        OVERFLOWING_LITERALS,
+        struct_expr.span,
+        fluent::lint_range_endpoint_out_of_range,
+        |lint| {
+            use ast::{LitIntType, LitKind};
+
+            lint.set_arg("ty", ty);
+
+            // We need to preserve the literal's suffix,
+            // as it may determine typing information.
+            let suffix = match lit.node {
+                LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
+                LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
+                LitKind::Int(_, LitIntType::Unsuffixed) => "",
+                _ => bug!(),
+            };
+            let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
+            lint.span_suggestion(
+                struct_expr.span,
+                fluent::suggestion,
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+
+            lint
+        },
+    );
+
+    // We've just emitted a lint, special cased for `(...)..MAX+1` ranges,
+    // return `true` so the callers don't also emit a lint
+    true
 }
 
 // For `isize` & `usize`, be conservative with the warnings, so that the
@@ -231,7 +233,7 @@ fn report_bin_hex_error(
     cx.struct_span_lint(
         OVERFLOWING_LITERALS,
         expr.span,
-        fluent::lint::overflowing_bin_hex,
+        fluent::lint_overflowing_bin_hex,
         |lint| {
             let (t, actually) = match ty {
                 attr::IntType::SignedInt(t) => {
@@ -251,10 +253,10 @@ fn report_bin_hex_error(
             if negative {
                 // If the value is negative,
                 // emits a note about the value itself, apart from the literal.
-                lint.note(fluent::lint::negative_note);
-                lint.note(fluent::lint::negative_becomes_note);
+                lint.note(fluent::negative_note);
+                lint.note(fluent::negative_becomes_note);
             } else {
-                lint.note(fluent::lint::positive_note);
+                lint.note(fluent::positive_note);
             }
             if let Some(sugg_ty) =
                 get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
@@ -264,12 +266,12 @@ fn report_bin_hex_error(
                     let (sans_suffix, _) = repr_str.split_at(pos);
                     lint.span_suggestion(
                         expr.span,
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         format!("{}{}", sans_suffix, sugg_ty),
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    lint.help(fluent::lint::help);
+                    lint.help(fluent::help);
                 }
             }
             lint.set_arg("ty", t)
@@ -358,11 +360,11 @@ fn lint_int_literal<'tcx>(
         }
 
         if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) {
-            // The overflowing literal lint was overridden.
+            // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`.
             return;
         }
 
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_int, |lint| {
+        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| {
             lint.set_arg("ty", t.name_str())
                 .set_arg(
                     "lit",
@@ -373,13 +375,13 @@ fn lint_int_literal<'tcx>(
                 )
                 .set_arg("min", min)
                 .set_arg("max", max)
-                .note(fluent::lint::note);
+                .note(fluent::note);
 
             if let Some(sugg_ty) =
                 get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             {
                 lint.set_arg("suggestion_ty", sugg_ty);
-                lint.help(fluent::lint::help);
+                lint.help(fluent::help);
             }
 
             lint
@@ -410,11 +412,11 @@ fn lint_uint_literal<'tcx>(
                         cx.struct_span_lint(
                             OVERFLOWING_LITERALS,
                             par_e.span,
-                            fluent::lint::only_cast_u8_to_char,
+                            fluent::lint_only_cast_u8_to_char,
                             |lint| {
                                 lint.span_suggestion(
                                     par_e.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     format!("'\\u{{{:X}}}'", lit_val),
                                     Applicability::MachineApplicable,
                                 )
@@ -427,7 +429,7 @@ fn lint_uint_literal<'tcx>(
             }
         }
         if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) {
-            // The overflowing literal lint was overridden.
+            // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`.
             return;
         }
         if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
@@ -441,7 +443,7 @@ fn lint_uint_literal<'tcx>(
             );
             return;
         }
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_uint, |lint| {
+        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| {
             lint.set_arg("ty", t.name_str())
                 .set_arg(
                     "lit",
@@ -452,7 +454,7 @@ fn lint_uint_literal<'tcx>(
                 )
                 .set_arg("min", min)
                 .set_arg("max", max)
-                .note(fluent::lint::note)
+                .note(fluent::note)
         });
     }
 }
@@ -485,7 +487,7 @@ fn lint_literal<'tcx>(
                 cx.struct_span_lint(
                     OVERFLOWING_LITERALS,
                     e.span,
-                    fluent::lint::overflowing_literal,
+                    fluent::lint_overflowing_literal,
                     |lint| {
                         lint.set_arg("ty", t.name_str())
                             .set_arg(
@@ -495,7 +497,7 @@ fn lint_literal<'tcx>(
                                     .span_to_snippet(lit.span)
                                     .expect("must get snippet from literal"),
                             )
-                            .note(fluent::lint::note)
+                            .note(fluent::note)
                     },
                 );
             }
@@ -518,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                     cx.struct_span_lint(
                         UNUSED_COMPARISONS,
                         e.span,
-                        fluent::lint::unused_comparisons,
+                        fluent::lint_unused_comparisons,
                         |lint| lint,
                     );
                 }
@@ -840,8 +842,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             self.emit_ffi_unsafe_type_lint(
                 ty,
                 sp,
-                fluent::lint::improper_ctypes_array_reason,
-                Some(fluent::lint::improper_ctypes_array_help),
+                fluent::lint_improper_ctypes_array_reason,
+                Some(fluent::lint_improper_ctypes_array_help),
             );
             true
         } else {
@@ -884,7 +886,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             } else {
                 // All fields are ZSTs; this means that the type should behave
                 // like (), which is FFI-unsafe
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
             }
         } else {
             // We can't completely trust repr(C) markings; make sure the fields are
@@ -898,7 +900,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     FfiPhantom(..) if def.is_enum() => {
                         return FfiUnsafe {
                             ty,
-                            reason: fluent::lint::improper_ctypes_enum_phantomdata,
+                            reason: fluent::lint_improper_ctypes_enum_phantomdata,
                             help: None,
                         };
                     }
@@ -934,7 +936,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     } else {
                         return FfiUnsafe {
                             ty,
-                            reason: fluent::lint::improper_ctypes_box,
+                            reason: fluent::lint_improper_ctypes_box,
                             help: None,
                         };
                     }
@@ -948,14 +950,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty,
                                 reason: if def.is_struct() {
-                                    fluent::lint::improper_ctypes_struct_layout_reason
+                                    fluent::lint_improper_ctypes_struct_layout_reason
                                 } else {
-                                    fluent::lint::improper_ctypes_union_layout_reason
+                                    fluent::lint_improper_ctypes_union_layout_reason
                                 },
                                 help: if def.is_struct() {
-                                    Some(fluent::lint::improper_ctypes_struct_layout_help)
+                                    Some(fluent::lint_improper_ctypes_struct_layout_help)
                                 } else {
-                                    Some(fluent::lint::improper_ctypes_union_layout_help)
+                                    Some(fluent::lint_improper_ctypes_union_layout_help)
                                 },
                             };
                         }
@@ -966,9 +968,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty,
                                 reason: if def.is_struct() {
-                                    fluent::lint::improper_ctypes_struct_non_exhaustive
+                                    fluent::lint_improper_ctypes_struct_non_exhaustive
                                 } else {
-                                    fluent::lint::improper_ctypes_union_non_exhaustive
+                                    fluent::lint_improper_ctypes_union_non_exhaustive
                                 },
                                 help: None,
                             };
@@ -978,14 +980,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty,
                                 reason: if def.is_struct() {
-                                    fluent::lint::improper_ctypes_struct_fieldless_reason
+                                    fluent::lint_improper_ctypes_struct_fieldless_reason
                                 } else {
-                                    fluent::lint::improper_ctypes_union_fieldless_reason
+                                    fluent::lint_improper_ctypes_union_fieldless_reason
                                 },
                                 help: if def.is_struct() {
-                                    Some(fluent::lint::improper_ctypes_struct_fieldless_help)
+                                    Some(fluent::lint_improper_ctypes_struct_fieldless_help)
                                 } else {
-                                    Some(fluent::lint::improper_ctypes_union_fieldless_help)
+                                    Some(fluent::lint_improper_ctypes_union_fieldless_help)
                                 },
                             };
                         }
@@ -1006,8 +1008,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: fluent::lint::improper_ctypes_enum_repr_reason,
-                                    help: Some(fluent::lint::improper_ctypes_enum_repr_help),
+                                    reason: fluent::lint_improper_ctypes_enum_repr_reason,
+                                    help: Some(fluent::lint_improper_ctypes_enum_repr_help),
                                 };
                             }
                         }
@@ -1015,7 +1017,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: fluent::lint::improper_ctypes_non_exhaustive,
+                                reason: fluent::lint_improper_ctypes_non_exhaustive,
                                 help: None,
                             };
                         }
@@ -1026,7 +1028,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if is_non_exhaustive && !variant.def_id.is_local() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: fluent::lint::improper_ctypes_non_exhaustive_variant,
+                                    reason: fluent::lint_improper_ctypes_non_exhaustive_variant,
                                     help: None,
                                 };
                             }
@@ -1044,12 +1046,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::Char => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_char_reason,
-                help: Some(fluent::lint::improper_ctypes_char_help),
+                reason: fluent::lint_improper_ctypes_char_reason,
+                help: Some(fluent::lint_improper_ctypes_char_help),
             },
 
             ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
             }
 
             // Primitive types with a stable representation.
@@ -1057,24 +1059,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::Slice(_) => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_slice_reason,
-                help: Some(fluent::lint::improper_ctypes_slice_help),
+                reason: fluent::lint_improper_ctypes_slice_reason,
+                help: Some(fluent::lint_improper_ctypes_slice_help),
             },
 
             ty::Dynamic(..) => {
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
             }
 
             ty::Str => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_str_reason,
-                help: Some(fluent::lint::improper_ctypes_str_help),
+                reason: fluent::lint_improper_ctypes_str_reason,
+                help: Some(fluent::lint_improper_ctypes_str_help),
             },
 
             ty::Tuple(..) => FfiUnsafe {
                 ty,
-                reason: fluent::lint::improper_ctypes_tuple_reason,
-                help: Some(fluent::lint::improper_ctypes_tuple_help),
+                reason: fluent::lint_improper_ctypes_tuple_reason,
+                help: Some(fluent::lint_improper_ctypes_tuple_help),
             },
 
             ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
@@ -1105,8 +1107,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 if self.is_internal_abi(sig.abi()) {
                     return FfiUnsafe {
                         ty,
-                        reason: fluent::lint::improper_ctypes_fnptr_reason,
-                        help: Some(fluent::lint::improper_ctypes_fnptr_help),
+                        reason: fluent::lint_improper_ctypes_fnptr_reason,
+                        help: Some(fluent::lint_improper_ctypes_fnptr_help),
                     };
                 }
 
@@ -1137,7 +1139,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             // While opaque types are checked for earlier, if a projection in a struct field
             // normalizes to an opaque type, then it will reach this branch.
             ty::Opaque(..) => {
-                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None }
+                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
             }
 
             // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
@@ -1171,21 +1173,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
         };
 
-        self.cx.struct_span_lint(lint, sp, fluent::lint::improper_ctypes, |lint| {
+        self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| {
             let item_description = match self.mode {
                 CItemKind::Declaration => "block",
                 CItemKind::Definition => "fn",
             };
             lint.set_arg("ty", ty);
             lint.set_arg("desc", item_description);
-            lint.span_label(sp, fluent::lint::label);
+            lint.span_label(sp, fluent::label);
             if let Some(help) = help {
                 lint.help(help);
             }
             lint.note(note);
             if let ty::Adt(def, _) = ty.kind() {
                 if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
-                    lint.span_note(sp, fluent::lint::note);
+                    lint.span_note(sp, fluent::note);
                 }
             }
             lint
@@ -1222,7 +1224,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() {
-            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None);
+            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
             true
         } else {
             false
@@ -1267,7 +1269,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 self.emit_ffi_unsafe_type_lint(
                     ty,
                     sp,
-                    fluent::lint::improper_ctypes_only_phantomdata,
+                    fluent::lint_improper_ctypes_only_phantomdata,
                     None,
                 );
             }
@@ -1401,7 +1403,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
                 cx.struct_span_lint(
                     VARIANT_SIZE_DIFFERENCES,
                     enum_definition.variants[largest_index].span,
-                    fluent::lint::variant_size_differences,
+                    fluent::lint_variant_size_differences,
                     |lint| lint.set_arg("largest", largest),
                 );
             }
@@ -1511,15 +1513,15 @@ impl InvalidAtomicOrdering {
     fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
             && let Some((ordering_arg, invalid_ordering, msg)) = match method {
-                sym::load => Some((&args[0], sym::Release, fluent::lint::atomic_ordering_load)),
-                sym::store => Some((&args[1], sym::Acquire, fluent::lint::atomic_ordering_store)),
+                sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)),
+                sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)),
                 _ => None,
             }
             && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
             && (ordering == invalid_ordering || ordering == sym::AcqRel)
         {
             cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
-                lint.help(fluent::lint::help)
+                lint.help(fluent::help)
             });
         }
     }
@@ -1531,9 +1533,9 @@ impl InvalidAtomicOrdering {
             && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
             && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
         {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint::atomic_ordering_fence, |lint| {
+            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| {
                 lint
-                    .help(fluent::lint::help)
+                    .help(fluent::help)
             });
         }
     }
@@ -1552,7 +1554,7 @@ impl InvalidAtomicOrdering {
 
         if matches!(fail_ordering, sym::Release | sym::AcqRel) {
             #[derive(LintDiagnostic)]
-            #[diag(lint::atomic_ordering_invalid)]
+            #[diag(lint_atomic_ordering_invalid)]
             #[help]
             struct InvalidAtomicOrderingDiag {
                 method: Symbol,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 787c9518b50..46706e49844 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -7,6 +7,7 @@ use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_infer::traits::util::elaborate_predicates_with_span;
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::Symbol;
@@ -154,12 +155,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         };
 
         if let Some(must_use_op) = must_use_op {
-            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint::unused_op, |lint| {
+            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
                 lint.set_arg("op", must_use_op)
-                    .span_label(expr.span, fluent::lint::label)
+                    .span_label(expr.span, fluent::label)
                     .span_suggestion_verbose(
                         expr.span.shrink_to_lo(),
-                        fluent::lint::suggestion,
+                        fluent::suggestion,
                         "let _ = ",
                         Applicability::MachineApplicable,
                     )
@@ -168,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         }
 
         if !(type_permits_lack_of_use || fn_warned || op_warned) {
-            cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint::unused_result, |lint| {
+            cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
                 lint.set_arg("ty", ty)
             });
         }
@@ -204,10 +205,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
-                    for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
+                    for obligation in elaborate_predicates_with_span(
+                        cx.tcx,
+                        cx.tcx.explicit_item_bounds(def).iter().cloned(),
+                    ) {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
-                            predicate.kind().skip_binder()
+                            obligation.predicate.kind().skip_binder()
                         {
                             let def_id = poly_trait_predicate.trait_ref.def_id;
                             let descr_pre =
@@ -268,14 +272,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     cx.struct_span_lint(
                         UNUSED_MUST_USE,
                         span,
-                        fluent::lint::unused_closure,
+                        fluent::lint_unused_closure,
                         |lint| {
                             // FIXME(davidtwco): this isn't properly translatable because of the
                             // pre/post strings
                             lint.set_arg("count", plural_len)
                                 .set_arg("pre", descr_pre)
                                 .set_arg("post", descr_post)
-                                .note(fluent::lint::note)
+                                .note(fluent::note)
                         },
                     );
                     true
@@ -284,14 +288,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                     cx.struct_span_lint(
                         UNUSED_MUST_USE,
                         span,
-                        fluent::lint::unused_generator,
+                        fluent::lint_unused_generator,
                         |lint| {
                             // FIXME(davidtwco): this isn't properly translatable because of the
                             // pre/post strings
                             lint.set_arg("count", plural_len)
                                 .set_arg("pre", descr_pre)
                                 .set_arg("post", descr_post)
-                                .note(fluent::lint::note)
+                                .note(fluent::note)
                         },
                     );
                     true
@@ -313,7 +317,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
             descr_post_path: &str,
         ) -> bool {
             if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
-                cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint::unused_def, |lint| {
+                cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| {
                     // FIXME(davidtwco): this isn't properly translatable because of the pre/post
                     // strings
                     lint.set_arg("pre", descr_pre_path);
@@ -365,17 +369,17 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
                     cx.struct_span_lint(
                         PATH_STATEMENTS,
                         s.span,
-                        fluent::lint::path_statement_drop,
+                        fluent::lint_path_statement_drop,
                         |lint| {
                             if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
                                 lint.span_suggestion(
                                     s.span,
-                                    fluent::lint::suggestion,
+                                    fluent::suggestion,
                                     format!("drop({});", snippet),
                                     Applicability::MachineApplicable,
                                 );
                             } else {
-                                lint.span_help(s.span, fluent::lint::suggestion);
+                                lint.span_help(s.span, fluent::suggestion);
                             }
                             lint
                         },
@@ -384,7 +388,7 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
                     cx.struct_span_lint(
                         PATH_STATEMENTS,
                         s.span,
-                        fluent::lint::path_statement_no_effect,
+                        fluent::lint_path_statement_no_effect,
                         |lint| lint,
                     );
                 }
@@ -557,7 +561,7 @@ trait UnusedDelimLint {
         } else {
             MultiSpan::from(value_span)
         };
-        cx.struct_span_lint(self.lint(), primary_span, fluent::lint::unused_delim, |lint| {
+        cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| {
             lint.set_arg("delim", Self::DELIM_STR);
             lint.set_arg("item", msg);
             if let Some((lo, hi)) = spans {
@@ -566,7 +570,7 @@ trait UnusedDelimLint {
                     (hi, if keep_space.1 { " ".into() } else { "".into() }),
                 ];
                 lint.multipart_suggestion(
-                    fluent::lint::suggestion,
+                    fluent::suggestion,
                     replacement,
                     Applicability::MachineApplicable,
                 );
@@ -1142,7 +1146,7 @@ impl UnusedImportBraces {
             cx.struct_span_lint(
                 UNUSED_IMPORT_BRACES,
                 item.span,
-                fluent::lint::unused_import_braces,
+                fluent::lint_unused_import_braces,
                 |lint| lint.set_arg("node", node_name),
             );
         }
@@ -1197,9 +1201,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
                     UNUSED_ALLOCATION,
                     e.span,
                     match m {
-                        adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
+                        adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation,
                         adjustment::AutoBorrowMutability::Mut { .. } => {
-                            fluent::lint::unused_allocation_mut
+                            fluent::lint_unused_allocation_mut
                         }
                     },
                     |lint| lint,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 8390d80a458..61ee467f595 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1427,6 +1427,7 @@ declare_lint! {
     "trait-object types were treated as different depending on marker-trait order",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -2878,7 +2879,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
-    /// #![feature(naked_functions)]
+    /// #![feature(asm_experimental_arch, naked_functions)]
     ///
     /// use std::arch::asm;
     ///
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 8cf307df5a5..ef1985b960e 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -40,7 +40,7 @@ impl<'a> DiagnosticDerive<'a> {
                     span_err(builder.span, "diagnostic slug not specified")
                         .help(&format!(
                             "specify the slug as the first argument to the `#[diag(...)]` \
-                            attribute, such as `#[diag(hir_analysis::example_error)]`",
+                            attribute, such as `#[diag(hir_analysis_example_error)]`",
                         ))
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
@@ -121,7 +121,7 @@ impl<'a> LintDiagnosticDerive<'a> {
                     span_err(builder.span, "diagnostic slug not specified")
                         .help(&format!(
                             "specify the slug as the first argument to the attribute, such as \
-                            `#[diag(compiletest::example)]`",
+                            `#[diag(compiletest_example)]`",
                         ))
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index dcbe89251cb..9f7d2661a3e 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -5,7 +5,7 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    build_field_mapping, report_error_if_not_applied_to_span, report_type_error,
+    build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
     should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
     HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
@@ -152,8 +152,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
     fn parse_subdiag_attribute(
         &self,
         attr: &Attribute,
-    ) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> {
-        let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?;
+    ) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
+        let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
+            // Some attributes aren't errors - like documentation comments - but also aren't
+            // subdiagnostics.
+            return Ok(None);
+        };
 
         if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
             let meta = attr.parse_meta()?;
@@ -170,7 +174,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
         });
 
-        Ok((subdiag, slug))
+        Ok(Some((subdiag, slug)))
     }
 
     /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
@@ -182,6 +186,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
     ) -> Result<TokenStream, DiagnosticDeriveError> {
         let diag = &self.parent.diag;
 
+        // Always allow documentation comments.
+        if is_doc_comment(attr) {
+            return Ok(quote! {});
+        }
+
         let name = attr.path.segments.last().unwrap().ident.to_string();
         let name = name.as_str();
         let meta = attr.parse_meta()?;
@@ -250,7 +259,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             return Ok(tokens);
         }
 
-        let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
+        let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
+            // Some attributes aren't errors - like documentation comments - but also aren't
+            // subdiagnostics.
+            return Ok(quote! {});
+        };
         let fn_ident = format_ident!("{}", subdiag);
         match subdiag {
             SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
@@ -291,6 +304,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             .attrs
             .iter()
             .map(move |attr| {
+                // Always allow documentation comments.
+                if is_doc_comment(attr) {
+                    return quote! {};
+                }
+
                 let name = attr.path.segments.last().unwrap().ident.to_string();
                 let needs_clone =
                     name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
@@ -397,8 +415,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             _ => (),
         }
 
-        let (subdiag, slug) = self.parse_subdiag_attribute(attr)?;
-
+        let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
+            // Some attributes aren't errors - like documentation comments - but also aren't
+            // subdiagnostics.
+            return Ok(quote! {});
+        };
         let fn_ident = format_ident!("{}", subdiag);
         match subdiag {
             SubdiagnosticKind::Label => {
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index f7d8b494ee2..3e447c94ef1 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -25,18 +25,18 @@ use syn::{
 use unic_langid::langid;
 
 struct Resource {
-    ident: Ident,
+    krate: Ident,
     #[allow(dead_code)]
     fat_arrow_token: token::FatArrow,
-    resource: LitStr,
+    resource_path: LitStr,
 }
 
 impl Parse for Resource {
     fn parse(input: ParseStream<'_>) -> Result<Self> {
         Ok(Resource {
-            ident: input.parse()?,
+            krate: input.parse()?,
             fat_arrow_token: input.parse()?,
-            resource: input.parse()?,
+            resource_path: input.parse()?,
         })
     }
 }
@@ -94,19 +94,20 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
     // diagnostics.
     let mut previous_defns = HashMap::new();
 
+    // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
+    // constant created for a given attribute is the same.
+    let mut previous_attrs = HashSet::new();
+
     let mut includes = TokenStream::new();
     let mut generated = TokenStream::new();
-    for res in resources.0 {
-        let ident_span = res.ident.span().unwrap();
-        let path_span = res.resource.span().unwrap();
 
-        // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
-        // constant created for a given attribute is the same.
-        let mut previous_attrs = HashSet::new();
+    for res in resources.0 {
+        let krate_span = res.krate.span().unwrap();
+        let path_span = res.resource_path.span().unwrap();
 
-        let relative_ftl_path = res.resource.value();
+        let relative_ftl_path = res.resource_path.value();
         let absolute_ftl_path =
-            invocation_relative_path_to_absolute(ident_span, &relative_ftl_path);
+            invocation_relative_path_to_absolute(krate_span, &relative_ftl_path);
         // As this macro also outputs an `include_str!` for this file, the macro will always be
         // re-executed when the file changes.
         let mut resource_file = match File::open(absolute_ftl_path) {
@@ -185,7 +186,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
 
         let mut constants = TokenStream::new();
         for entry in resource.entries() {
-            let span = res.ident.span();
+            let span = res.krate.span();
             if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
                 let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
 
@@ -199,29 +200,30 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                     .emit();
                 }
 
-                // `typeck_foo_bar` => `foo_bar` (in `typeck.ftl`)
-                // `const_eval_baz` => `baz` (in `const_eval.ftl`)
+                // Require that the message name starts with the crate name
+                // `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
+                // `const_eval_baz` (in `const_eval.ftl`)
                 // `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`)
                 // The last case we error about above, but we want to fall back gracefully
                 // so that only the error is being emitted and not also one about the macro
                 // failing.
-                let crate_prefix = format!("{}_", res.ident);
+                let crate_prefix = format!("{}_", res.krate);
 
                 let snake_name = name.replace('-', "_");
-                let snake_name = match snake_name.strip_prefix(&crate_prefix) {
-                    Some(rest) => Ident::new(rest, span),
-                    None => {
-                        Diagnostic::spanned(
-                            path_span,
-                            Level::Error,
-                            format!("name `{name}` does not start with the crate name"),
-                        )
-                        .help(format!("prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"))
-                        .emit();
-                        Ident::new(&snake_name, span)
-                    }
+                if !snake_name.starts_with(&crate_prefix) {
+                    Diagnostic::spanned(
+                        path_span,
+                        Level::Error,
+                        format!("name `{name}` does not start with the crate name"),
+                    )
+                    .help(format!(
+                        "prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"
+                    ))
+                    .emit();
                 };
 
+                let snake_name = Ident::new(&snake_name, span);
+
                 constants.extend(quote! {
                     pub const #snake_name: crate::DiagnosticMessage =
                         crate::DiagnosticMessage::FluentIdentifier(
@@ -275,12 +277,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
 
         includes.extend(quote! { include_str!(#relative_ftl_path), });
 
-        let ident = res.ident;
-        generated.extend(quote! {
-            pub mod #ident {
-                #constants
-            }
-        });
+        generated.extend(constants);
     }
 
     quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index f98cc66e9e9..860340b4390 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -23,14 +23,14 @@ use synstructure::Structure;
 /// # extern crate rust_middle;
 /// # use rustc_middle::ty::Ty;
 /// #[derive(Diagnostic)]
-/// #[diag(borrowck::move_out_of_borrow, code = "E0505")]
+/// #[diag(borrowck_move_out_of_borrow, code = "E0505")]
 /// pub struct MoveOutOfBorrowError<'tcx> {
 ///     pub name: Ident,
 ///     pub ty: Ty<'tcx>,
 ///     #[primary_span]
 ///     #[label]
 ///     pub span: Span,
-///     #[label(borrowck::first_borrow_label)]
+///     #[label(first_borrow_label)]
 ///     pub first_borrow_span: Span,
 ///     #[suggestion(code = "{name}.clone()")]
 ///     pub clone_sugg: Option<(Span, Applicability)>
@@ -67,14 +67,14 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 ///
 /// ```ignore (rust)
 /// #[derive(LintDiagnostic)]
-/// #[diag(lint::atomic_ordering_invalid_fail_success)]
+/// #[diag(lint_atomic_ordering_invalid_fail_success)]
 /// pub struct AtomicOrderingInvalidLint {
 ///     method: Symbol,
 ///     success_ordering: Symbol,
 ///     fail_ordering: Symbol,
-///     #[label(lint::fail_label)]
+///     #[label(fail_label)]
 ///     fail_order_arg_span: Span,
-///     #[label(lint::success_label)]
+///     #[label(success_label)]
 ///     #[suggestion(
 ///         code = "std::sync::atomic::Ordering::{success_suggestion}",
 ///         applicability = "maybe-incorrect"
@@ -115,12 +115,12 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 /// ```ignore (rust)
 /// #[derive(Subdiagnostic)]
 /// pub enum ExpectedIdentifierLabel<'tcx> {
-///     #[label(parser::expected_identifier)]
+///     #[label(expected_identifier)]
 ///     WithoutFound {
 ///         #[primary_span]
 ///         span: Span,
 ///     }
-///     #[label(parser::expected_identifier_found)]
+///     #[label(expected_identifier_found)]
 ///     WithFound {
 ///         #[primary_span]
 ///         span: Span,
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 3d4c3ab9fd7..d1acb713842 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -5,9 +5,9 @@ use crate::diagnostics::error::{
     DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability,
-    report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
-    SpannedOption, SubdiagnosticKind,
+    build_field_mapping, is_doc_comment, new_code_ident,
+    report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
+    FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
@@ -41,8 +41,14 @@ impl SubdiagnosticDeriveBuilder {
                 }
             }
 
-            if matches!(ast.data, syn::Data::Enum(..)) {
+            let is_enum = matches!(ast.data, syn::Data::Enum(..));
+            if is_enum {
                 for attr in &ast.attrs {
+                    // Always allow documentation comments.
+                    if is_doc_comment(attr) {
+                        continue;
+                    }
+
                     span_err(
                         attr.span().unwrap(),
                         "unsupported type attribute for subdiagnostic enum",
@@ -62,6 +68,7 @@ impl SubdiagnosticDeriveBuilder {
                     span_field: None,
                     applicability: None,
                     has_suggestion_parts: false,
+                    is_enum,
                 };
                 builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
             });
@@ -79,7 +86,7 @@ impl SubdiagnosticDeriveBuilder {
             gen impl rustc_errors::AddToDiagnostic for @Self {
                 fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F)
                 where
-                    __F: Fn(
+                    __F: core::ops::Fn(
                         &mut rustc_errors::Diagnostic,
                         rustc_errors::SubdiagnosticMessage
                     ) -> rustc_errors::SubdiagnosticMessage,
@@ -122,6 +129,9 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
     /// during finalization if still `false`.
     has_suggestion_parts: bool,
+
+    /// Set to true when this variant is an enum variant rather than just the body of a struct.
+    is_enum: bool,
 }
 
 impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
@@ -173,7 +183,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
         let mut kind_slugs = vec![];
 
         for attr in self.variant.ast().attrs {
-            let (kind, slug) = SubdiagnosticKind::from_attr(attr, self)?;
+            let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
+                // Some attributes aren't errors - like documentation comments - but also aren't
+                // subdiagnostics.
+                continue;
+            };
 
             let Some(slug) = slug else {
                 let name = attr.path.segments.last().unwrap().ident.to_string();
@@ -227,6 +241,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
         ast.attrs
             .iter()
             .map(|attr| {
+                // Always allow documentation comments.
+                if is_doc_comment(attr) {
+                    return quote! {};
+                }
+
                 let info = FieldInfo {
                     binding,
                     ty: inner_ty.inner_type().unwrap_or(&ast.ty),
@@ -290,6 +309,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
                     report_error_if_not_applied_to_span(attr, &info)?;
 
                     let binding = info.binding.binding.clone();
+                    // FIXME(#100717): support `Option<Span>` on `primary_span` like in the
+                    // diagnostic derive
                     self.span_field.set_once(binding, span);
                 }
 
@@ -443,10 +464,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
         let kind_slugs = self.identify_kind()?;
         if kind_slugs.is_empty() {
-            throw_span_err!(
-                self.variant.ast().ident.span().unwrap(),
-                "subdiagnostic kind not specified"
-            );
+            if self.is_enum {
+                // It's okay for a variant to not be a subdiagnostic at all..
+                return Ok(quote! {});
+            } else {
+                // ..but structs should always be _something_.
+                throw_span_err!(
+                    self.variant.ast().ident.span().unwrap(),
+                    "subdiagnostic kind not specified"
+                );
+            }
         };
 
         let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 4fd4adc5112..61d5007fc30 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -477,7 +477,12 @@ impl SubdiagnosticKind {
     pub(super) fn from_attr(
         attr: &Attribute,
         fields: &impl HasFieldMap,
-    ) -> Result<(SubdiagnosticKind, Option<Path>), DiagnosticDeriveError> {
+    ) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> {
+        // Always allow documentation comments.
+        if is_doc_comment(attr) {
+            return Ok(None);
+        }
+
         let span = attr.span().unwrap();
 
         let name = attr.path.segments.last().unwrap().ident.to_string();
@@ -526,7 +531,9 @@ impl SubdiagnosticKind {
                     | SubdiagnosticKind::Note
                     | SubdiagnosticKind::Help
                     | SubdiagnosticKind::Warn
-                    | SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)),
+                    | SubdiagnosticKind::MultipartSuggestion { .. } => {
+                        return Ok(Some((kind, None)));
+                    }
                     SubdiagnosticKind::Suggestion { .. } => {
                         throw_span_err!(span, "suggestion without `code = \"...\"`")
                     }
@@ -626,7 +633,7 @@ impl SubdiagnosticKind {
             | SubdiagnosticKind::MultipartSuggestion { .. } => {}
         }
 
-        Ok((kind, slug))
+        Ok(Some((kind, slug)))
     }
 }
 
@@ -654,3 +661,7 @@ impl quote::IdentFragment for SubdiagnosticKind {
 pub(super) fn should_generate_set_arg(field: &Field) -> bool {
     field.attrs.is_empty()
 }
+
+pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
+    attr.path.segments.last().unwrap().ident.to_string() == "doc"
+}
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index dbfa22aaff0..7c387b9a9ec 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -12,41 +12,41 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 use crate::locator::CrateFlavor;
 
 #[derive(Diagnostic)]
-#[diag(metadata::rlib_required)]
+#[diag(metadata_rlib_required)]
 pub struct RlibRequired {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::lib_required)]
+#[diag(metadata_lib_required)]
 pub struct LibRequired<'a> {
     pub crate_name: Symbol,
     pub kind: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::crate_dep_multiple)]
+#[diag(metadata_crate_dep_multiple)]
 #[help]
 pub struct CrateDepMultiple {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::two_panic_runtimes)]
+#[diag(metadata_two_panic_runtimes)]
 pub struct TwoPanicRuntimes {
     pub prev_name: Symbol,
     pub cur_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::bad_panic_strategy)]
+#[diag(metadata_bad_panic_strategy)]
 pub struct BadPanicStrategy {
     pub runtime: Symbol,
     pub strategy: PanicStrategy,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::required_panic_strategy)]
+#[diag(metadata_required_panic_strategy)]
 pub struct RequiredPanicStrategy {
     pub crate_name: Symbol,
     pub found_strategy: PanicStrategy,
@@ -54,7 +54,7 @@ pub struct RequiredPanicStrategy {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::incompatible_panic_in_drop_strategy)]
+#[diag(metadata_incompatible_panic_in_drop_strategy)]
 pub struct IncompatiblePanicInDropStrategy {
     pub crate_name: Symbol,
     pub found_strategy: PanicStrategy,
@@ -62,56 +62,56 @@ pub struct IncompatiblePanicInDropStrategy {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_names_in_link)]
+#[diag(metadata_multiple_names_in_link)]
 pub struct MultipleNamesInLink {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_kinds_in_link)]
+#[diag(metadata_multiple_kinds_in_link)]
 pub struct MultipleKindsInLink {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_name_form)]
+#[diag(metadata_link_name_form)]
 pub struct LinkNameForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_kind_form)]
+#[diag(metadata_link_kind_form)]
 pub struct LinkKindForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_modifiers_form)]
+#[diag(metadata_link_modifiers_form)]
 pub struct LinkModifiersForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_cfg_form)]
+#[diag(metadata_link_cfg_form)]
 pub struct LinkCfgForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::wasm_import_form)]
+#[diag(metadata_wasm_import_form)]
 pub struct WasmImportForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::empty_link_name, code = "E0454")]
+#[diag(metadata_empty_link_name, code = "E0454")]
 pub struct EmptyLinkName {
     #[primary_span]
     #[label]
@@ -119,21 +119,21 @@ pub struct EmptyLinkName {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_framework_apple, code = "E0455")]
+#[diag(metadata_link_framework_apple, code = "E0455")]
 pub struct LinkFrameworkApple {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::framework_only_windows, code = "E0455")]
+#[diag(metadata_framework_only_windows, code = "E0455")]
 pub struct FrameworkOnlyWindows {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unknown_link_kind, code = "E0458")]
+#[diag(metadata_unknown_link_kind, code = "E0458")]
 pub struct UnknownLinkKind<'a> {
     #[primary_span]
     #[label]
@@ -142,49 +142,49 @@ pub struct UnknownLinkKind<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_link_modifiers)]
+#[diag(metadata_multiple_link_modifiers)]
 pub struct MultipleLinkModifiers {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_cfgs)]
+#[diag(metadata_multiple_cfgs)]
 pub struct MultipleCfgs {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_cfg_single_predicate)]
+#[diag(metadata_link_cfg_single_predicate)]
 pub struct LinkCfgSinglePredicate {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_wasm_import)]
+#[diag(metadata_multiple_wasm_import)]
 pub struct MultipleWasmImport {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unexpected_link_arg)]
+#[diag(metadata_unexpected_link_arg)]
 pub struct UnexpectedLinkArg {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::invalid_link_modifier)]
+#[diag(metadata_invalid_link_modifier)]
 pub struct InvalidLinkModifier {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_modifiers)]
+#[diag(metadata_multiple_modifiers)]
 pub struct MultipleModifiers<'a> {
     #[primary_span]
     pub span: Span,
@@ -192,28 +192,28 @@ pub struct MultipleModifiers<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::bundle_needs_static)]
+#[diag(metadata_bundle_needs_static)]
 pub struct BundleNeedsStatic {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::whole_archive_needs_static)]
+#[diag(metadata_whole_archive_needs_static)]
 pub struct WholeArchiveNeedsStatic {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::as_needed_compatibility)]
+#[diag(metadata_as_needed_compatibility)]
 pub struct AsNeededCompatibility {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unknown_link_modifier)]
+#[diag(metadata_unknown_link_modifier)]
 pub struct UnknownLinkModifier<'a> {
     #[primary_span]
     pub span: Span,
@@ -221,14 +221,14 @@ pub struct UnknownLinkModifier<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::incompatible_wasm_link)]
+#[diag(metadata_incompatible_wasm_link)]
 pub struct IncompatibleWasmLink {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_requires_name, code = "E0459")]
+#[diag(metadata_link_requires_name, code = "E0459")]
 pub struct LinkRequiresName {
     #[primary_span]
     #[label]
@@ -236,126 +236,126 @@ pub struct LinkRequiresName {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::raw_dylib_no_nul)]
+#[diag(metadata_raw_dylib_no_nul)]
 pub struct RawDylibNoNul {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::link_ordinal_raw_dylib)]
+#[diag(metadata_link_ordinal_raw_dylib)]
 pub struct LinkOrdinalRawDylib {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::lib_framework_apple)]
+#[diag(metadata_lib_framework_apple)]
 pub struct LibFrameworkApple;
 
 #[derive(Diagnostic)]
-#[diag(metadata::empty_renaming_target)]
+#[diag(metadata_empty_renaming_target)]
 pub struct EmptyRenamingTarget<'a> {
     pub lib_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::renaming_no_link)]
+#[diag(metadata_renaming_no_link)]
 pub struct RenamingNoLink<'a> {
     pub lib_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_renamings)]
+#[diag(metadata_multiple_renamings)]
 pub struct MultipleRenamings<'a> {
     pub lib_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_link_mod_override)]
+#[diag(metadata_no_link_mod_override)]
 pub struct NoLinkModOverride {
     #[primary_span]
     pub span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unsupported_abi_i686)]
+#[diag(metadata_unsupported_abi_i686)]
 pub struct UnsupportedAbiI686 {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unsupported_abi)]
+#[diag(metadata_unsupported_abi)]
 pub struct UnsupportedAbi {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::fail_create_file_encoder)]
+#[diag(metadata_fail_create_file_encoder)]
 pub struct FailCreateFileEncoder {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::fail_seek_file)]
+#[diag(metadata_fail_seek_file)]
 pub struct FailSeekFile {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::fail_write_file)]
+#[diag(metadata_fail_write_file)]
 pub struct FailWriteFile {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::crate_not_panic_runtime)]
+#[diag(metadata_crate_not_panic_runtime)]
 pub struct CrateNotPanicRuntime {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_panic_strategy)]
+#[diag(metadata_no_panic_strategy)]
 pub struct NoPanicStrategy {
     pub crate_name: Symbol,
     pub strategy: PanicStrategy,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::profiler_builtins_needs_core)]
+#[diag(metadata_profiler_builtins_needs_core)]
 pub struct ProfilerBuiltinsNeedsCore;
 
 #[derive(Diagnostic)]
-#[diag(metadata::not_profiler_runtime)]
+#[diag(metadata_not_profiler_runtime)]
 pub struct NotProfilerRuntime {
     pub crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_multiple_global_alloc)]
+#[diag(metadata_no_multiple_global_alloc)]
 pub struct NoMultipleGlobalAlloc {
     #[primary_span]
     #[label]
     pub span2: Span,
-    #[label(metadata::prev_global_alloc)]
+    #[label(metadata_prev_global_alloc)]
     pub span1: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::conflicting_global_alloc)]
+#[diag(metadata_conflicting_global_alloc)]
 pub struct ConflictingGlobalAlloc {
     pub crate_name: Symbol,
     pub other_crate_name: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::global_alloc_required)]
+#[diag(metadata_global_alloc_required)]
 pub struct GlobalAllocRequired;
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_transitive_needs_dep)]
+#[diag(metadata_no_transitive_needs_dep)]
 pub struct NoTransitiveNeedsDep<'a> {
     pub crate_name: Symbol,
     pub needs_crate_name: &'a str,
@@ -363,14 +363,14 @@ pub struct NoTransitiveNeedsDep<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_write_error)]
+#[diag(metadata_failed_write_error)]
 pub struct FailedWriteError {
     pub filename: PathBuf,
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::missing_native_library)]
+#[diag(metadata_missing_native_library)]
 pub struct MissingNativeLibrary<'a> {
     libname: &'a str,
     #[subdiagnostic]
@@ -404,32 +404,32 @@ impl<'a> MissingNativeLibrary<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[help(metadata::only_provide_library_name)]
+#[help(metadata_only_provide_library_name)]
 pub struct SuggestLibraryName<'a> {
     suggested_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_create_tempdir)]
+#[diag(metadata_failed_create_tempdir)]
 pub struct FailedCreateTempdir {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_create_file)]
+#[diag(metadata_failed_create_file)]
 pub struct FailedCreateFile<'a> {
     pub filename: &'a Path,
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::failed_create_encoded_metadata)]
+#[diag(metadata_failed_create_encoded_metadata)]
 pub struct FailedCreateEncodedMetadata {
     pub err: Error,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::non_ascii_name)]
+#[diag(metadata_non_ascii_name)]
 pub struct NonAsciiName {
     #[primary_span]
     pub span: Span,
@@ -437,7 +437,7 @@ pub struct NonAsciiName {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::extern_location_not_exist)]
+#[diag(metadata_extern_location_not_exist)]
 pub struct ExternLocationNotExist<'a> {
     #[primary_span]
     pub span: Span,
@@ -446,7 +446,7 @@ pub struct ExternLocationNotExist<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::extern_location_not_file)]
+#[diag(metadata_extern_location_not_file)]
 pub struct ExternLocationNotFile<'a> {
     #[primary_span]
     pub span: Span,
@@ -466,7 +466,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("flavor", self.flavor);
         diag.code(error_code!(E0465));
@@ -479,7 +479,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_matching_crates, code = "E0464")]
+#[diag(metadata_multiple_matching_crates, code = "E0464")]
 #[note]
 pub struct MultipleMatchingCrates {
     #[primary_span]
@@ -489,7 +489,7 @@ pub struct MultipleMatchingCrates {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::symbol_conflicts_current, code = "E0519")]
+#[diag(metadata_symbol_conflicts_current, code = "E0519")]
 pub struct SymbolConflictsCurrent {
     #[primary_span]
     pub span: Span,
@@ -497,7 +497,7 @@ pub struct SymbolConflictsCurrent {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::symbol_conflicts_others, code = "E0523")]
+#[diag(metadata_symbol_conflicts_others, code = "E0523")]
 pub struct SymbolConflictsOthers {
     #[primary_span]
     pub span: Span,
@@ -505,7 +505,7 @@ pub struct SymbolConflictsOthers {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::stable_crate_id_collision)]
+#[diag(metadata_stable_crate_id_collision)]
 pub struct StableCrateIdCollision {
     #[primary_span]
     pub span: Span,
@@ -514,7 +514,7 @@ pub struct StableCrateIdCollision {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::dl_error)]
+#[diag(metadata_dl_error)]
 pub struct DlError {
     #[primary_span]
     pub span: Span,
@@ -522,9 +522,9 @@ pub struct DlError {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::newer_crate_version, code = "E0460")]
+#[diag(metadata_newer_crate_version, code = "E0460")]
 #[note]
-#[note(metadata::found_crate_versions)]
+#[note(metadata_found_crate_versions)]
 pub struct NewerCrateVersion {
     #[primary_span]
     pub span: Span,
@@ -534,8 +534,8 @@ pub struct NewerCrateVersion {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_crate_with_triple, code = "E0461")]
-#[note(metadata::found_crate_versions)]
+#[diag(metadata_no_crate_with_triple, code = "E0461")]
+#[note(metadata_found_crate_versions)]
 pub struct NoCrateWithTriple<'a> {
     #[primary_span]
     pub span: Span,
@@ -546,8 +546,8 @@ pub struct NoCrateWithTriple<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::found_staticlib, code = "E0462")]
-#[note(metadata::found_crate_versions)]
+#[diag(metadata_found_staticlib, code = "E0462")]
+#[note(metadata_found_crate_versions)]
 #[help]
 pub struct FoundStaticlib {
     #[primary_span]
@@ -558,8 +558,8 @@ pub struct FoundStaticlib {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::incompatible_rustc, code = "E0514")]
-#[note(metadata::found_crate_versions)]
+#[diag(metadata_incompatible_rustc, code = "E0514")]
+#[note(metadata_found_crate_versions)]
 #[help]
 pub struct IncompatibleRustc {
     #[primary_span]
@@ -582,7 +582,7 @@ impl IntoDiagnostic<'_> for InvalidMetadataFiles {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_invalid_meta_files);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("add_info", self.add_info);
         diag.code(error_code!(E0786));
@@ -610,7 +610,7 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_cannot_find_crate);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("current_crate", self.current_crate);
         diag.set_arg("add_info", self.add_info);
@@ -621,38 +621,38 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
             && self.locator_triple != TargetTriple::from_triple(config::host_triple())
         {
             if self.missing_core {
-                diag.note(rustc_errors::fluent::metadata::target_not_installed);
+                diag.note(rustc_errors::fluent::metadata_target_not_installed);
             } else {
-                diag.note(rustc_errors::fluent::metadata::target_no_std_support);
+                diag.note(rustc_errors::fluent::metadata_target_no_std_support);
             }
             // NOTE: this suggests using rustup, even though the user may not have it installed.
             // That's because they could choose to install it; or this may give them a hint which
             // target they need to install from their distro.
             if self.missing_core {
-                diag.help(rustc_errors::fluent::metadata::consider_downloading_target);
+                diag.help(rustc_errors::fluent::metadata_consider_downloading_target);
             }
             // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
             // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
             // If it's not a dummy, that means someone added `extern crate std` explicitly and
             // `#![no_std]` won't help.
             if !self.missing_core && self.span.is_dummy() {
-                diag.note(rustc_errors::fluent::metadata::std_required);
+                diag.note(rustc_errors::fluent::metadata_std_required);
             }
             if self.is_nightly_build {
-                diag.help(rustc_errors::fluent::metadata::consider_building_std);
+                diag.help(rustc_errors::fluent::metadata_consider_building_std);
             }
         } else if self.crate_name == self.profiler_runtime {
-            diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler);
+            diag.note(rustc_errors::fluent::metadata_compiler_missing_profiler);
         } else if self.crate_name.as_str().starts_with("rustc_") {
-            diag.help(rustc_errors::fluent::metadata::install_missing_components);
+            diag.help(rustc_errors::fluent::metadata_install_missing_components);
         }
-        diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate);
+        diag.span_label(self.span, rustc_errors::fluent::metadata_cant_find_crate);
         diag
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::no_dylib_plugin, code = "E0457")]
+#[diag(metadata_no_dylib_plugin, code = "E0457")]
 pub struct NoDylibPlugin {
     #[primary_span]
     pub span: Span,
@@ -660,7 +660,7 @@ pub struct NoDylibPlugin {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::crate_location_unknown_type)]
+#[diag(metadata_crate_location_unknown_type)]
 pub struct CrateLocationUnknownType<'a> {
     #[primary_span]
     pub span: Span,
@@ -668,7 +668,7 @@ pub struct CrateLocationUnknownType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::lib_filename_form)]
+#[diag(metadata_lib_filename_form)]
 pub struct LibFilenameForm<'a> {
     #[primary_span]
     pub span: Span,
@@ -677,28 +677,28 @@ pub struct LibFilenameForm<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::multiple_import_name_type)]
+#[diag(metadata_multiple_import_name_type)]
 pub struct MultipleImportNameType {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::import_name_type_form)]
+#[diag(metadata_import_name_type_form)]
 pub struct ImportNameTypeForm {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::import_name_type_x86)]
+#[diag(metadata_import_name_type_x86)]
 pub struct ImportNameTypeX86 {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::unknown_import_name_type)]
+#[diag(metadata_unknown_import_name_type)]
 pub struct UnknownImportNameType<'a> {
     #[primary_span]
     pub span: Span,
@@ -706,7 +706,7 @@ pub struct UnknownImportNameType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata::import_name_type_raw)]
+#[diag(metadata_import_name_type_raw)]
 pub struct ImportNameTypeRaw {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index c4dff8b3f48..a0a0855251b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -15,7 +15,6 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_session::cstore::{CrateSource, CrateStore};
-use rustc_session::utils::NativeLibKind;
 use rustc_session::{Session, StableCrateId};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::source_map::{Span, Spanned};
@@ -224,6 +223,7 @@ provide! { tcx, def_id, other, cdata,
     fn_arg_names => { table }
     generator_kind => { table }
     trait_def => { table }
+    deduced_param_attrs => { table }
     collect_trait_impl_trait_tys => {
         Ok(cdata
             .root
@@ -339,20 +339,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
-        is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(
-                NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
-            ) => true,
-            _ => false,
-        },
-        is_statically_included_foreign_item: |tcx, id| {
-            matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
-        },
         is_private_dep: |_tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
             false
         },
-        native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind),
         native_library: |tcx, id| {
             tcx.native_libraries(id.krate)
                 .iter()
@@ -597,11 +587,6 @@ impl CStore {
         self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
     }
 
-    /// Decodes all traits in the crate (for rustdoc).
-    pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
-        self.get_crate_data(cnum).get_traits()
-    }
-
     /// Decodes all trait impls in the crate (for rustdoc).
     pub fn trait_impls_in_crate_untracked(
         &self,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 68119598285..c019211a948 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
 use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
 
+use rustc_ast::Attribute;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
@@ -30,7 +31,7 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
-use rustc_session::config::CrateType;
+use rustc_session::config::{CrateType, OptLevel};
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
 use rustc_span::symbol::{sym, Symbol};
@@ -764,6 +765,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 }
 
+/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
+/// useful in downstream crates. Local-only attributes are an obvious example, but some
+/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
+///
+/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
+///
+/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public
+/// visibility: this is a piece of data that can be computed once per defid, and not once per
+/// attribute. Some attributes would only be usable downstream if they are public.
+#[inline]
+fn should_encode_attr(
+    tcx: TyCtxt<'_>,
+    attr: &Attribute,
+    def_id: LocalDefId,
+    is_def_id_public: &mut Option<bool>,
+) -> bool {
+    if rustc_feature::is_builtin_only_local(attr.name_or_empty()) {
+        // Attributes marked local-only don't need to be encoded for downstream crates.
+        false
+    } else if attr.doc_str().is_some() {
+        // We keep all public doc comments because they might be "imported" into downstream crates
+        // if they use `#[doc(inline)]` to copy an item's documentation into their own.
+        *is_def_id_public.get_or_insert_with(|| {
+            tcx.privacy_access_levels(()).get_effective_vis(def_id).is_some()
+        })
+    } else if attr.has_name(sym::doc) {
+        // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
+        // remove it. It won't be inlinable in downstream crates.
+        attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false)
+    } else {
+        true
+    }
+}
+
 fn should_encode_visibility(def_kind: DefKind) -> bool {
     match def_kind {
         DefKind::Mod
@@ -1126,12 +1161,14 @@ fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) ->
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_attrs(&mut self, def_id: LocalDefId) {
-        let mut attrs = self
-            .tcx
+        let tcx = self.tcx;
+        let mut is_public: Option<bool> = None;
+
+        let mut attrs = tcx
             .hir()
-            .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id))
+            .attrs(tcx.hir().local_def_id_to_hir_id(def_id))
             .iter()
-            .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
+            .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public));
 
         record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
         if attrs.any(|attr| attr.may_have_doc_links()) {
@@ -1441,6 +1478,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
         }
+
+        // Encode all the deduced parameter attributes for everything that has MIR, even for items
+        // that can't be inlined. But don't if we aren't optimizing in non-incremental mode, to
+        // save the query traffic.
+        if tcx.sess.opts.output_types.should_codegen()
+            && tcx.sess.opts.optimize != OptLevel::No
+            && tcx.sess.opts.incremental.is_none()
+        {
+            for &local_def_id in tcx.mir_keys(()) {
+                if let DefKind::AssocFn | DefKind::Fn = tcx.def_kind(local_def_id) {
+                    record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <-
+                        self.tcx.deduced_param_attrs(local_def_id.to_def_id()));
+                }
+            }
+        }
     }
 
     fn encode_stability(&mut self, def_id: DefId) {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a509ecdf759..27dc8ff16ac 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -23,7 +23,7 @@ use rustc_middle::mir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, ReprOptions, Ty};
-use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
+use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
 use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
@@ -402,6 +402,7 @@ define_tables! {
     macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     module_reexports: Table<DefIndex, LazyArray<ModChild>>,
+    deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
 
     trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
 }
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index e69cb546d15..a7a7ac0599d 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -4,7 +4,7 @@ use rustc_span::Span;
 use crate::ty::Ty;
 
 #[derive(Diagnostic)]
-#[diag(middle::drop_check_overflow, code = "E0320")]
+#[diag(middle_drop_check_overflow, code = "E0320")]
 #[note]
 pub struct DropCheckOverflow<'tcx> {
     #[primary_span]
@@ -14,7 +14,7 @@ pub struct DropCheckOverflow<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle::opaque_hidden_type_mismatch)]
+#[diag(middle_opaque_hidden_type_mismatch)]
 pub struct OpaqueHiddenTypeMismatch<'tcx> {
     pub self_ty: Ty<'tcx>,
     pub other_ty: Ty<'tcx>,
@@ -27,12 +27,12 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> {
 
 #[derive(Subdiagnostic)]
 pub enum TypeMismatchReason {
-    #[label(middle::conflict_types)]
+    #[label(middle_conflict_types)]
     ConflictType {
         #[primary_span]
         span: Span,
     },
-    #[note(middle::previous_use_here)]
+    #[note(middle_previous_use_here)]
     PreviousUse {
         #[primary_span]
         span: Span,
@@ -40,7 +40,7 @@ pub enum TypeMismatchReason {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle::limit_invalid)]
+#[diag(middle_limit_invalid)]
 pub struct LimitInvalid<'a> {
     #[primary_span]
     pub span: Span,
@@ -50,7 +50,7 @@ pub struct LimitInvalid<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(middle::const_eval_non_int)]
+#[diag(middle_const_eval_non_int)]
 pub struct ConstEvalNonIntError {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index d3cf519b633..f4f1d82c3b8 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -302,10 +302,8 @@ impl<'tcx, V> Canonical<'tcx, V> {
     }
 }
 
-pub type QueryOutlivesConstraint<'tcx> = (
-    ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
-    ConstraintCategory<'tcx>,
-);
+pub type QueryOutlivesConstraint<'tcx> =
+    (ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>, ConstraintCategory);
 
 TrivialTypeTraversalAndLiftImpls! {
     for <'tcx> {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 45c84680ad2..a58cbc3767e 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -55,6 +55,7 @@
 #![feature(drain_filter)]
 #![feature(intra_doc_pointers)]
 #![feature(yeet_expr)]
+#![feature(result_option_inspect)]
 #![feature(const_option)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index d95c5cbd654..79522bd0b2b 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -274,6 +274,39 @@ pub fn explain_lint_level_source(
     }
 }
 
+/// The innermost function for emitting lints.
+///
+/// If you are loocking to implement a lint, look for higher level functions,
+/// for example:
+/// - [`TyCtxt::emit_spanned_lint`]
+/// - [`TyCtxt::struct_span_lint_hir`]
+/// - [`TyCtxt::emit_lint`]
+/// - [`TyCtxt::struct_lint_node`]
+/// - `LintContext::lookup`
+///
+/// ## `decorate` signature
+///
+/// The return value of `decorate` is ignored by this function. So what is the
+/// point of returning `&'b mut DiagnosticBuilder<'a, ()>`?
+///
+/// There are 2 reasons for this signature.
+///
+/// First of all, it prevents accidental use of `.emit()` -- it's clear that the
+/// builder will be later used and shouldn't be emitted right away (this is
+/// especially important because the old API expected you to call `.emit()` in
+/// the closure).
+///
+/// Second of all, it makes the most common case of adding just a single label
+/// /suggestion much nicer, since [`DiagnosticBuilder`] methods return
+/// `&mut DiagnosticBuilder`, you can just chain methods, without needed
+/// awkward `{ ...; }`:
+/// ```ignore pseudo-code
+/// struct_lint_level(
+///     ...,
+///     |lint| lint.span_label(sp, "lbl")
+///     //          ^^^^^^^^^^^^^^^^^^^^^ returns `&mut DiagnosticBuilder` by default
+/// )
+/// ```
 pub fn struct_lint_level(
     sess: &Session,
     lint: &'static Lint,
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 0e85c60a363..01fe72de612 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -54,13 +54,22 @@ macro_rules! TrivialTypeTraversalImpls {
             impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
                 fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
                     self,
-                    _: &mut F
-                ) -> ::std::result::Result<$ty, F::Error> {
+                    _: &mut F,
+                ) -> ::std::result::Result<Self, F::Error> {
                     Ok(self)
                 }
+
+                #[inline]
+                fn fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
+                    self,
+                    _: &mut F,
+                ) -> Self {
+                    self
+                }
             }
 
             impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty {
+                #[inline]
                 fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
                     &self,
                     _: &mut F)
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index c595fbec0dd..556bd24d00f 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -1,12 +1,12 @@
 //! A pass that checks to make sure private fields and methods aren't used
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
-use crate::ty::Visibility;
+use crate::ty::{DefIdTree, Visibility};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{DefId, LocalDefId};
 use std::hash::Hash;
 
 /// Represents the levels of accessibility an item can have.
@@ -27,26 +27,36 @@ pub enum AccessLevel {
     Public,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)]
+impl AccessLevel {
+    pub fn all_levels() -> [AccessLevel; 4] {
+        [
+            AccessLevel::Public,
+            AccessLevel::Exported,
+            AccessLevel::Reachable,
+            AccessLevel::ReachableFromImplTrait,
+        ]
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
 pub struct EffectiveVisibility {
-    public: Option<Visibility>,
-    exported: Option<Visibility>,
-    reachable: Option<Visibility>,
-    reachable_from_impl_trait: Option<Visibility>,
+    public: Visibility,
+    exported: Visibility,
+    reachable: Visibility,
+    reachable_from_impl_trait: Visibility,
 }
 
 impl EffectiveVisibility {
-    pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> {
+    pub fn get(&self, tag: AccessLevel) -> &Visibility {
         match tag {
             AccessLevel::Public => &self.public,
             AccessLevel::Exported => &self.exported,
             AccessLevel::Reachable => &self.reachable,
             AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
         }
-        .as_ref()
     }
 
-    fn get_mut(&mut self, tag: AccessLevel) -> &mut Option<Visibility> {
+    fn get_mut(&mut self, tag: AccessLevel) -> &mut Visibility {
         match tag {
             AccessLevel::Public => &mut self.public,
             AccessLevel::Exported => &mut self.exported,
@@ -56,7 +66,30 @@ impl EffectiveVisibility {
     }
 
     pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
-        self.get(tag).map_or(false, |vis| vis.is_public())
+        self.get(tag).is_public()
+    }
+
+    fn update(&mut self, vis: Visibility, tag: AccessLevel, tree: impl DefIdTree) -> bool {
+        let mut changed = false;
+        for level in AccessLevel::all_levels() {
+            if level <= tag {
+                let current_effective_vis = self.get_mut(level);
+                if *current_effective_vis != vis && vis.is_at_least(*current_effective_vis, tree) {
+                    changed = true;
+                    *current_effective_vis = vis;
+                }
+            }
+        }
+        changed
+    }
+
+    fn from_vis(vis: Visibility) -> EffectiveVisibility {
+        EffectiveVisibility {
+            public: vis,
+            exported: vis,
+            reachable: vis,
+            reachable_from_impl_trait: vis,
+        }
     }
 }
 
@@ -89,12 +122,7 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
 
     pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
         self.get_effective_vis(id).and_then(|effective_vis| {
-            for level in [
-                AccessLevel::Public,
-                AccessLevel::Exported,
-                AccessLevel::Reachable,
-                AccessLevel::ReachableFromImplTrait,
-            ] {
+            for level in AccessLevel::all_levels() {
                 if effective_vis.is_public_at_level(level) {
                     return Some(level);
                 }
@@ -103,21 +131,6 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
         })
     }
 
-    pub fn set_access_level(&mut self, id: Id, tag: AccessLevel) {
-        let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default();
-        for level in [
-            AccessLevel::Public,
-            AccessLevel::Exported,
-            AccessLevel::Reachable,
-            AccessLevel::ReachableFromImplTrait,
-        ] {
-            if level <= tag {
-                *effective_vis.get_mut(level) = Some(Visibility::Public);
-            }
-        }
-        self.map.insert(id, effective_vis);
-    }
-
     pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
         self.map.get(&id)
     }
@@ -129,6 +142,65 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
     pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
         AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
     }
+
+    pub fn set_access_level(
+        &mut self,
+        id: Id,
+        default_vis: impl FnOnce() -> Visibility,
+        tag: AccessLevel,
+    ) {
+        let mut effective_vis = self
+            .get_effective_vis(id)
+            .copied()
+            .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
+        for level in AccessLevel::all_levels() {
+            if level <= tag {
+                *effective_vis.get_mut(level) = Visibility::Public;
+            }
+        }
+        self.map.insert(id, effective_vis);
+    }
+}
+
+impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
+    // `parent_id` is not necessarily a parent in source code tree,
+    // it is the node from which the maximum effective visibility is inherited.
+    pub fn update(
+        &mut self,
+        id: Id,
+        nominal_vis: Visibility,
+        default_vis: impl FnOnce() -> Visibility,
+        parent_id: Id,
+        tag: AccessLevel,
+        tree: impl DefIdTree,
+    ) -> Result<bool, ()> {
+        let mut changed = false;
+        let mut current_effective_vis = self
+            .get_effective_vis(id)
+            .copied()
+            .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
+        if let Some(inherited_effective_vis) = self.get_effective_vis(parent_id) {
+            for level in AccessLevel::all_levels() {
+                if tag >= level {
+                    let inherited_effective_vis_at_level = *inherited_effective_vis.get(level);
+                    let calculated_effective_vis =
+                        if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
+                            inherited_effective_vis_at_level
+                        } else {
+                            nominal_vis
+                        };
+                    changed |= current_effective_vis.update(calculated_effective_vis, level, tree);
+                }
+            }
+        } else {
+            if !id.into().is_crate_root() {
+                return Err(());
+            }
+            changed |= current_effective_vis.update(Visibility::Public, AccessLevel::Public, tree);
+        }
+        self.map.insert(id, current_effective_vis);
+        Ok(changed)
+    }
 }
 
 impl<Id> Default for AccessLevels<Id> {
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 8f67161420d..473894ac1ca 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -4,7 +4,9 @@ use crate::mir;
 use crate::ty::subst::InternalSubsts;
 use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_session::lint;
 use rustc_span::{Span, DUMMY_SP};
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -51,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match ty::Instance::resolve_opt_const_arg(
             self, param_env,
-            // FIXME: maybe have a seperate version for resolving mir::UnevaluatedConst?
+            // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
             ct.def, ct.substs,
         ) {
             Ok(Some(instance)) => {
@@ -83,7 +85,29 @@ impl<'tcx> TyCtxt<'tcx> {
         match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: None };
-                self.const_eval_global_id_for_typeck(param_env, cid, span)
+                self.const_eval_global_id_for_typeck(param_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.
+                    //
+                    // @lcnr believes that successfully evaluating even though there are
+                    // used generic parameters is a bug of evaluation, so checking for it
+                    // here does feel somewhat sensible.
+                    if !self.features().generic_const_exprs && ct.substs.has_non_region_param() {
+                        assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst));
+                        let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def);
+                        if mir_body.is_polymorphic {
+                            let Some(local_def_id) = ct.def.did.as_local() else { return };
+                            self.struct_span_lint_hir(
+                                lint::builtin::CONST_EVALUATABLE_UNCHECKED,
+                                self.hir().local_def_id_to_hir_id(local_def_id),
+                                self.def_span(ct.def.did),
+                                "cannot use constants which depend on generic parameters in types",
+                                |err| err,
+                            )
+                        }
+                    }
+                })
             }
             Ok(None) => Err(ErrorHandled::TooGeneric),
             Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index c022ea9e5b4..e0e823e2090 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -7,9 +7,9 @@ use crate::mir::interpret::{
 };
 use crate::mir::visit::MirVisitable;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
 use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
@@ -2056,7 +2056,7 @@ pub struct Constant<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
-#[derive(Lift)]
+#[derive(Lift, TypeFoldable, TypeVisitable)]
 pub enum ConstantKind<'tcx> {
     /// This constant came from the type system
     Ty(ty::Const<'tcx>),
@@ -2448,7 +2448,7 @@ impl<'tcx> ConstantKind<'tcx> {
 
 /// An unevaluated (potentially generic) constant used in MIR.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
-#[derive(Hash, HashStable)]
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: ty::WithOptConstParam<DefId>,
     pub substs: SubstsRef<'tcx>,
@@ -2875,7 +2875,7 @@ fn pretty_print_const_value<'tcx>(
 /// `Location` represents the position of the start of the statement; or, if
 /// `statement_index` equals the number of statements, then the start of the
 /// terminator.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable, TyEncodable, TyDecodable)]
 pub struct Location {
     /// The block that the location is within.
     pub block: BasicBlock,
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index efd7357afc4..1d847d8f3d3 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -15,7 +15,7 @@ use smallvec::SmallVec;
 use std::cell::Cell;
 use std::fmt::{self, Debug};
 
-use super::{Field, SourceInfo};
+use super::{Field, Location, SourceInfo};
 
 #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
 pub enum UnsafetyViolationKind {
@@ -314,12 +314,12 @@ pub struct ClosureOutlivesRequirement<'tcx> {
     pub blame_span: Span,
 
     // ... due to this reason.
-    pub category: ConstraintCategory<'tcx>,
+    pub category: ConstraintCategory,
 }
 
 // Make sure this enum doesn't unintentionally grow
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
+rustc_data_structures::static_assert_size!(ConstraintCategory, 16);
 
 /// Outlives-constraints can be categorized to determine whether and why they
 /// are interesting (for error reporting). Order of variants indicates sort
@@ -327,8 +327,8 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 ///
 /// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
-pub enum ConstraintCategory<'tcx> {
+#[derive(TyEncodable, TyDecodable, HashStable)]
+pub enum ConstraintCategory {
     Return(ReturnConstraint),
     Yield,
     UseAsConst,
@@ -342,7 +342,7 @@ pub enum ConstraintCategory<'tcx> {
     ClosureBounds,
 
     /// Contains the function type if available.
-    CallArgument(Option<Ty<'tcx>>),
+    CallArgument(Location),
     CopyBound,
     SizedBound,
     Assignment,
@@ -368,6 +368,10 @@ pub enum ConstraintCategory<'tcx> {
     Internal,
 }
 
+TrivialTypeTraversalAndLiftImpls! {
+    ConstraintCategory,
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
 pub enum ReturnConstraint {
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 8e18cad442e..4c0974f86fb 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -3,7 +3,6 @@
 use rustc_ast::InlineAsmTemplatePiece;
 
 use super::*;
-use crate::mir;
 use crate::ty;
 
 TrivialTypeTraversalAndLiftImpls! {
@@ -27,6 +26,12 @@ TrivialTypeTraversalAndLiftImpls! {
     GeneratorSavedLocal,
 }
 
+TrivialTypeTraversalImpls! {
+    for <'tcx> {
+        ConstValue<'tcx>,
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for &'tcx [InlineAsmTemplatePiece] {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
@@ -50,44 +55,3 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
         Ok(self)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_mir_unevaluated(self)
-    }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(mir::UnevaluatedConst {
-            def: self.def,
-            substs: self.substs.try_fold_with(folder)?,
-            promoted: self.promoted,
-        })
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
-    #[inline(always)]
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_mir_const(self)
-    }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        match self {
-            ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)),
-            ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
-            ConstantKind::Unevaluated(uv, t) => {
-                Ok(ConstantKind::Unevaluated(uv.try_fold_with(folder)?, t.try_fold_with(folder)?))
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
index a136ca4d8c3..e7cd497b206 100644
--- a/compiler/rustc_middle/src/mir/type_visitable.rs
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -1,41 +1,9 @@
 //! `TypeVisitable` implementations for MIR types
 
 use super::*;
-use crate::mir;
 
 impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
-
-impl<'tcx> TypeVisitable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_mir_unevaluated(*self)
-    }
-}
-
-impl<'tcx> TypeSuperVisitable<'tcx> for mir::UnevaluatedConst<'tcx> {
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.substs.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_mir_const(*self)
-    }
-}
-
-impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> {
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        match *self {
-            ConstantKind::Ty(c) => c.visit_with(visitor),
-            ConstantKind::Val(_, t) => t.visit_with(visitor),
-            ConstantKind::Unevaluated(uv, t) => {
-                uv.visit_with(visitor)?;
-                t.visit_with(visitor)
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index cfdc21ac234..2ab3b0d27c8 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -20,19 +20,19 @@ use rustc_span::def_id::LOCAL_CRATE;
 // as they will raise an fatal error on query cycles instead.
 rustc_queries! {
     query trigger_delay_span_bug(key: DefId) -> () {
-        desc { "trigger a delay span bug" }
+        desc { "triggering a delay span bug" }
     }
 
     query resolutions(_: ()) -> &'tcx ty::ResolverOutputs {
         eval_always
         no_hash
-        desc { "get the resolver outputs" }
+        desc { "getting the resolver outputs" }
     }
 
     query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
         eval_always
         no_hash
-        desc { "get the resolver for lowering" }
+        desc { "getting the resolver for lowering" }
     }
 
     /// Return the span for a definition.
@@ -40,7 +40,7 @@ rustc_queries! {
     /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
     /// of rustc_middle::hir::source_map.
     query source_span(key: LocalDefId) -> Span {
-        desc { "get the source span" }
+        desc { "getting the source span" }
     }
 
     /// Represents crate as a whole (as distinct from the top-level crate module).
@@ -52,14 +52,14 @@ rustc_queries! {
     query hir_crate(key: ()) -> Crate<'tcx> {
         arena_cache
         eval_always
-        desc { "get the crate HIR" }
+        desc { "getting the crate HIR" }
     }
 
     /// All items in the crate.
     query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
         arena_cache
         eval_always
-        desc { "get HIR crate items" }
+        desc { "getting HIR crate items" }
     }
 
     /// The items in a module.
@@ -68,7 +68,7 @@ rustc_queries! {
     /// Avoid calling this query directly.
     query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
         arena_cache
-        desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
     }
 
@@ -77,7 +77,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner(key: hir::OwnerId) -> Option<crate::hir::Owner<'tcx>> {
-        desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR ID for the given `LocalDefId` owner `key`.
@@ -85,7 +85,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
-        desc { |tcx| "HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR node's parent for the HIR owner `key`.
@@ -93,7 +93,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
-        desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
@@ -101,7 +101,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner_nodes(key: hir::OwnerId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
-        desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Gives access to the HIR attributes inside the HIR owner `key`.
@@ -109,7 +109,7 @@ rustc_queries! {
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
-        desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
@@ -138,7 +138,7 @@ rustc_queries! {
     /// Given the def_id of a const-generic parameter, computes the associated default const
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
     query const_param_default(param: DefId) -> ty::Const<'tcx> {
-        desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param)  }
+        desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param)  }
         cache_on_disk_if { param.is_local() }
         separate_provide_extern
     }
@@ -167,7 +167,7 @@ rustc_queries! {
     query collect_trait_impl_trait_tys(key: DefId)
         -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
     {
-        desc { "compare an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
+        desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
@@ -290,11 +290,11 @@ rustc_queries! {
 
     query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
         eval_always
-        desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
-        desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
         separate_provide_extern
     }
 
@@ -306,7 +306,7 @@ rustc_queries! {
 
     /// Checks whether a type is representable or infinitely sized
     query representability(_: LocalDefId) -> rustc_middle::ty::Representability {
-        desc { "checking if {:?} is representable", tcx.def_path_str(key.to_def_id()) }
+        desc { "checking if `{}` is representable", tcx.def_path_str(key.to_def_id()) }
         // infinitely sized types will cause a cycle
         cycle_delay_bug
         // we don't want recursive representability calls to be forced with
@@ -317,7 +317,7 @@ rustc_queries! {
 
     /// An implementation detail for the `representability` query
     query representability_adt_ty(_: Ty<'tcx>) -> rustc_middle::ty::Representability {
-        desc { "checking if {:?} is representable", key }
+        desc { "checking if `{}` is representable", key }
         cycle_delay_bug
         anon
     }
@@ -383,7 +383,7 @@ rustc_queries! {
     /// See the README for the `mir` module for details.
     query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
         desc {
-            |tcx| "processing MIR for {}`{}`",
+            |tcx| "preparing {}`{}` for borrow checking",
             if key.const_param_did.is_some() { "the const argument " } else { "" },
             tcx.def_path_str(key.did.to_def_id()),
         }
@@ -395,7 +395,7 @@ rustc_queries! {
         key: DefId
     ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
         desc {
-            |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
+            |tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
         }
         separate_provide_extern
     }
@@ -405,7 +405,7 @@ rustc_queries! {
     ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
         desc {
             |tcx|
-            "building an abstract representation for the const argument {}",
+            "building an abstract representation for the const argument `{}`",
             tcx.def_path_str(key.0.to_def_id()),
         }
     }
@@ -414,7 +414,7 @@ rustc_queries! {
         ty::ParamEnvAnd<'tcx, (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>
     )>) -> bool {
         desc {
-            |tcx| "trying to unify the generic constants {} and {}",
+            |tcx| "trying to unify the generic constants `{}` and `{}`",
             tcx.def_path_str(key.value.0.def.did), tcx.def_path_str(key.value.1.def.did)
         }
     }
@@ -436,7 +436,7 @@ rustc_queries! {
 
     query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
         desc {
-            |tcx| "MIR for CTFE of the const argument `{}`",
+            |tcx| "caching MIR for CTFE of the const argument `{}`",
             tcx.def_path_str(key.0.to_def_id())
         }
     }
@@ -448,7 +448,7 @@ rustc_queries! {
         ) {
         no_hash
         desc {
-            |tcx| "processing {}`{}`",
+            |tcx| "processing MIR for {}`{}`",
             if key.const_param_did.is_some() { "the const argument " } else { "" },
             tcx.def_path_str(key.did.to_def_id()),
         }
@@ -459,7 +459,7 @@ rustc_queries! {
     ) -> Vec<rustc_span::Symbol> {
         arena_cache
         desc {
-            |tcx| "symbols for captures of closure `{}` in `{}`",
+            |tcx| "finding symbols for captures of closure `{}` in `{}`",
             tcx.def_path_str(key.1.to_def_id()),
             tcx.def_path_str(key.0.to_def_id())
         }
@@ -521,12 +521,12 @@ rustc_queries! {
         // queries). Making it anonymous avoids hashing the result, which
         // may save a bit of time.
         anon
-        desc { "erasing regions from `{:?}`", ty }
+        desc { "erasing regions from `{}`", ty }
     }
 
     query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
         arena_cache
-        desc { "wasm import module map" }
+        desc { "getting wasm import module map" }
     }
 
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
@@ -706,7 +706,7 @@ rustc_queries! {
     /// Collects the associated items defined on a trait or impl.
     query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
         arena_cache
-        desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+        desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
     }
 
     /// Maps from associated items on a trait to the corresponding associated
@@ -732,7 +732,7 @@ rustc_queries! {
     ///`{ trait_f: impl_f, trait_g: impl_g }`
     query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
         arena_cache
-        desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+        desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
     }
 
     /// Given an `impl_id`, return the trait it implements.
@@ -804,7 +804,7 @@ rustc_queries! {
     /// Note that we've liberated the late bound regions of function signatures, so
     /// this can not be used to check whether these types are well formed.
     query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
-        desc { |tcx| "computing the implied bounds of {}", tcx.def_path_str(key) }
+        desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
     }
 
     /// Computes the signature of the function.
@@ -853,7 +853,7 @@ rustc_queries! {
     }
 
     query check_liveness(key: DefId) {
-        desc { |tcx| "checking liveness of variables in {}", tcx.def_path_str(key) }
+        desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
     }
 
     /// Return the live symbols in the crate for dead code check.
@@ -865,7 +865,7 @@ rustc_queries! {
         FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
     ) {
         arena_cache
-        desc { "find live symbols in crate" }
+        desc { "finding live symbols in crate" }
     }
 
     query check_mod_deathness(key: LocalDefId) -> () {
@@ -913,7 +913,7 @@ rustc_queries! {
     }
 
     query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
-        desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
     }
 
@@ -942,7 +942,7 @@ rustc_queries! {
     /// Not meant to be used directly outside of coherence.
     query crate_inherent_impls(k: ()) -> CrateInherentImpls {
         arena_cache
-        desc { "all inherent impls defined in crate" }
+        desc { "finding all inherent impls defined in crate" }
     }
 
     /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
@@ -1032,7 +1032,7 @@ rustc_queries! {
     query try_destructure_mir_constant(
         key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
     ) -> Option<mir::DestructuredConstant<'tcx>> {
-        desc { "destructuring mir constant"}
+        desc { "destructuring MIR constant"}
         remap_env_constness
     }
 
@@ -1041,12 +1041,12 @@ rustc_queries! {
     query deref_mir_constant(
         key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
     ) -> mir::ConstantKind<'tcx> {
-        desc { "dereferencing mir constant" }
+        desc { "dereferencing MIR constant" }
         remap_env_constness
     }
 
     query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
-        desc { "get a &core::panic::Location referring to a span" }
+        desc { "getting a &core::panic::Location referring to a span" }
     }
 
     // FIXME get rid of this with valtrees
@@ -1068,7 +1068,7 @@ rustc_queries! {
     /// Performs part of the privacy check and computes "access levels".
     query privacy_access_levels(_: ()) -> &'tcx AccessLevels {
         eval_always
-        desc { "privacy access levels" }
+        desc { "checking privacy access levels" }
     }
     query check_private_in_public(_: ()) -> () {
         eval_always
@@ -1196,29 +1196,29 @@ rustc_queries! {
     }
 
     query is_ctfe_mir_available(key: DefId) -> bool {
-        desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "checking if item has CTFE MIR available: `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
     query is_mir_available(key: DefId) -> bool {
-        desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "checking if item has MIR available: `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
     query own_existential_vtable_entries(
-        key: ty::PolyExistentialTraitRef<'tcx>
+        key: DefId
     ) -> &'tcx [DefId] {
-        desc { |tcx| "finding all existential vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+        desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) }
     }
 
     query vtable_entries(key: ty::PolyTraitRef<'tcx>)
                         -> &'tcx [ty::VtblEntry<'tcx>] {
-        desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+        desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
     }
 
     query vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> {
-        desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+        desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable",
             key.1, key.0 }
     }
 
@@ -1238,13 +1238,13 @@ rustc_queries! {
 
     /// Return all `impl` blocks in the current crate.
     query all_local_trait_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap<DefId, Vec<LocalDefId>> {
-        desc { "local trait impls" }
+        desc { "finding local trait impls" }
     }
 
     /// Given a trait `trait_id`, return all known `impl` blocks.
     query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
         arena_cache
-        desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
+        desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) }
     }
 
     query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
@@ -1253,7 +1253,7 @@ rustc_queries! {
         cache_on_disk_if { true }
     }
     query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
-        desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
+        desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
     }
 
     /// Gets the ParameterEnvironment for a given item; this environment
@@ -1311,7 +1311,7 @@ rustc_queries! {
     /// correctly.
     query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
         desc {
-            "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
+            "computing whether `{}` implements `PartialStructuralEq` and `StructuralEq`",
             ty
         }
     }
@@ -1370,13 +1370,13 @@ rustc_queries! {
 
     query dylib_dependency_formats(_: CrateNum)
                                     -> &'tcx [(CrateNum, LinkagePreference)] {
-        desc { "dylib dependency formats of crate" }
+        desc { "getting dylib dependency formats of crate" }
         separate_provide_extern
     }
 
     query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
         arena_cache
-        desc { "get the linkage format of all dependencies" }
+        desc { "getting the linkage format of all dependencies" }
     }
 
     query is_compiler_builtins(_: CrateNum) -> bool {
@@ -1398,31 +1398,31 @@ rustc_queries! {
     }
     query is_profiler_runtime(_: CrateNum) -> bool {
         fatal_cycle
-        desc { "query a crate is `#![profiler_runtime]`" }
+        desc { "checking if a crate is `#![profiler_runtime]`" }
         separate_provide_extern
     }
     query has_ffi_unwind_calls(key: LocalDefId) -> bool {
-        desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+        desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
     }
     query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
         fatal_cycle
-        desc { "query a crate's required panic strategy" }
+        desc { "getting a crate's required panic strategy" }
         separate_provide_extern
     }
     query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
         fatal_cycle
-        desc { "query a crate's configured panic-in-drop strategy" }
+        desc { "getting a crate's configured panic-in-drop strategy" }
         separate_provide_extern
     }
     query is_no_builtins(_: CrateNum) -> bool {
         fatal_cycle
-        desc { "test whether a crate has `#![no_builtins]`" }
+        desc { "getting whether a crate has `#![no_builtins]`" }
         separate_provide_extern
     }
     query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
         fatal_cycle
-        desc { "query a crate's symbol mangling version" }
+        desc { "getting a crate's symbol mangling version" }
         separate_provide_extern
     }
 
@@ -1437,7 +1437,7 @@ rustc_queries! {
     }
     query in_scope_traits_map(_: hir::OwnerId)
         -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
-        desc { "traits in scope at a block" }
+        desc { "getting traits in scope at a block" }
     }
 
     query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
@@ -1587,18 +1587,8 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query is_dllimport_foreign_item(def_id: DefId) -> bool {
-        desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
-    }
-    query is_statically_included_foreign_item(def_id: DefId) -> bool {
-        desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) }
-    }
-    query native_library_kind(def_id: DefId)
-        -> Option<NativeLibKind> {
-        desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
-    }
     query native_library(def_id: DefId) -> Option<&'tcx NativeLib> {
-        desc { |tcx| "native_library({})", tcx.def_path_str(def_id) }
+        desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
     }
 
     /// Does lifetime resolution, but does not descend into trait items. This
@@ -1653,14 +1643,13 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Computes the set of modules from which this type is visibly uninhabited.
-    /// To check whether a type is uninhabited at all (not just from a given module), you could
-    /// check whether the forest is empty.
-    query type_uninhabited_from(
-        key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
-    ) -> ty::inhabitedness::DefIdForest<'tcx> {
-        desc { "computing the inhabitedness of `{:?}`", key }
-        remap_env_constness
+    query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> {
+        desc { "computing the uninhabited predicate of `{:?}`", key }
+    }
+
+    /// Do not call this query directly: invoke `Ty::inhabited_predicate` instead.
+    query inhabited_predicate_type(key: Ty<'tcx>) -> ty::inhabitedness::InhabitedPredicate<'tcx> {
+        desc { "computing the uninhabited predicate of `{}`", key }
     }
 
     query dep_kind(_: CrateNum) -> CrateDepKind {
@@ -1698,7 +1687,7 @@ rustc_queries! {
     }
     /// Whether the function is an intrinsic
     query is_intrinsic(def_id: DefId) -> bool {
-        desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
+        desc { |tcx| "checking whether `{}` is an intrinsic", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
     /// Returns the lang items defined in another crate by loading it from metadata.
@@ -1765,12 +1754,12 @@ rustc_queries! {
     /// is marked as a private dependency
     query is_private_dep(c: CrateNum) -> bool {
         eval_always
-        desc { "check whether crate {} is a private dependency", c }
+        desc { "checking whether crate `{}` is a private dependency", c }
         separate_provide_extern
     }
     query allocator_kind(_: ()) -> Option<AllocatorKind> {
         eval_always
-        desc { "allocator kind for the current crate" }
+        desc { "getting the allocator kind for the current crate" }
     }
 
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
@@ -1783,7 +1772,7 @@ rustc_queries! {
         desc { "looking up all possibly unused extern crates" }
     }
     query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
-        desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+        desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
     query stability_index(_: ()) -> stability::Index {
@@ -1809,7 +1798,7 @@ rustc_queries! {
     ///   correspond to a publicly visible symbol in `cnum` machine code.
     /// - The `exported_symbols` sets of different crates do not intersect.
     query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
-        desc { "exported_symbols" }
+        desc { "collecting exported symbols for crate `{}`", cnum}
         cache_on_disk_if { *cnum == LOCAL_CRATE }
         separate_provide_extern
     }
@@ -1818,6 +1807,7 @@ rustc_queries! {
         eval_always
         desc { "collect_and_partition_mono_items" }
     }
+
     query is_codegened_item(def_id: DefId) -> bool {
         desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
     }
@@ -1825,12 +1815,13 @@ rustc_queries! {
     /// All items participating in code generation together with items inlined into them.
     query codegened_and_inlined_items(_: ()) -> &'tcx DefIdSet {
         eval_always
-       desc { "codegened_and_inlined_items" }
+        desc { "collecting codegened and inlined items" }
     }
 
-    query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
-        desc { "codegen_unit" }
+    query codegen_unit(sym: Symbol) -> &'tcx CodegenUnit<'tcx> {
+        desc { "getting codegen unit `{sym}`" }
     }
+
     query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
         cache_on_disk_if { key.def_id().is_local() }
         desc {
@@ -1839,6 +1830,7 @@ rustc_queries! {
         }
         separate_provide_extern
     }
+
     query backend_optimization_level(_: ()) -> OptLevel {
         desc { "optimization level used by backend" }
     }
@@ -1849,7 +1841,7 @@ rustc_queries! {
     /// has been destroyed.
     query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
         eval_always
-        desc { "output_filenames" }
+        desc { "getting output filenames" }
     }
 
     /// Do not call this query directly: invoke `normalize` instead.
@@ -1859,7 +1851,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1871,21 +1863,13 @@ rustc_queries! {
         remap_env_constness
     }
 
-    /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
-    query try_normalize_mir_const_after_erasing_regions(
-        goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
-    ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
-        desc { "normalizing `{}`", goal.value }
-        remap_env_constness
-    }
-
     query implied_outlives_bounds(
         goal: CanonicalTyGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
         NoSolution,
     > {
-        desc { "computing implied outlives bounds for `{:?}`", goal }
+        desc { "computing implied outlives bounds for `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1897,7 +1881,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
         NoSolution,
     > {
-        desc { "computing dropck types for `{:?}`", goal }
+        desc { "computing dropck types for `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1925,7 +1909,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
+        desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1936,7 +1920,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_eq` `{:?}`", goal }
+        desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1947,7 +1931,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_subtype` `{:?}`", goal }
+        desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
         remap_env_constness
     }
 
@@ -1958,7 +1942,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
         NoSolution,
     > {
-        desc { "evaluating `type_op_prove_predicate` `{:?}`", goal }
+        desc { "evaluating `type_op_prove_predicate` `{:?}`", goal.value.value }
     }
 
     /// Do not call this query directly: part of the `Normalize` type-op
@@ -1968,7 +1952,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{}`", goal.value.value.value }
         remap_env_constness
     }
 
@@ -1979,7 +1963,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{:?}`", goal.value.value.value }
         remap_env_constness
     }
 
@@ -1990,7 +1974,7 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{:?}`", goal.value.value.value }
         remap_env_constness
     }
 
@@ -2001,20 +1985,20 @@ rustc_queries! {
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
         NoSolution,
     > {
-        desc { "normalizing `{:?}`", goal }
+        desc { "normalizing `{:?}`", goal.value.value.value }
         remap_env_constness
     }
 
     query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
         desc { |tcx|
-            "impossible substituted predicates:`{}`",
+            "checking impossible substituted predicates: `{}`",
             tcx.def_path_str(key.0)
         }
     }
 
     query is_impossible_method(key: (DefId, DefId)) -> bool {
         desc { |tcx|
-            "checking if {} is impossible to call within {}",
+            "checking if `{}` is impossible to call within `{}`",
             tcx.def_path_str(key.1),
             tcx.def_path_str(key.0),
         }
@@ -2023,7 +2007,7 @@ rustc_queries! {
     query method_autoderef_steps(
         goal: CanonicalTyGoal<'tcx>
     ) -> MethodAutoderefStepsResult<'tcx> {
-        desc { "computing autoderef types for `{:?}`", goal }
+        desc { "computing autoderef types for `{}`", goal.value.value }
         remap_env_constness
     }
 
@@ -2071,7 +2055,7 @@ rustc_queries! {
     }
 
     query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
-        desc { "normalizing opaque types in {:?}", key }
+        desc { "normalizing opaque types in `{:?}`", key }
     }
 
     /// Checks whether a type is definitely uninhabited. This is
@@ -2081,7 +2065,7 @@ rustc_queries! {
     /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
     /// size, to account for partial initialisation. See #49298 for details.)
     query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-        desc { "conservatively checking if {:?} is privately uninhabited", key }
+        desc { "conservatively checking if `{}` is privately uninhabited", key.value }
         remap_env_constness
     }
 
@@ -2101,7 +2085,7 @@ rustc_queries! {
         arena_cache
         eval_always
         no_hash
-        desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
+        desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 }
     }
 
 
@@ -2120,11 +2104,11 @@ rustc_queries! {
     }
 
     query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if {:?} permits being left uninit", key.ty }
+        desc { "checking to see if `{}` permits being left uninit", key.ty }
     }
 
     query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if {:?} permits being left zeroed", key.ty }
+        desc { "checking to see if `{}` permits being left zeroed", key.ty }
     }
 
     query compare_assoc_const_impl_item_with_trait_item(
@@ -2132,4 +2116,9 @@ rustc_queries! {
     ) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) }
     }
+
+    query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
+        desc { |tcx| "deducing parameter attributes for {}", tcx.def_path_str(def_id) }
+        separate_provide_extern
+    }
 }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a635e0463e5..3adc2e1b73e 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -185,7 +185,7 @@ impl<'tcx> ObligationCause<'tcx> {
         self
     }
 
-    pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
+    pub fn to_constraint_category(&self) -> ConstraintCategory {
         match self.code() {
             MatchImpl(cause, _) => cause.to_constraint_category(),
             AscribeUserTypeProvePredicate(predicate_span) => {
@@ -598,11 +598,6 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 ///     // type parameters, ImplSource will carry resolutions for those as well:
 ///     concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
 ///
-///     // Case A: ImplSource points at a specific impl. Only possible when
-///     // type is concretely known. If the impl itself has bounded
-///     // type parameters, ImplSource will carry resolutions for those as well:
-///     concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
-///
 ///     // Case B: ImplSource must be provided by caller. This applies when
 ///     // type is a type parameter.
 ///     param.clone();    // ImplSource::Param
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 51137c52659..14ec88b7e0d 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -455,6 +455,7 @@ impl_arena_copy_decoder! {<'tcx>
     rustc_span::def_id::DefId,
     rustc_span::def_id::LocalDefId,
     (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+    ty::DeducedParamAttrs,
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 315e3794f15..f998e608344 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -263,6 +263,10 @@ impl<'tcx> Const<'tcx> {
         self.try_eval_usize(tcx, param_env)
             .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
     }
+
+    pub fn is_ct_infer(self) -> bool {
+        matches!(self.kind(), ty::ConstKind::Infer(_))
+    }
 }
 
 pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index c444ec23563..4ab761e0715 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -5,6 +5,7 @@ use crate::mir::interpret::{AllocId, ConstValue, Scalar};
 use crate::ty::subst::{InternalSubsts, SubstsRef};
 use crate::ty::ParamEnv;
 use crate::ty::{self, TyCtxt, TypeVisitable};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -14,7 +15,7 @@ use super::ScalarInt;
 
 /// An unevaluated (potentially generic) constant used in the type-system.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
-#[derive(Hash, HashStable)]
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: ty::WithOptConstParam<DefId>,
     pub substs: SubstsRef<'tcx>,
@@ -108,7 +109,6 @@ impl<'tcx> ConstKind<'tcx> {
 
 /// An inference variable for a const, for use in const generics.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
-#[derive(HashStable)]
 pub enum InferConst<'tcx> {
     /// Infer the value of the const.
     Var(ty::ConstVid<'tcx>),
@@ -116,6 +116,15 @@ pub enum InferConst<'tcx> {
     Fresh(u32),
 }
 
+impl<CTX> HashStable<CTX> for InferConst<'_> {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        match self {
+            InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
+            InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
+        }
+    }
+}
+
 enum EvalMode {
     Typeck,
     Mir,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index ad63f6dbb54..0816a5cb8f1 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -198,9 +198,9 @@ impl<'tcx> CtxtInterners<'tcx> {
                 .intern(kind, |kind| {
                     let flags = super::flags::FlagComputation::for_kind(&kind);
 
-                    // It's impossible to hash inference regions (and will ICE), so we don't need to try to cache them.
+                    // It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them.
                     // Without incremental, we rarely stable-hash types, so let's not do it proactively.
-                    let stable_hash = if flags.flags.intersects(TypeFlags::HAS_RE_INFER)
+                    let stable_hash = if flags.flags.intersects(TypeFlags::NEEDS_INFER)
                         || sess.opts.incremental.is_none()
                     {
                         Fingerprint::ZERO
@@ -2823,6 +2823,11 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
+    /// Emit a lint at the appropriate level for a hir node, with an associated span.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     pub fn struct_span_lint_hir(
         self,
         lint: &'static Lint,
@@ -2848,6 +2853,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag))
     }
 
+    /// Emit a lint at the appropriate level for a hir node.
+    ///
+    /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+    ///
+    /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
     pub fn struct_lint_node(
         self,
         lint: &'static Lint,
@@ -2944,6 +2954,21 @@ impl<'tcx> TyCtxtAt<'tcx> {
     }
 }
 
+/// Parameter attributes that can only be determined by examining the body of a function instead
+/// of just its signature.
+///
+/// These can be useful for optimization purposes when a function is directly called. We compute
+/// them and store them into the crate metadata so that downstream crates can make use of them.
+///
+/// Right now, we only have `read_only`, but `no_capture` and `no_alias` might be useful in the
+/// future.
+#[derive(Clone, Copy, PartialEq, Debug, Default, TyDecodable, TyEncodable, HashStable)]
+pub struct DeducedParamAttrs {
+    /// The parameter is marked immutable in the function and contains no `UnsafeCell` (i.e. its
+    /// type is freeze).
+    pub read_only: bool,
+}
+
 // We are comparing types with different invariant lifetimes, so `ptr::eq`
 // won't work for us.
 fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index ffade628e53..b8fd01e6a77 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -513,7 +513,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(borrowck::const_not_used_in_type_alias)]
+#[diag(borrowck_const_not_used_in_type_alias)]
 pub(super) struct ConstNotUsedTraitAlias {
     pub ct: String,
     #[primary_span]
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 3226950e79e..ffdac93bcd0 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,4 +1,3 @@
-use crate::mir;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, Ty, TyCtxt, TypeFlags};
@@ -67,8 +66,4 @@ impl<'tcx> TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
             _ => self.tcx.lifetimes.re_erased,
         }
     }
-
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        c.super_fold_with(self)
-    }
 }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index a6d0678e99d..7201737be65 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -34,12 +34,6 @@ impl FlagComputation {
         result.flags
     }
 
-    pub fn for_unevaluated_const(uv: ty::UnevaluatedConst<'_>) -> TypeFlags {
-        let mut result = FlagComputation::new();
-        result.add_unevaluated_const(uv);
-        result.flags
-    }
-
     fn add_flags(&mut self, flags: TypeFlags) {
         self.flags = self.flags | flags;
     }
@@ -256,7 +250,7 @@ impl FlagComputation {
                 self.add_substs(substs);
             }
             ty::PredicateKind::ConstEvaluatable(uv) => {
-                self.add_unevaluated_const(uv);
+                self.add_const(uv);
             }
             ty::PredicateKind::ConstEquate(expected, found) => {
                 self.add_const(expected);
@@ -289,7 +283,10 @@ impl FlagComputation {
     fn add_const(&mut self, c: ty::Const<'_>) {
         self.add_ty(c.ty());
         match c.kind() {
-            ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
+            ty::ConstKind::Unevaluated(uv) => {
+                self.add_substs(uv.substs);
+                self.add_flags(TypeFlags::HAS_CT_PROJECTION);
+            }
             ty::ConstKind::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
@@ -313,11 +310,6 @@ impl FlagComputation {
         }
     }
 
-    fn add_unevaluated_const(&mut self, ct: ty::UnevaluatedConst<'_>) {
-        self.add_substs(ct.substs);
-        self.add_flags(TypeFlags::HAS_CT_PROJECTION);
-    }
-
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
         match projection.term.unpack() {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index ce4a46e362d..54f1499eb3d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -42,7 +42,6 @@
 //!     - ty.super_fold_with(folder)
 //! - u.fold_with(folder)
 //! ```
-use crate::mir;
 use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
@@ -127,27 +126,9 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
         c.super_fold_with(self)
     }
 
-    fn fold_ty_unevaluated(
-        &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
-    ) -> ty::UnevaluatedConst<'tcx> {
-        uv.super_fold_with(self)
-    }
-
-    fn fold_mir_unevaluated(
-        &mut self,
-        uv: mir::UnevaluatedConst<'tcx>,
-    ) -> mir::UnevaluatedConst<'tcx> {
-        uv.super_fold_with(self)
-    }
-
     fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
         p.super_fold_with(self)
     }
-
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        bug!("most type folders should not be folding MIR datastructures: {:?}", c)
-    }
 }
 
 /// This trait is implemented for every folding traversal. There is a fold
@@ -181,33 +162,12 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
         c.try_super_fold_with(self)
     }
 
-    fn try_fold_ty_unevaluated(
-        &mut self,
-        c: ty::UnevaluatedConst<'tcx>,
-    ) -> Result<ty::UnevaluatedConst<'tcx>, Self::Error> {
-        c.try_super_fold_with(self)
-    }
-
-    fn try_fold_mir_unevaluated(
-        &mut self,
-        c: mir::UnevaluatedConst<'tcx>,
-    ) -> Result<mir::UnevaluatedConst<'tcx>, Self::Error> {
-        c.try_super_fold_with(self)
-    }
-
     fn try_fold_predicate(
         &mut self,
         p: ty::Predicate<'tcx>,
     ) -> Result<ty::Predicate<'tcx>, Self::Error> {
         p.try_super_fold_with(self)
     }
-
-    fn try_fold_mir_const(
-        &mut self,
-        c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        bug!("most type folders should not be folding MIR datastructures: {:?}", c)
-    }
 }
 
 // This blanket implementation of the fallible trait for infallible folders
@@ -241,30 +201,9 @@ where
         Ok(self.fold_const(c))
     }
 
-    fn try_fold_ty_unevaluated(
-        &mut self,
-        c: ty::UnevaluatedConst<'tcx>,
-    ) -> Result<ty::UnevaluatedConst<'tcx>, !> {
-        Ok(self.fold_ty_unevaluated(c))
-    }
-
-    fn try_fold_mir_unevaluated(
-        &mut self,
-        c: mir::UnevaluatedConst<'tcx>,
-    ) -> Result<mir::UnevaluatedConst<'tcx>, !> {
-        Ok(self.fold_mir_unevaluated(c))
-    }
-
     fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
         Ok(self.fold_predicate(p))
     }
-
-    fn try_fold_mir_const(
-        &mut self,
-        c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, !> {
-        Ok(self.fold_mir_const(c))
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
deleted file mode 100644
index c4ad698ba76..00000000000
--- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::ty::context::TyCtxt;
-use crate::ty::{DefId, DefIdTree};
-use rustc_span::def_id::CRATE_DEF_ID;
-use smallvec::SmallVec;
-use std::mem;
-
-use DefIdForest::*;
-
-/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
-/// if a `DefId` representing a module is contained in the forest then all
-/// `DefId`s defined in that module or submodules are also implicitly contained
-/// in the forest.
-///
-/// This is used to represent a set of modules in which a type is visibly
-/// uninhabited.
-///
-/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
-/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
-/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
-#[derive(Copy, Clone, HashStable, Debug)]
-pub enum DefIdForest<'a> {
-    Empty,
-    Single(DefId),
-    /// This variant is very rare.
-    /// Invariant: >1 elements
-    Multiple(&'a [DefId]),
-}
-
-/// Tests whether a slice of roots contains a given DefId.
-#[inline]
-fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
-    slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
-}
-
-impl<'tcx> DefIdForest<'tcx> {
-    /// Creates an empty forest.
-    pub fn empty() -> DefIdForest<'tcx> {
-        DefIdForest::Empty
-    }
-
-    /// Creates a forest consisting of a single tree representing the entire
-    /// crate.
-    #[inline]
-    pub fn full() -> DefIdForest<'tcx> {
-        DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
-    }
-
-    /// Creates a forest containing a `DefId` and all its descendants.
-    pub fn from_id(id: DefId) -> DefIdForest<'tcx> {
-        DefIdForest::Single(id)
-    }
-
-    fn as_slice(&self) -> &[DefId] {
-        match self {
-            Empty => &[],
-            Single(id) => std::slice::from_ref(id),
-            Multiple(root_ids) => root_ids,
-        }
-    }
-
-    // Only allocates in the rare `Multiple` case.
-    fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> {
-        match &root_ids[..] {
-            [] => Empty,
-            [id] => Single(*id),
-            _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)),
-        }
-    }
-
-    /// Tests whether the forest is empty.
-    pub fn is_empty(&self) -> bool {
-        match self {
-            Empty => true,
-            Single(..) | Multiple(..) => false,
-        }
-    }
-
-    /// Iterate over the set of roots.
-    fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
-        self.as_slice().iter().copied()
-    }
-
-    /// Tests whether the forest contains a given DefId.
-    pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
-        slice_contains(tcx, self.as_slice(), id)
-    }
-
-    /// Calculate the intersection of a collection of forests.
-    pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
-    where
-        I: IntoIterator<Item = DefIdForest<'tcx>>,
-    {
-        let mut iter = iter.into_iter();
-        let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
-            SmallVec::from_slice(first.as_slice())
-        } else {
-            return DefIdForest::full();
-        };
-
-        let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
-        for next_forest in iter {
-            // No need to continue if the intersection is already empty.
-            if ret.is_empty() || next_forest.is_empty() {
-                return DefIdForest::empty();
-            }
-
-            // We keep the elements in `ret` that are also in `next_forest`.
-            next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
-            // We keep the elements in `next_forest` that are also in `ret`.
-            next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
-
-            mem::swap(&mut next_ret, &mut ret);
-            next_ret.clear();
-        }
-        DefIdForest::from_vec(tcx, ret)
-    }
-
-    /// Calculate the union of a collection of forests.
-    pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
-    where
-        I: IntoIterator<Item = DefIdForest<'tcx>>,
-    {
-        let mut ret: SmallVec<[_; 1]> = SmallVec::new();
-        let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
-        for next_forest in iter {
-            // Union with the empty set is a no-op.
-            if next_forest.is_empty() {
-                continue;
-            }
-
-            // We add everything in `ret` that is not in `next_forest`.
-            next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
-            // We add everything in `next_forest` that we haven't added yet.
-            for id in next_forest.iter() {
-                if !slice_contains(tcx, &next_ret, id) {
-                    next_ret.push(id);
-                }
-            }
-
-            mem::swap(&mut next_ret, &mut ret);
-            next_ret.clear();
-        }
-        DefIdForest::from_vec(tcx, ret)
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
new file mode 100644
index 00000000000..b7aa455727d
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -0,0 +1,204 @@
+use crate::ty::context::TyCtxt;
+use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty};
+
+/// Represents whether some type is inhabited in a given context.
+/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
+/// containing either of those types.
+/// A type's inhabitedness may depend on the `ParamEnv` as well as what types
+/// are visible in the current module.
+#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+pub enum InhabitedPredicate<'tcx> {
+    /// Inhabited
+    True,
+    /// Uninhabited
+    False,
+    /// Uninhabited when a const value is non-zero. This occurs when there is an
+    /// array of uninhabited items, but the array is inhabited if it is empty.
+    ConstIsZero(ty::Const<'tcx>),
+    /// Uninhabited if within a certain module. This occurs when an uninhabited
+    /// type has restricted visibility.
+    NotInModule(DefId),
+    /// Inhabited if some generic type is inhabited.
+    /// These are replaced by calling [`Self::subst`].
+    GenericType(Ty<'tcx>),
+    /// A AND B
+    And(&'tcx [InhabitedPredicate<'tcx>; 2]),
+    /// A OR B
+    Or(&'tcx [InhabitedPredicate<'tcx>; 2]),
+}
+
+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 {
+        let Ok(result) = self
+            .apply_inner::<!>(tcx, param_env, &|id| Ok(tcx.is_descendant_of(module_def_id, id)));
+        result
+    }
+
+    /// 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, &|_| Err(())).ok()
+    }
+
+    fn apply_inner<E>(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        in_module: &impl Fn(DefId) -> Result<bool, E>,
+    ) -> Result<bool, E> {
+        match self {
+            Self::False => Ok(false),
+            Self::True => Ok(true),
+            Self::ConstIsZero(const_) => match const_.try_eval_usize(tcx, param_env) {
+                None | Some(0) => Ok(true),
+                Some(1..) => Ok(false),
+            },
+            Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod),
+            Self::GenericType(_) => Ok(true),
+            Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
+            Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
+        }
+    }
+
+    pub fn and(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
+        self.reduce_and(tcx, other).unwrap_or_else(|| Self::And(tcx.arena.alloc([self, other])))
+    }
+
+    pub fn or(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
+        self.reduce_or(tcx, other).unwrap_or_else(|| Self::Or(tcx.arena.alloc([self, other])))
+    }
+
+    pub fn all(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
+        let mut result = Self::True;
+        for pred in iter {
+            if matches!(pred, Self::False) {
+                return Self::False;
+            }
+            result = result.and(tcx, pred);
+        }
+        result
+    }
+
+    pub fn any(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
+        let mut result = Self::False;
+        for pred in iter {
+            if matches!(pred, Self::True) {
+                return Self::True;
+            }
+            result = result.or(tcx, pred);
+        }
+        result
+    }
+
+    fn reduce_and(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
+        match (self, other) {
+            (Self::True, a) | (a, Self::True) => Some(a),
+            (Self::False, _) | (_, Self::False) => Some(Self::False),
+            (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
+                Some(Self::NotInModule(b))
+            }
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
+                Some(Self::NotInModule(a))
+            }
+            (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
+            (Self::And(&[a, b]), c) | (c, Self::And(&[a, b])) => {
+                if let Some(ac) = a.reduce_and(tcx, c) {
+                    Some(ac.and(tcx, b))
+                } else if let Some(bc) = b.reduce_and(tcx, c) {
+                    Some(Self::And(tcx.arena.alloc([a, bc])))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    }
+
+    fn reduce_or(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
+        match (self, other) {
+            (Self::True, _) | (_, Self::True) => Some(Self::True),
+            (Self::False, a) | (a, Self::False) => Some(a),
+            (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
+                Some(Self::NotInModule(a))
+            }
+            (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
+                Some(Self::NotInModule(b))
+            }
+            (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
+            (Self::Or(&[a, b]), c) | (c, Self::Or(&[a, b])) => {
+                if let Some(ac) = a.reduce_or(tcx, c) {
+                    Some(ac.or(tcx, b))
+                } else if let Some(bc) = b.reduce_or(tcx, c) {
+                    Some(Self::Or(tcx.arena.alloc([a, bc])))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    }
+
+    /// Replaces generic types with its corresponding predicate
+    pub fn subst(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Self {
+        self.subst_opt(tcx, substs).unwrap_or(self)
+    }
+
+    fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> {
+        match self {
+            Self::ConstIsZero(c) => {
+                let c = ty::EarlyBinder(c).subst(tcx, substs);
+                let pred = match c.kind().try_to_machine_usize(tcx) {
+                    Some(0) => Self::True,
+                    Some(1..) => Self::False,
+                    None => Self::ConstIsZero(c),
+                };
+                Some(pred)
+            }
+            Self::GenericType(t) => {
+                Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx))
+            }
+            Self::And(&[a, b]) => match a.subst_opt(tcx, substs) {
+                None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)),
+                Some(InhabitedPredicate::False) => Some(InhabitedPredicate::False),
+                Some(a) => Some(a.and(tcx, b.subst_opt(tcx, substs).unwrap_or(b))),
+            },
+            Self::Or(&[a, b]) => match a.subst_opt(tcx, substs) {
+                None => b.subst_opt(tcx, substs).map(|b| a.or(tcx, b)),
+                Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True),
+                Some(a) => Some(a.or(tcx, b.subst_opt(tcx, substs).unwrap_or(b))),
+            },
+            _ => None,
+        }
+    }
+}
+
+// this is basically like `f(a)? && f(b)?` but different in the case of
+// `Ok(false) && Err(_) -> Ok(false)`
+fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
+    let a = f(a);
+    if matches!(a, Ok(false)) {
+        return Ok(false);
+    }
+    match (a, f(b)) {
+        (_, Ok(false)) | (Ok(false), _) => Ok(false),
+        (Ok(true), Ok(true)) => Ok(true),
+        (Err(e), _) | (_, Err(e)) => Err(e),
+    }
+}
+
+fn try_or<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
+    let a = f(a);
+    if matches!(a, Ok(true)) {
+        return Ok(true);
+    }
+    match (a, f(b)) {
+        (_, Ok(true)) | (Ok(true), _) => Ok(true),
+        (Ok(false), Ok(false)) => Ok(false),
+        (Err(e), _) | (_, Err(e)) => Err(e),
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index aaa66deb2a3..279a728ea39 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -1,57 +1,60 @@
-pub use self::def_id_forest::DefIdForest;
+//! This module contains logic for determining whether a type is inhabited or
+//! uninhabited. The [`InhabitedPredicate`] type captures the minimum
+//! information needed to determine whether a type is inhabited given a
+//! `ParamEnv` and module ID.
+//!
+//! # Example
+//! ```rust
+//! enum Void {}
+//! mod a {
+//!     pub mod b {
+//!         pub struct SecretlyUninhabited {
+//!             _priv: !,
+//!         }
+//!     }
+//! }
+//!
+//! mod c {
+//!     pub struct AlsoSecretlyUninhabited {
+//!         _priv: Void,
+//!     }
+//!     mod d {
+//!     }
+//! }
+//!
+//! struct Foo {
+//!     x: a::b::SecretlyUninhabited,
+//!     y: c::AlsoSecretlyUninhabited,
+//! }
+//! ```
+//! In this code, the type `Foo` will only be visibly uninhabited inside the
+//! modules `b`, `c` and `d`. Calling `uninhabited_predicate` on `Foo` will
+//! return `NotInModule(b) AND NotInModule(c)`.
+//!
+//! We need this information for pattern-matching on `Foo` or types that contain
+//! `Foo`.
+//!
+//! # Example
+//! ```rust
+//! let foo_result: Result<T, Foo> = ... ;
+//! let Ok(t) = foo_result;
+//! ```
+//! This code should only compile in modules where the uninhabitedness of `Foo`
+//! is visible.
 
-use crate::ty;
 use crate::ty::context::TyCtxt;
-use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
-use crate::ty::{AdtKind, Visibility};
-use crate::ty::{DefId, SubstsRef};
+use crate::ty::{self, DefId, Ty, VariantDef, Visibility};
 
 use rustc_type_ir::sty::TyKind::*;
 
-mod def_id_forest;
+pub mod inhabited_predicate;
 
-// The methods in this module calculate `DefIdForest`s of modules in which an
-// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
-//
-// # Example
-// ```rust
-// enum Void {}
-// mod a {
-//     pub mod b {
-//         pub struct SecretlyUninhabited {
-//             _priv: !,
-//         }
-//     }
-// }
-//
-// mod c {
-//     pub struct AlsoSecretlyUninhabited {
-//         _priv: Void,
-//     }
-//     mod d {
-//     }
-// }
-//
-// struct Foo {
-//     x: a::b::SecretlyUninhabited,
-//     y: c::AlsoSecretlyUninhabited,
-// }
-// ```
-// In this code, the type `Foo` will only be visibly uninhabited inside the
-// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will
-// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the
-// set {`b`, `c`}).
-//
-// We need this information for pattern-matching on `Foo` or types that contain
-// `Foo`.
-//
-// # Example
-// ```rust
-// let foo_result: Result<T, Foo> = ... ;
-// let Ok(t) = foo_result;
-// ```
-// This code should only compile in modules where the uninhabitedness of `Foo` is
-// visible.
+pub use inhabited_predicate::InhabitedPredicate;
+
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
+    *providers =
+        ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
+}
 
 impl<'tcx> TyCtxt<'tcx> {
     /// Checks whether a type is visibly uninhabited from a particular module.
@@ -100,131 +103,92 @@ impl<'tcx> TyCtxt<'tcx> {
         ty: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
-        // To check whether this type is uninhabited at all (not just from the
-        // given node), you could check whether the forest is empty.
-        // ```
-        // forest.is_empty()
-        // ```
-        ty.uninhabited_from(self, param_env).contains(self, module)
+        !ty.inhabited_predicate(self).apply(self, param_env, module)
     }
 }
 
-impl<'tcx> AdtDef<'tcx> {
-    /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
-    fn uninhabited_from(
-        self,
-        tcx: TyCtxt<'tcx>,
-        substs: SubstsRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        // Non-exhaustive ADTs from other crates are always considered inhabited.
-        if self.is_variant_list_non_exhaustive() && !self.did().is_local() {
-            DefIdForest::empty()
-        } else {
-            DefIdForest::intersection(
-                tcx,
-                self.variants()
-                    .iter()
-                    .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
-            )
+/// Returns an `InhabitedPredicate` that is generic over type parameters and
+/// requires calling [`InhabitedPredicate::subst`]
+fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
+    if let Some(def_id) = def_id.as_local() {
+        if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
+            return InhabitedPredicate::True;
         }
     }
+    let adt = tcx.adt_def(def_id);
+    InhabitedPredicate::any(
+        tcx,
+        adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)),
+    )
 }
 
 impl<'tcx> VariantDef {
     /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
-    pub fn uninhabited_from(
+    pub fn inhabited_predicate(
         &self,
         tcx: TyCtxt<'tcx>,
-        substs: SubstsRef<'tcx>,
-        adt_kind: AdtKind,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        let is_enum = match adt_kind {
-            // For now, `union`s are never considered uninhabited.
-            // The precise semantics of inhabitedness with respect to unions is currently undecided.
-            AdtKind::Union => return DefIdForest::empty(),
-            AdtKind::Enum => true,
-            AdtKind::Struct => false,
-        };
-        // Non-exhaustive variants from other crates are always considered inhabited.
+        adt: ty::AdtDef<'_>,
+    ) -> InhabitedPredicate<'tcx> {
+        debug_assert!(!adt.is_union());
         if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
-            DefIdForest::empty()
-        } else {
-            DefIdForest::union(
-                tcx,
-                self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)),
-            )
+            // Non-exhaustive variants from other crates are always considered inhabited.
+            return InhabitedPredicate::True;
         }
-    }
-}
-
-impl<'tcx> FieldDef {
-    /// Calculates the forest of `DefId`s from which this field is visibly uninhabited.
-    fn uninhabited_from(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        substs: SubstsRef<'tcx>,
-        is_enum: bool,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
-        if is_enum {
-            data_uninhabitedness()
-        } else {
-            match self.vis {
-                Visibility::Restricted(from) => {
-                    let forest = DefIdForest::from_id(from);
-                    let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
-                    DefIdForest::intersection(tcx, iter)
+        InhabitedPredicate::all(
+            tcx,
+            self.fields.iter().map(|field| {
+                let pred = tcx.type_of(field.did).inhabited_predicate(tcx);
+                if adt.is_enum() {
+                    return pred;
                 }
-                Visibility::Public => data_uninhabitedness(),
-            }
-        }
+                match field.vis {
+                    Visibility::Public => pred,
+                    Visibility::Restricted(from) => {
+                        pred.or(tcx, InhabitedPredicate::NotInModule(from))
+                    }
+                }
+            }),
+        )
     }
 }
 
 impl<'tcx> Ty<'tcx> {
-    /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
-    fn uninhabited_from(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest<'tcx> {
-        tcx.type_uninhabited_from(param_env.and(self))
+    pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
+        match self.kind() {
+            // For now, union`s are always considered inhabited
+            Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
+            // Non-exhaustive ADTs from other crates are always considered inhabited
+            Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => {
+                InhabitedPredicate::True
+            }
+            Never => InhabitedPredicate::False,
+            Param(_) | Projection(_) => InhabitedPredicate::GenericType(self),
+            Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
+            // use a query for more complex cases
+            Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
+            // references and other types are inhabited
+            _ => InhabitedPredicate::True,
+        }
     }
 }
 
-// Query provider for `type_uninhabited_from`.
-pub(crate) fn type_uninhabited_from<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> DefIdForest<'tcx> {
-    let ty = key.value;
-    let param_env = key.param_env;
+/// N.B. this query should only be called through `Ty::inhabited_predicate`
+fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
     match *ty.kind() {
-        Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
+        Adt(adt, substs) => tcx.inhabited_predicate_adt(adt.did()).subst(tcx, substs),
 
-        Never => DefIdForest::full(),
-
-        Tuple(ref tys) => {
-            DefIdForest::union(tcx, tys.iter().map(|ty| ty.uninhabited_from(tcx, param_env)))
+        Tuple(tys) => {
+            InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
         }
 
-        Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
-            Some(0) | None => DefIdForest::empty(),
-            // If the array is definitely non-empty, it's uninhabited if
-            // the type of its elements is uninhabited.
-            Some(1..) => ty.uninhabited_from(tcx, param_env),
+        // If we can evaluate the array length before having a `ParamEnv`, then
+        // we can simplify the predicate. This is an optimization.
+        Array(ty, len) => match len.kind().try_to_machine_usize(tcx) {
+            Some(0) => InhabitedPredicate::True,
+            Some(1..) => ty.inhabited_predicate(tcx),
+            None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
         },
 
-        // References to uninitialised memory are valid for any type, including
-        // uninhabited types, in unsafe code, so we treat all references as
-        // inhabited.
-        // The precise semantics of inhabitedness with respect to references is currently
-        // undecided.
-        Ref(..) => DefIdForest::empty(),
-
-        _ => DefIdForest::empty(),
+        _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
     }
 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 6045c1acdd0..0a109fd8f44 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -196,16 +196,16 @@ impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
         match self {
             LayoutError::Unknown(ty) => {
                 diag.set_arg("ty", ty);
-                diag.set_primary_message(rustc_errors::fluent::middle::unknown_layout);
+                diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
             }
             LayoutError::SizeOverflow(ty) => {
                 diag.set_arg("ty", ty);
-                diag.set_primary_message(rustc_errors::fluent::middle::values_too_big);
+                diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
             }
             LayoutError::NormalizationFailure(ty, e) => {
                 diag.set_arg("ty", ty);
                 diag.set_arg("failure_ty", e.get_type_for_failure());
-                diag.set_primary_message(rustc_errors::fluent::middle::cannot_be_normalized);
+                diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
             }
         }
         diag
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 0d7d4054bb3..c2aef8178e2 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -26,6 +26,7 @@ use crate::ty::util::Discr;
 pub use adt::*;
 pub use assoc::*;
 pub use generics::*;
+use hir::OpaqueTyOrigin;
 use rustc_ast as ast;
 use rustc_ast::node_id::NodeMap;
 use rustc_attr as attr;
@@ -77,7 +78,7 @@ pub use self::consts::{
 };
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-    CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+    CtxtInterners, DeducedParamAttrs, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
     GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
     UserTypeAnnotationIndex,
 };
@@ -682,7 +683,7 @@ pub enum PredicateKind<'tcx> {
     Coerce(CoercePredicate<'tcx>),
 
     /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(ty::UnevaluatedConst<'tcx>),
+    ConstEvaluatable(ty::Const<'tcx>),
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(Const<'tcx>, Const<'tcx>),
@@ -1309,6 +1310,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         tcx: TyCtxt<'tcx>,
         // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
         ignore_errors: bool,
+        origin: OpaqueTyOrigin,
     ) -> Self {
         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
 
@@ -1320,8 +1322,79 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         // shifting.
         let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
         debug!(?id_substs);
-        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
-            substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
+
+        let map = substs.iter().zip(id_substs);
+
+        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = match origin {
+            // HACK: The HIR lowering for async fn does not generate
+            // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
+            // would now fail to compile. We should probably just make hir lowering fill this in properly.
+            OpaqueTyOrigin::AsyncFn(_) => map.collect(),
+            OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
+                // Opaque types may only use regions that are bound. So for
+                // ```rust
+                // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
+                // ```
+                // we may not use `'c` in the hidden type.
+                struct OpaqueTypeLifetimeCollector<'tcx> {
+                    lifetimes: FxHashSet<ty::Region<'tcx>>,
+                }
+
+                impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
+                    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+                        self.lifetimes.insert(r);
+                        r.super_visit_with(self)
+                    }
+                }
+
+                let mut collector = OpaqueTypeLifetimeCollector { lifetimes: Default::default() };
+
+                for pred in tcx.bound_explicit_item_bounds(def_id.to_def_id()).transpose_iter() {
+                    let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+
+                    trace!(pred=?pred.kind());
+
+                    // We only ignore opaque type substs if the opaque type is the outermost type.
+                    // The opaque type may be nested within itself via recursion in e.g.
+                    // type Foo<'a> = impl PartialEq<Foo<'a>>;
+                    // which thus mentions `'a` and should thus accept hidden types that borrow 'a
+                    // instead of requiring an additional `+ 'a`.
+                    match pred.kind().skip_binder() {
+                        ty::PredicateKind::Trait(TraitPredicate {
+                            trait_ref: ty::TraitRef { def_id: _, substs },
+                            constness: _,
+                            polarity: _,
+                        }) => {
+                            trace!(?substs);
+                            for subst in &substs[1..] {
+                                subst.visit_with(&mut collector);
+                            }
+                        }
+                        ty::PredicateKind::Projection(ty::ProjectionPredicate {
+                            projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+                            term,
+                        }) => {
+                            for subst in &substs[1..] {
+                                subst.visit_with(&mut collector);
+                            }
+                            term.visit_with(&mut collector);
+                        }
+                        _ => {
+                            pred.visit_with(&mut collector);
+                        }
+                    }
+                }
+                let lifetimes = collector.lifetimes;
+                trace!(?lifetimes);
+                map.filter(|(_, v)| {
+                    let ty::GenericArgKind::Lifetime(lt) = v.unpack() else {
+                        return true;
+                    };
+                    lifetimes.contains(&lt)
+                })
+                .collect()
+            }
+        };
         debug!("map = {:#?}", map);
 
         // Convert the type from the function into a type valid outside
@@ -2621,6 +2694,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
     closure::provide(providers);
     context::provide(providers);
     erase_regions::provide(providers);
+    inhabitedness::provide(providers);
     util::provide(providers);
     print::provide(providers);
     super::util::bug::provide(providers);
@@ -2628,7 +2702,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
         incoherent_impls: trait_def::incoherent_impls_provider,
-        type_uninhabited_from: inhabitedness::type_uninhabited_from,
         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 fe303e21b65..ee13920d52e 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -214,15 +214,6 @@ impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
     }
-
-    #[inline]
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        // FIXME: This *probably* needs canonicalization too!
-        let arg = self.param_env.and(c);
-        self.tcx
-            .try_normalize_mir_const_after_erasing_regions(arg)
-            .unwrap_or_else(|_| bug!("failed to normalize {:?}", c))
-    }
 }
 
 struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
@@ -267,16 +258,4 @@ impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'t
             Err(_) => Err(NormalizationError::Const(c)),
         }
     }
-
-    fn try_fold_mir_const(
-        &mut self,
-        c: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        // FIXME: This *probably* needs canonicalization too!
-        let arg = self.param_env.and(c);
-        match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
-            Ok(c) => Ok(c),
-            Err(_) => Err(NormalizationError::ConstantKind(c)),
-        }
-    }
 }
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index f289f2265a2..e1e705a922f 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -61,6 +61,7 @@ trivially_parameterized_over_tcx! {
     crate::middle::resolve_lifetime::ObjectLifetimeDefault,
     crate::mir::ConstQualifs,
     ty::AssocItemContainer,
+    ty::DeducedParamAttrs,
     ty::Generics,
     ty::ImplPolarity,
     ty::ReprOptions,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 66354196b4e..b8ee2b994b1 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -16,6 +16,7 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
+use smallvec::SmallVec;
 
 use std::cell::Cell;
 use std::char;
@@ -794,9 +795,9 @@ pub trait PrettyPrinter<'tcx>:
         let mut traits = FxIndexMap::default();
         let mut fn_traits = FxIndexMap::default();
         let mut is_sized = false;
+        let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
 
-        for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
-            let predicate = predicate.subst(tcx, substs);
+        for (predicate, _) in bounds.subst_iter_copied(tcx, substs) {
             let bound_predicate = predicate.kind();
 
             match bound_predicate.skip_binder() {
@@ -825,6 +826,9 @@ pub trait PrettyPrinter<'tcx>:
                         &mut fn_traits,
                     );
                 }
+                ty::PredicateKind::TypeOutlives(outlives) => {
+                    lifetimes.push(outlives.1);
+                }
                 _ => {}
             }
         }
@@ -978,6 +982,11 @@ pub trait PrettyPrinter<'tcx>:
             write!(self, "Sized")?;
         }
 
+        for re in lifetimes {
+            write!(self, " + ")?;
+            self = self.print_region(re)?;
+        }
+
         Ok(self)
     }
 
@@ -2702,8 +2711,8 @@ define_print_and_forward_display! {
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind))
             }
-            ty::PredicateKind::ConstEvaluatable(uv) => {
-                p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
+            ty::PredicateKind::ConstEvaluatable(ct) => {
+                p!("the constant `", print(ct), "` can be evaluated")
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
                 p!("the constant `", print(c1), "` equals `", print(c2), "`")
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index ce1b69935f2..9c97ce34f29 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -52,7 +52,6 @@ use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolMangli
 use rustc_session::cstore::{CrateDepKind, CrateSource};
 use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use rustc_session::lint::LintExpectationId;
-use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 1164cf3e01a..2cad333e3f5 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -166,8 +166,8 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
-            ty::PredicateKind::ConstEvaluatable(uv) => {
-                write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
+            ty::PredicateKind::ConstEvaluatable(ct) => {
+                write!(f, "ConstEvaluatable({ct:?})")
             }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@@ -832,27 +832,6 @@ impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::UnevaluatedConst<'tcx> {
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_ty_unevaluated(self)
-    }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_ty_unevaluated(*self)
-    }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for ty::UnevaluatedConst<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(ty::UnevaluatedConst { def: self.def, substs: self.substs.try_fold_with(folder)? })
-    }
-}
-
 impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.substs.visit_with(visitor)
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 36eb2ab5157..0660e9b79a7 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -1,12 +1,12 @@
 // Type substitutions.
 
-use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
 use crate::ty::visit::{TypeVisitable, TypeVisitor};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -189,6 +189,14 @@ impl<'tcx> GenericArg<'tcx> {
             _ => bug!("expected a const, but found another kind"),
         }
     }
+
+    pub fn is_non_region_infer(self) -> bool {
+        match self.unpack() {
+            GenericArgKind::Lifetime(_) => false,
+            GenericArgKind::Type(ty) => ty.is_ty_infer(),
+            GenericArgKind::Const(ct) => ct.is_ct_infer(),
+        }
+    }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
@@ -551,6 +559,28 @@ impl<T, U> EarlyBinder<(T, U)> {
     }
 }
 
+impl<'tcx, 's, T: IntoIterator<Item = I>, I: TypeFoldable<'tcx>> EarlyBinder<T> {
+    pub fn subst_iter(
+        self,
+        tcx: TyCtxt<'tcx>,
+        substs: &'s [GenericArg<'tcx>],
+    ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> {
+        self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs))
+    }
+}
+
+impl<'tcx, 's, 'a, T: IntoIterator<Item = &'a I>, I: Copy + TypeFoldable<'tcx> + 'a>
+    EarlyBinder<T>
+{
+    pub fn subst_iter_copied(
+        self,
+        tcx: TyCtxt<'tcx>,
+        substs: &'s [GenericArg<'tcx>],
+    ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> + Captures<'a> {
+        self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs))
+    }
+}
+
 pub struct EarlyBinderIter<T> {
     t: T,
 }
@@ -606,9 +636,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         #[cold]
         #[inline(never)]
-        fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
+        fn region_param_out_of_range(data: ty::EarlyBoundRegion, substs: &[GenericArg<'_>]) -> ! {
             bug!(
-                "Region parameter out of range when substituting in region {} (index={})",
+                "Region parameter out of range when substituting in region {} (index={}, substs = {:?})",
+                data.name,
+                data.index,
+                substs,
+            )
+        }
+
+        #[cold]
+        #[inline(never)]
+        fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! {
+            bug!(
+                "Unexpected parameter {:?} when substituting in region {} (index={})",
+                other,
                 data.name,
                 data.index
             )
@@ -624,7 +666,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                 let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
                 match rk {
                     Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
-                    _ => region_param_out_of_range(data),
+                    Some(other) => region_param_invalid(data, other),
+                    None => region_param_out_of_range(data, self.substs),
                 }
             }
             _ => r,
@@ -649,11 +692,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
             c.super_fold_with(self)
         }
     }
-
-    #[inline]
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
-        c.super_fold_with(self)
-    }
 }
 
 impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 6e1991b527f..c09f71f9a6d 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -38,7 +38,6 @@
 //!     - ty.super_visit_with(visitor)
 //! - u.visit_with(visitor)
 //! ```
-use crate::mir;
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
 use rustc_errors::ErrorGuaranteed;
 
@@ -198,27 +197,9 @@ pub trait TypeVisitor<'tcx>: Sized {
         c.super_visit_with(self)
     }
 
-    fn visit_ty_unevaluated(
-        &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        uv.super_visit_with(self)
-    }
-
-    fn visit_mir_unevaluated(
-        &mut self,
-        uv: mir::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        uv.super_visit_with(self)
-    }
-
     fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         p.super_visit_with(self)
     }
-
-    fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
-        c.super_visit_with(self)
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -606,34 +587,6 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
 
     #[inline]
     #[instrument(level = "trace", ret)]
-    fn visit_ty_unevaluated(
-        &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        let flags = FlagComputation::for_unevaluated_const(uv);
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    fn visit_mir_unevaluated(
-        &mut self,
-        uv: mir::UnevaluatedConst<'tcx>,
-    ) -> ControlFlow<Self::BreakTy> {
-        let flags = FlagComputation::for_unevaluated_const(uv.shrink());
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    #[instrument(level = "trace", ret)]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!(
             "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index a3e11bbf056..91db9698c41 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -112,6 +112,22 @@ impl<'tcx> Ty<'tcx> {
     }
 }
 
+impl<'tcx> ty::Const<'tcx> {
+    /// Iterator that walks `self` and any types reachable from
+    /// `self`, in depth-first order. Note that just walks the types
+    /// that appear in `self`, it does not descend into the fields of
+    /// structs or variants. For example:
+    ///
+    /// ```text
+    /// isize => { isize }
+    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+    /// [isize] => { [isize], isize }
+    /// ```
+    pub fn walk(self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self.into())
+    }
+}
+
 /// We push `GenericArg`s on the stack in reverse order so as to
 /// maintain a pre-order traversal. As of the time of this
 /// writing, the fact that the traversal is pre-order is not
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 828f32db361..924d2f555b9 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -264,14 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
                     i == variant_index || {
                         self.tcx.features().exhaustive_patterns
-                            && !v
-                                .uninhabited_from(
-                                    self.tcx,
-                                    substs,
-                                    adt_def.adt_kind(),
-                                    self.param_env,
-                                )
-                                .is_empty()
+                            && v.inhabited_predicate(self.tcx, adt_def)
+                                .subst(self.tcx, substs)
+                                .apply_any_module(self.tcx, self.param_env)
+                                != Some(true)
                     }
                 }) && (adt_def.did().is_local()
                     || !adt_def.is_variant_list_non_exhaustive());
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 91ecfccdb5f..595abc8f668 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -988,10 +988,12 @@ impl<'tcx> SplitWildcard<'tcx> {
                     .filter(|(_, v)| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
                         // uninhabited.
-                        let is_uninhabited = is_exhaustive_pat_feature
-                            && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
-                                .contains(cx.tcx, cx.module);
-                        !is_uninhabited
+                        !is_exhaustive_pat_feature
+                            || v.inhabited_predicate(cx.tcx, *def).subst(cx.tcx, substs).apply(
+                                cx.tcx,
+                                cx.param_env,
+                                cx.module,
+                            )
                     })
                     .map(|(idx, _)| Variant(idx))
                     .collect();
diff --git a/compiler/rustc_mir_dataflow/src/errors.rs b/compiler/rustc_mir_dataflow/src/errors.rs
index 5b1a88cb284..cfacc0ec370 100644
--- a/compiler/rustc_mir_dataflow/src/errors.rs
+++ b/compiler/rustc_mir_dataflow/src/errors.rs
@@ -2,21 +2,21 @@ use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::path_must_end_in_filename)]
+#[diag(mir_dataflow_path_must_end_in_filename)]
 pub(crate) struct PathMustEndInFilename {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::unknown_formatter)]
+#[diag(mir_dataflow_unknown_formatter)]
 pub(crate) struct UnknownFormatter {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::duplicate_values_for)]
+#[diag(mir_dataflow_duplicate_values_for)]
 pub(crate) struct DuplicateValuesFor {
     #[primary_span]
     pub span: Span,
@@ -24,7 +24,7 @@ pub(crate) struct DuplicateValuesFor {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::requires_an_argument)]
+#[diag(mir_dataflow_requires_an_argument)]
 pub(crate) struct RequiresAnArgument {
     #[primary_span]
     pub span: Span,
@@ -32,39 +32,39 @@ pub(crate) struct RequiresAnArgument {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::stop_after_dataflow_ended_compilation)]
+#[diag(mir_dataflow_stop_after_dataflow_ended_compilation)]
 pub(crate) struct StopAfterDataFlowEndedCompilation;
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_must_be_place_or_ref_place)]
+#[diag(mir_dataflow_peek_must_be_place_or_ref_place)]
 pub(crate) struct PeekMustBePlaceOrRefPlace {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_must_be_not_temporary)]
+#[diag(mir_dataflow_peek_must_be_not_temporary)]
 pub(crate) struct PeekMustBeNotTemporary {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_bit_not_set)]
+#[diag(mir_dataflow_peek_bit_not_set)]
 pub(crate) struct PeekBitNotSet {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_argument_not_a_local)]
+#[diag(mir_dataflow_peek_argument_not_a_local)]
 pub(crate) struct PeekArgumentNotALocal {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_dataflow::peek_argument_untracked)]
+#[diag(mir_dataflow_peek_argument_untracked)]
 pub(crate) struct PeekArgumentUntracked {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
new file mode 100644
index 00000000000..18352fbf675
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -0,0 +1,249 @@
+//! Deduces supplementary parameter attributes from MIR.
+//!
+//! Deduced parameter attributes are those that can only be soundly determined by examining the
+//! body of the function instead of just the signature. These can be useful for optimization
+//! purposes on a best-effort basis. We compute them here and store them into the crate metadata so
+//! dependent crates can use them.
+
+use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE};
+use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
+use rustc_span::DUMMY_SP;
+
+/// A visitor that determines which arguments have been mutated. We can't use the mutability field
+/// on LocalDecl for this because it has no meaning post-optimization.
+struct DeduceReadOnly {
+    /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
+    /// 1). The bit is true if the argument may have been mutated or false if we know it hasn't
+    /// been up to the point we're at.
+    mutable_args: BitSet<usize>,
+}
+
+impl DeduceReadOnly {
+    /// Returns a new DeduceReadOnly instance.
+    fn new(arg_count: usize) -> Self {
+        Self { mutable_args: BitSet::new_empty(arg_count) }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
+    fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) {
+        // We're only interested in arguments.
+        if local == RETURN_PLACE || local.index() > self.mutable_args.domain_size() {
+            return;
+        }
+
+        // Replace place contexts that are moves with copies. This is safe in all cases except
+        // function argument position, which we already handled in `visit_terminator()` by using the
+        // ArgumentChecker. See the comment in that method for more details.
+        //
+        // In the future, we might want to move this out into a separate pass, but for now let's
+        // just do it on the fly because that's faster.
+        if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) {
+            context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
+        }
+
+        match context {
+            PlaceContext::MutatingUse(..)
+            | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
+                // This is a mutation, so mark it as such.
+                self.mutable_args.insert(local.index() - 1);
+            }
+            PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
+                // Not mutating, so it's fine.
+            }
+        }
+    }
+
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        // OK, this is subtle. Suppose that we're trying to deduce whether `x` in `f` is read-only
+        // and we have the following:
+        //
+        //     fn f(x: BigStruct) { g(x) }
+        //     fn g(mut y: BigStruct) { y.foo = 1 }
+        //
+        // If, at the generated MIR level, `f` turned into something like:
+        //
+        //      fn f(_1: BigStruct) -> () {
+        //          let mut _0: ();
+        //          bb0: {
+        //              _0 = g(move _1) -> bb1;
+        //          }
+        //          ...
+        //      }
+        //
+        // then it would be incorrect to mark `x` (i.e. `_1`) as `readonly`, because `g`'s write to
+        // its copy of the indirect parameter would actually be a write directly to the pointer that
+        // `f` passes. Note that function arguments are the only situation in which this problem can
+        // arise: every other use of `move` in MIR doesn't actually write to the value it moves
+        // from.
+        //
+        // Anyway, right now this situation doesn't actually arise in practice. Instead, the MIR for
+        // that function looks like this:
+        //
+        //      fn f(_1: BigStruct) -> () {
+        //          let mut _0: ();
+        //          let mut _2: BigStruct;
+        //          bb0: {
+        //              _2 = move _1;
+        //              _0 = g(move _2) -> bb1;
+        //          }
+        //          ...
+        //      }
+        //
+        // Because of that extra move that MIR construction inserts, `x` (i.e. `_1`) can *in
+        // practice* safely be marked `readonly`.
+        //
+        // To handle the possibility that other optimizations (for example, destination propagation)
+        // might someday generate MIR like the first example above, we panic upon seeing an argument
+        // to *our* function that is directly moved into *another* function as an argument. Having
+        // eliminated that problematic case, we can safely treat moves as copies in this analysis.
+        //
+        // In the future, if MIR optimizations cause arguments of a caller to be directly moved into
+        // the argument of a callee, we can just add that argument to `mutated_args` instead of
+        // panicking.
+        //
+        // Note that, because the problematic MIR is never actually generated, we can't add a test
+        // case for this.
+
+        if let TerminatorKind::Call { ref args, .. } = terminator.kind {
+            for arg in args {
+                if let Operand::Move(_) = *arg {
+                    // ArgumentChecker panics if a direct move of an argument from a caller to a
+                    // callee was detected.
+                    //
+                    // If, in the future, MIR optimizations cause arguments to be moved directly
+                    // from callers to callees, change the panic to instead add the argument in
+                    // question to `mutating_uses`.
+                    ArgumentChecker::new(self.mutable_args.domain_size())
+                        .visit_operand(arg, location)
+                }
+            }
+        };
+
+        self.super_terminator(terminator, location);
+    }
+}
+
+/// A visitor that simply panics if a direct move of an argument from a caller to a callee was
+/// detected.
+struct ArgumentChecker {
+    /// The number of arguments to the calling function.
+    arg_count: usize,
+}
+
+impl ArgumentChecker {
+    /// Creates a new ArgumentChecker.
+    fn new(arg_count: usize) -> Self {
+        Self { arg_count }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for ArgumentChecker {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
+        // Check to make sure that, if this local is an argument, we didn't move directly from it.
+        if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move))
+            && local != RETURN_PLACE
+            && local.index() <= self.arg_count
+        {
+            // If, in the future, MIR optimizations cause arguments to be moved directly from
+            // callers to callees, change this panic to instead add the argument in question to
+            // `mutating_uses`.
+            panic!("Detected a direct move from a caller's argument to a callee's argument!")
+        }
+    }
+}
+
+/// Returns true if values of a given type will never be passed indirectly, regardless of ABI.
+fn type_will_always_be_passed_directly<'tcx>(ty: Ty<'tcx>) -> bool {
+    matches!(
+        ty.kind(),
+        ty::Bool
+            | ty::Char
+            | ty::Float(..)
+            | ty::Int(..)
+            | ty::RawPtr(..)
+            | ty::Ref(..)
+            | ty::Slice(..)
+            | ty::Uint(..)
+    )
+}
+
+/// Returns the deduced parameter attributes for a function.
+///
+/// Deduced parameter attributes are those that can only be soundly determined by examining the
+/// body of the function instead of just the signature. These can be useful for optimization
+/// purposes on a best-effort basis. We compute them here and store them into the crate metadata so
+/// dependent crates can use them.
+pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [DeducedParamAttrs] {
+    // This computation is unfortunately rather expensive, so don't do it unless we're optimizing.
+    // Also skip it in incremental mode.
+    if tcx.sess.opts.optimize == OptLevel::No || tcx.sess.opts.incremental.is_some() {
+        return &[];
+    }
+
+    // If the Freeze language item isn't present, then don't bother.
+    if tcx.lang_items().freeze_trait().is_none() {
+        return &[];
+    }
+
+    // Codegen won't use this information for anything if all the function parameters are passed
+    // directly. Detect that and bail, for compilation speed.
+    let fn_ty = tcx.type_of(def_id);
+    if matches!(fn_ty.kind(), ty::FnDef(..)) {
+        if fn_ty
+            .fn_sig(tcx)
+            .inputs()
+            .skip_binder()
+            .iter()
+            .cloned()
+            .all(type_will_always_be_passed_directly)
+        {
+            return &[];
+        }
+    }
+
+    // Don't deduce any attributes for functions that have no MIR.
+    if !tcx.is_mir_available(def_id) {
+        return &[];
+    }
+
+    // Deduced attributes for other crates should be read from the metadata instead of via this
+    // function.
+    debug_assert!(def_id.is_local());
+
+    // Grab the optimized MIR. Analyze it to determine which arguments have been mutated.
+    let body: &Body<'tcx> = tcx.optimized_mir(def_id);
+    let mut deduce_read_only = DeduceReadOnly::new(body.arg_count);
+    deduce_read_only.visit_body(body);
+
+    // Set the `readonly` attribute for every argument that we concluded is immutable and that
+    // contains no UnsafeCells.
+    //
+    // FIXME: This is overly conservative around generic parameters: `is_freeze()` will always
+    // return false for them. For a description of alternatives that could do a better job here,
+    // see [1].
+    //
+    // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
+    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 {
+                read_only: !deduce_read_only.mutable_args.contains(arg_index)
+                    && local_decl.ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all()),
+            },
+        ),
+    );
+
+    // Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the
+    // default set of attributes, so we don't have to store them explicitly. Pop them off to save a
+    // few bytes in metadata.
+    while deduced_param_attrs.last() == Some(&DeducedParamAttrs::default()) {
+        let last_index = deduced_param_attrs.len() - 1;
+        deduced_param_attrs = &mut deduced_param_attrs[0..last_index];
+    }
+
+    deduced_param_attrs
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 2230c3399f0..5c411fa5657 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -56,6 +56,7 @@ mod const_prop_lint;
 mod coverage;
 mod dead_store_elimination;
 mod deaggregator;
+mod deduce_param_attrs;
 mod deduplicate_blocks;
 mod deref_separator;
 mod dest_prop;
@@ -139,6 +140,7 @@ pub fn provide(providers: &mut Providers) {
         promoted_mir_of_const_arg: |tcx, (did, param_did)| {
             promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
         },
+        deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
         ..*providers
     };
 }
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index cf6e18c013b..ce097b8d846 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic};
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::recursion_limit)]
+#[diag(monomorphize_recursion_limit)]
 pub struct RecursionLimit {
     #[primary_span]
     pub span: Span,
@@ -14,26 +14,26 @@ pub struct RecursionLimit {
     #[note]
     pub def_span: Span,
     pub def_path_str: String,
-    #[note(monomorphize::written_to_path)]
+    #[note(monomorphize_written_to_path)]
     pub was_written: Option<()>,
     pub path: PathBuf,
 }
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::type_length_limit)]
-#[help(monomorphize::consider_type_length_limit)]
+#[diag(monomorphize_type_length_limit)]
+#[help(monomorphize_consider_type_length_limit)]
 pub struct TypeLengthLimit {
     #[primary_span]
     pub span: Span,
     pub shrunk: String,
-    #[note(monomorphize::written_to_path)]
+    #[note(monomorphize_written_to_path)]
     pub was_written: Option<()>,
     pub path: PathBuf,
     pub type_length: usize,
 }
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::requires_lang_item)]
+#[diag(monomorphize_requires_lang_item)]
 pub struct RequiresLangItem {
     pub lang_item: String,
 }
@@ -49,8 +49,7 @@ impl IntoDiagnostic<'_> for UnusedGenericParams {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag =
-            handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
+        let mut diag = handler.struct_err(rustc_errors::fluent::monomorphize_unused_generic_params);
         diag.set_span(self.span);
         for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
             // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
@@ -63,7 +62,7 @@ impl IntoDiagnostic<'_> for UnusedGenericParams {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(monomorphize::large_assignments)]
+#[diag(monomorphize_large_assignments)]
 #[note]
 pub struct LargeAssignmentsLint {
     #[label]
@@ -73,11 +72,11 @@ pub struct LargeAssignmentsLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::unknown_partition_strategy)]
+#[diag(monomorphize_unknown_partition_strategy)]
 pub struct UnknownPartitionStrategy;
 
 #[derive(Diagnostic)]
-#[diag(monomorphize::symbol_already_defined)]
+#[diag(monomorphize_symbol_already_defined)]
 pub struct SymbolAlreadyDefined {
     #[primary_span]
     pub span: Option<Span>,
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index a93f6a60114..650076c2213 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -276,9 +276,21 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
             ConstantKind::Ty(c) => {
                 c.visit_with(self);
             }
-            ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => {
-                Visitor::visit_ty(self, ty, TyContext::Location(location))
+            ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs: _, promoted }, ty) => {
+                // Avoid considering `T` unused when constants are of the form:
+                //   `<Self as Foo<T>>::foo::promoted[p]`
+                if let Some(p) = promoted {
+                    if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self {
+                        // If there is a promoted, don't look at the substs - since it will always contain
+                        // the generic parameters, instead, traverse the promoted MIR.
+                        let promoted = self.tcx.promoted_mir(def.did);
+                        self.visit_body(&promoted[p]);
+                    }
+                }
+
+                Visitor::visit_ty(self, ty, TyContext::Location(location));
             }
+            ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
         }
     }
 
@@ -310,30 +322,6 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
         }
     }
 
-    fn visit_mir_const(&mut self, constant: ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !constant.has_non_region_param() {
-            return ControlFlow::CONTINUE;
-        }
-
-        match constant {
-            ConstantKind::Ty(ct) => ct.visit_with(self),
-            ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs: _, promoted: Some(p) }, _)
-                // Avoid considering `T` unused when constants are of the form:
-                //   `<Self as Foo<T>>::foo::promoted[p]`
-                if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
-            {
-                // If there is a promoted, don't look at the substs - since it will always contain
-                // the generic parameters, instead, traverse the promoted MIR.
-                let promoted = self.tcx.promoted_mir(def.did);
-                self.visit_body(&promoted[p]);
-                ControlFlow::CONTINUE
-            }
-            ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => {
-                constant.super_visit_with(self)
-            }
-        }
-    }
-
     #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.has_non_region_param() {
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 98fee997427..9b177c5189b 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol};
 use crate::parser::TokenDescription;
 
 #[derive(Diagnostic)]
-#[diag(parser::maybe_report_ambiguous_plus)]
+#[diag(parser_maybe_report_ambiguous_plus)]
 pub(crate) struct AmbiguousPlus {
     pub sum_ty: String,
     #[primary_span]
@@ -18,7 +18,7 @@ pub(crate) struct AmbiguousPlus {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
+#[diag(parser_maybe_recover_from_bad_type_plus, code = "E0178")]
 pub(crate) struct BadTypePlus {
     pub ty: String,
     #[primary_span]
@@ -30,7 +30,7 @@ pub(crate) struct BadTypePlus {
 #[derive(Subdiagnostic)]
 pub(crate) enum BadTypePlusSub {
     #[suggestion(
-        parser::add_paren,
+        parser_add_paren,
         code = "{sum_with_parens}",
         applicability = "machine-applicable"
     )]
@@ -39,12 +39,12 @@ pub(crate) enum BadTypePlusSub {
         #[primary_span]
         span: Span,
     },
-    #[label(parser::forgot_paren)]
+    #[label(parser_forgot_paren)]
     ForgotParen {
         #[primary_span]
         span: Span,
     },
-    #[label(parser::expect_path)]
+    #[label(parser_expect_path)]
     ExpectPath {
         #[primary_span]
         span: Span,
@@ -52,7 +52,7 @@ pub(crate) enum BadTypePlusSub {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::maybe_recover_from_bad_qpath_stage_2)]
+#[diag(parser_maybe_recover_from_bad_qpath_stage_2)]
 pub(crate) struct BadQPathStage2 {
     #[primary_span]
     #[suggestion(code = "", applicability = "maybe-incorrect")]
@@ -61,7 +61,7 @@ pub(crate) struct BadQPathStage2 {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_semicolon)]
+#[diag(parser_incorrect_semicolon)]
 pub(crate) struct IncorrectSemicolon<'a> {
     #[primary_span]
     #[suggestion_short(code = "", applicability = "machine-applicable")]
@@ -72,26 +72,26 @@ pub(crate) struct IncorrectSemicolon<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_use_of_await)]
+#[diag(parser_incorrect_use_of_await)]
 pub(crate) struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(parser::parentheses_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(parentheses_suggestion, code = "", applicability = "machine-applicable")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_use_of_await)]
+#[diag(parser_incorrect_use_of_await)]
 pub(crate) struct IncorrectAwait {
     #[primary_span]
     pub span: Span,
-    #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")]
+    #[suggestion(postfix_suggestion, code = "{expr}.await{question_mark}")]
     pub sugg_span: (Span, Applicability),
     pub expr: String,
     pub question_mark: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::in_in_typo)]
+#[diag(parser_in_in_typo)]
 pub(crate) struct InInTypo {
     #[primary_span]
     pub span: Span,
@@ -100,7 +100,7 @@ pub(crate) struct InInTypo {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_variable_declaration)]
+#[diag(parser_invalid_variable_declaration)]
 pub(crate) struct InvalidVariableDeclaration {
     #[primary_span]
     pub span: Span,
@@ -110,26 +110,22 @@ pub(crate) struct InvalidVariableDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidVariableDeclarationSub {
-    #[suggestion(
-        parser::switch_mut_let_order,
-        applicability = "maybe-incorrect",
-        code = "let mut"
-    )]
+    #[suggestion(parser_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")]
     SwitchMutLetOrder(#[primary_span] Span),
     #[suggestion(
-        parser::missing_let_before_mut,
+        parser_missing_let_before_mut,
         applicability = "machine-applicable",
         code = "let mut"
     )]
     MissingLet(#[primary_span] Span),
-    #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")]
+    #[suggestion(parser_use_let_not_auto, applicability = "machine-applicable", code = "let")]
     UseLetNotAuto(#[primary_span] Span),
-    #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
+    #[suggestion(parser_use_let_not_var, applicability = "machine-applicable", code = "let")]
     UseLetNotVar(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_comparison_operator)]
+#[diag(parser_invalid_comparison_operator)]
 pub(crate) struct InvalidComparisonOperator {
     #[primary_span]
     pub span: Span,
@@ -140,23 +136,19 @@ pub(crate) struct InvalidComparisonOperator {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidComparisonOperatorSub {
-    #[suggestion_short(
-        parser::use_instead,
-        applicability = "machine-applicable",
-        code = "{correct}"
-    )]
+    #[suggestion_short(use_instead, applicability = "machine-applicable", code = "{correct}")]
     Correctable {
         #[primary_span]
         span: Span,
         invalid: String,
         correct: String,
     },
-    #[label(parser::spaceship_operator_invalid)]
+    #[label(spaceship_operator_invalid)]
     Spaceship(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_logical_operator)]
+#[diag(parser_invalid_logical_operator)]
 #[note]
 pub(crate) struct InvalidLogicalOperator {
     #[primary_span]
@@ -169,13 +161,13 @@ pub(crate) struct InvalidLogicalOperator {
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidLogicalOperatorSub {
     #[suggestion_short(
-        parser::use_amp_amp_for_conjunction,
+        use_amp_amp_for_conjunction,
         applicability = "machine-applicable",
         code = "&&"
     )]
     Conjunction(#[primary_span] Span),
     #[suggestion_short(
-        parser::use_pipe_pipe_for_disjunction,
+        use_pipe_pipe_for_disjunction,
         applicability = "machine-applicable",
         code = "||"
     )]
@@ -183,7 +175,7 @@ pub(crate) enum InvalidLogicalOperatorSub {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::tilde_is_not_unary_operator)]
+#[diag(parser_tilde_is_not_unary_operator)]
 pub(crate) struct TildeAsUnaryOperator(
     #[primary_span]
     #[suggestion_short(applicability = "machine-applicable", code = "!")]
@@ -191,7 +183,7 @@ pub(crate) struct TildeAsUnaryOperator(
 );
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_token_after_not)]
+#[diag(parser_unexpected_token_after_not)]
 pub(crate) struct NotAsNegationOperator {
     #[primary_span]
     pub negated: Span,
@@ -203,21 +195,21 @@ pub(crate) struct NotAsNegationOperator {
 #[derive(Subdiagnostic)]
 pub enum NotAsNegationOperatorSub {
     #[suggestion_short(
-        parser::unexpected_token_after_not_default,
+        parser_unexpected_token_after_not_default,
         applicability = "machine-applicable",
         code = "!"
     )]
     SuggestNotDefault(#[primary_span] Span),
 
     #[suggestion_short(
-        parser::unexpected_token_after_not_bitwise,
+        parser_unexpected_token_after_not_bitwise,
         applicability = "machine-applicable",
         code = "!"
     )]
     SuggestNotBitwise(#[primary_span] Span),
 
     #[suggestion_short(
-        parser::unexpected_token_after_not_logical,
+        parser_unexpected_token_after_not_logical,
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -225,7 +217,7 @@ pub enum NotAsNegationOperatorSub {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::malformed_loop_label)]
+#[diag(parser_malformed_loop_label)]
 pub(crate) struct MalformedLoopLabel {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
@@ -234,7 +226,7 @@ pub(crate) struct MalformedLoopLabel {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::lifetime_in_borrow_expression)]
+#[diag(parser_lifetime_in_borrow_expression)]
 pub(crate) struct LifetimeInBorrowExpression {
     #[primary_span]
     pub span: Span,
@@ -244,27 +236,27 @@ pub(crate) struct LifetimeInBorrowExpression {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::field_expression_with_generic)]
+#[diag(parser_field_expression_with_generic)]
 pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
 
 #[derive(Diagnostic)]
-#[diag(parser::macro_invocation_with_qualified_path)]
+#[diag(parser_macro_invocation_with_qualified_path)]
 pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_token_after_label)]
+#[diag(parser_unexpected_token_after_label)]
 pub(crate) struct UnexpectedTokenAfterLabel {
     #[primary_span]
-    #[label(parser::unexpected_token_after_label)]
+    #[label(parser_unexpected_token_after_label)]
     pub span: Span,
-    #[suggestion_verbose(parser::suggestion_remove_label, code = "")]
+    #[suggestion_verbose(suggestion_remove_label, code = "")]
     pub remove_label: Option<Span>,
     #[subdiagnostic]
     pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion_enclose_in_block, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion_enclose_in_block, applicability = "machine-applicable")]
 pub(crate) struct UnexpectedTokenAfterLabelSugg {
     #[suggestion_part(code = "{{ ")]
     pub left: Span,
@@ -273,7 +265,7 @@ pub(crate) struct UnexpectedTokenAfterLabelSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::require_colon_after_labeled_expression)]
+#[diag(parser_require_colon_after_labeled_expression)]
 #[note]
 pub(crate) struct RequireColonAfterLabeledExpression {
     #[primary_span]
@@ -285,7 +277,7 @@ pub(crate) struct RequireColonAfterLabeledExpression {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::do_catch_syntax_removed)]
+#[diag(parser_do_catch_syntax_removed)]
 #[note]
 pub(crate) struct DoCatchSyntaxRemoved {
     #[primary_span]
@@ -294,7 +286,7 @@ pub(crate) struct DoCatchSyntaxRemoved {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::float_literal_requires_integer_part)]
+#[diag(parser_float_literal_requires_integer_part)]
 pub(crate) struct FloatLiteralRequiresIntegerPart {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "{correct}")]
@@ -303,7 +295,7 @@ pub(crate) struct FloatLiteralRequiresIntegerPart {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_int_literal_width)]
+#[diag(parser_invalid_int_literal_width)]
 #[help]
 pub(crate) struct InvalidIntLiteralWidth {
     #[primary_span]
@@ -312,7 +304,7 @@ pub(crate) struct InvalidIntLiteralWidth {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_num_literal_base_prefix)]
+#[diag(parser_invalid_num_literal_base_prefix)]
 #[note]
 pub(crate) struct InvalidNumLiteralBasePrefix {
     #[primary_span]
@@ -322,7 +314,7 @@ pub(crate) struct InvalidNumLiteralBasePrefix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_num_literal_suffix)]
+#[diag(parser_invalid_num_literal_suffix)]
 #[help]
 pub(crate) struct InvalidNumLiteralSuffix {
     #[primary_span]
@@ -332,7 +324,7 @@ pub(crate) struct InvalidNumLiteralSuffix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_float_literal_width)]
+#[diag(parser_invalid_float_literal_width)]
 #[help]
 pub(crate) struct InvalidFloatLiteralWidth {
     #[primary_span]
@@ -341,7 +333,7 @@ pub(crate) struct InvalidFloatLiteralWidth {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_float_literal_suffix)]
+#[diag(parser_invalid_float_literal_suffix)]
 #[help]
 pub(crate) struct InvalidFloatLiteralSuffix {
     #[primary_span]
@@ -351,14 +343,14 @@ pub(crate) struct InvalidFloatLiteralSuffix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::int_literal_too_large)]
+#[diag(parser_int_literal_too_large)]
 pub(crate) struct IntLiteralTooLarge {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::missing_semicolon_before_array)]
+#[diag(parser_missing_semicolon_before_array)]
 pub(crate) struct MissingSemicolonBeforeArray {
     #[primary_span]
     pub open_delim: Span,
@@ -367,7 +359,7 @@ pub(crate) struct MissingSemicolonBeforeArray {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_block_macro_segment)]
+#[diag(parser_invalid_block_macro_segment)]
 pub(crate) struct InvalidBlockMacroSegment {
     #[primary_span]
     pub span: Span,
@@ -376,7 +368,7 @@ pub(crate) struct InvalidBlockMacroSegment {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::if_expression_missing_then_block)]
+#[diag(parser_if_expression_missing_then_block)]
 pub(crate) struct IfExpressionMissingThenBlock {
     #[primary_span]
     pub if_span: Span,
@@ -386,31 +378,31 @@ pub(crate) struct IfExpressionMissingThenBlock {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum IfExpressionMissingThenBlockSub {
-    #[help(parser::condition_possibly_unfinished)]
+    #[help(condition_possibly_unfinished)]
     UnfinishedCondition(#[primary_span] Span),
-    #[help(parser::add_then_block)]
+    #[help(add_then_block)]
     AddThenBlock(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::if_expression_missing_condition)]
+#[diag(parser_if_expression_missing_condition)]
 pub(crate) struct IfExpressionMissingCondition {
     #[primary_span]
-    #[label(parser::condition_label)]
+    #[label(condition_label)]
     pub if_span: Span,
-    #[label(parser::block_label)]
+    #[label(block_label)]
     pub block_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::expected_expression_found_let)]
+#[diag(parser_expected_expression_found_let)]
 pub(crate) struct ExpectedExpressionFoundLet {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::expected_else_block)]
+#[diag(parser_expected_else_block)]
 pub(crate) struct ExpectedElseBlock {
     #[primary_span]
     pub first_tok_span: Span,
@@ -422,15 +414,15 @@ pub(crate) struct ExpectedElseBlock {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::outer_attribute_not_allowed_on_if_else)]
+#[diag(parser_outer_attribute_not_allowed_on_if_else)]
 pub(crate) struct OuterAttributeNotAllowedOnIfElse {
     #[primary_span]
     pub last: Span,
 
-    #[label(parser::branch_label)]
+    #[label(branch_label)]
     pub branch_span: Span,
 
-    #[label(parser::ctx_label)]
+    #[label(ctx_label)]
     pub ctx_span: Span,
     pub ctx: String,
 
@@ -439,7 +431,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::missing_in_in_for_loop)]
+#[diag(parser_missing_in_in_for_loop)]
 pub(crate) struct MissingInInForLoop {
     #[primary_span]
     pub span: Span,
@@ -450,14 +442,14 @@ pub(crate) struct MissingInInForLoop {
 #[derive(Subdiagnostic)]
 pub(crate) enum MissingInInForLoopSub {
     // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
-    #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+    #[suggestion_short(use_in_not_of, applicability = "maybe-incorrect", code = "in")]
     InNotOf(#[primary_span] Span),
-    #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
+    #[suggestion_short(add_in, applicability = "maybe-incorrect", code = " in ")]
     AddIn(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::missing_comma_after_match_arm)]
+#[diag(parser_missing_comma_after_match_arm)]
 pub(crate) struct MissingCommaAfterMatchArm {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = ",")]
@@ -465,7 +457,7 @@ pub(crate) struct MissingCommaAfterMatchArm {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::catch_after_try)]
+#[diag(parser_catch_after_try)]
 #[help]
 pub(crate) struct CatchAfterTry {
     #[primary_span]
@@ -473,7 +465,7 @@ pub(crate) struct CatchAfterTry {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::comma_after_base_struct)]
+#[diag(parser_comma_after_base_struct)]
 #[note]
 pub(crate) struct CommaAfterBaseStruct {
     #[primary_span]
@@ -483,7 +475,7 @@ pub(crate) struct CommaAfterBaseStruct {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::eq_field_init)]
+#[diag(parser_eq_field_init)]
 pub(crate) struct EqFieldInit {
     #[primary_span]
     pub span: Span,
@@ -492,16 +484,16 @@ pub(crate) struct EqFieldInit {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::dotdotdot)]
+#[diag(parser_dotdotdot)]
 pub(crate) struct DotDotDot {
     #[primary_span]
-    #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
-    #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    #[suggestion(suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+    #[suggestion(suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::left_arrow_operator)]
+#[diag(parser_left_arrow_operator)]
 pub(crate) struct LeftArrowOperator {
     #[primary_span]
     #[suggestion(applicability = "maybe-incorrect", code = "< -")]
@@ -509,7 +501,7 @@ pub(crate) struct LeftArrowOperator {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::remove_let)]
+#[diag(parser_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "")]
@@ -517,7 +509,7 @@ pub(crate) struct RemoveLet {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::use_eq_instead)]
+#[diag(parser_use_eq_instead)]
 pub(crate) struct UseEqInstead {
     #[primary_span]
     #[suggestion_short(applicability = "machine-applicable", code = "=")]
@@ -525,7 +517,7 @@ pub(crate) struct UseEqInstead {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::use_empty_block_not_semi)]
+#[diag(parser_use_empty_block_not_semi)]
 pub(crate) struct UseEmptyBlockNotSemi {
     #[primary_span]
     #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")]
@@ -533,33 +525,33 @@ pub(crate) struct UseEmptyBlockNotSemi {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::comparison_interpreted_as_generic)]
+#[diag(parser_comparison_interpreted_as_generic)]
 pub(crate) struct ComparisonInterpretedAsGeneric {
     #[primary_span]
-    #[label(parser::label_comparison)]
+    #[label(label_comparison)]
     pub comparison: Span,
     pub r#type: Path,
-    #[label(parser::label_args)]
+    #[label(label_args)]
     pub args: Span,
     #[subdiagnostic]
     pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::shift_interpreted_as_generic)]
+#[diag(parser_shift_interpreted_as_generic)]
 pub(crate) struct ShiftInterpretedAsGeneric {
     #[primary_span]
-    #[label(parser::label_comparison)]
+    #[label(label_comparison)]
     pub shift: Span,
     pub r#type: Path,
-    #[label(parser::label_args)]
+    #[label(label_args)]
     pub args: Span,
     #[subdiagnostic]
     pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -568,7 +560,7 @@ pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::found_expr_would_be_stmt)]
+#[diag(parser_found_expr_would_be_stmt)]
 pub(crate) struct FoundExprWouldBeStmt {
     #[primary_span]
     #[label]
@@ -579,23 +571,19 @@ pub(crate) struct FoundExprWouldBeStmt {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::leading_plus_not_supported)]
+#[diag(parser_leading_plus_not_supported)]
 pub(crate) struct LeadingPlusNotSupported {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[suggestion_verbose(
-        parser::suggestion_remove_plus,
-        code = "",
-        applicability = "machine-applicable"
-    )]
+    #[suggestion_verbose(suggestion_remove_plus, code = "", applicability = "machine-applicable")]
     pub remove_plus: Option<Span>,
     #[subdiagnostic]
     pub add_parentheses: Option<ExprParenthesesNeeded>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::parentheses_with_struct_fields)]
+#[diag(parser_parentheses_with_struct_fields)]
 pub(crate) struct ParenthesesWithStructFields {
     #[primary_span]
     pub span: Span,
@@ -607,7 +595,7 @@ pub(crate) struct ParenthesesWithStructFields {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion_braces_for_struct, applicability = "maybe-incorrect")]
+#[multipart_suggestion(suggestion_braces_for_struct, applicability = "maybe-incorrect")]
 pub(crate) struct BracesForStructLiteral {
     #[suggestion_part(code = " {{ ")]
     pub first: Span,
@@ -616,14 +604,14 @@ pub(crate) struct BracesForStructLiteral {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
+#[multipart_suggestion(suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
 pub(crate) struct NoFieldsForFnCall {
     #[suggestion_part(code = "")]
     pub fields: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::labeled_loop_in_break)]
+#[diag(parser_labeled_loop_in_break)]
 pub(crate) struct LabeledLoopInBreak {
     #[primary_span]
     pub span: Span,
@@ -633,7 +621,7 @@ pub(crate) struct LabeledLoopInBreak {
 
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(
-    parser::sugg_wrap_expression_in_parentheses,
+    parser_sugg_wrap_expression_in_parentheses,
     applicability = "machine-applicable"
 )]
 pub(crate) struct WrapExpressionInParentheses {
@@ -644,7 +632,7 @@ pub(crate) struct WrapExpressionInParentheses {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::array_brackets_instead_of_braces)]
+#[diag(parser_array_brackets_instead_of_braces)]
 pub(crate) struct ArrayBracketsInsteadOfSpaces {
     #[primary_span]
     pub span: Span,
@@ -653,7 +641,7 @@ pub(crate) struct ArrayBracketsInsteadOfSpaces {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "maybe-incorrect")]
+#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
 pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
     #[suggestion_part(code = "[")]
     pub left: Span,
@@ -662,12 +650,12 @@ pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::match_arm_body_without_braces)]
+#[diag(parser_match_arm_body_without_braces)]
 pub(crate) struct MatchArmBodyWithoutBraces {
     #[primary_span]
-    #[label(parser::label_statements)]
+    #[label(label_statements)]
     pub statements: Span,
-    #[label(parser::label_arrow)]
+    #[label(label_arrow)]
     pub arrow: Span,
     pub num_statements: usize,
     #[subdiagnostic]
@@ -676,7 +664,7 @@ pub(crate) struct MatchArmBodyWithoutBraces {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum MatchArmBodyWithoutBracesSugg {
-    #[multipart_suggestion(parser::suggestion_add_braces, applicability = "machine-applicable")]
+    #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
     AddBraces {
         #[suggestion_part(code = "{{ ")]
         left: Span,
@@ -684,7 +672,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
         right: Span,
     },
     #[suggestion(
-        parser::suggestion_use_comma_not_semicolon,
+        suggestion_use_comma_not_semicolon,
         code = ",",
         applicability = "machine-applicable"
     )]
@@ -695,7 +683,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::struct_literal_not_allowed_here)]
+#[diag(parser_struct_literal_not_allowed_here)]
 pub(crate) struct StructLiteralNotAllowedHere {
     #[primary_span]
     pub span: Span,
@@ -704,7 +692,7 @@ pub(crate) struct StructLiteralNotAllowedHere {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct StructLiteralNotAllowedHereSugg {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -713,38 +701,38 @@ pub(crate) struct StructLiteralNotAllowedHereSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_interpolated_expression)]
+#[diag(parser_invalid_interpolated_expression)]
 pub(crate) struct InvalidInterpolatedExpression {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::hexadecimal_float_literal_not_supported)]
+#[diag(parser_hexadecimal_float_literal_not_supported)]
 pub(crate) struct HexadecimalFloatLiteralNotSupported {
     #[primary_span]
-    #[label(parser::not_supported)]
+    #[label(parser_not_supported)]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::octal_float_literal_not_supported)]
+#[diag(parser_octal_float_literal_not_supported)]
 pub(crate) struct OctalFloatLiteralNotSupported {
     #[primary_span]
-    #[label(parser::not_supported)]
+    #[label(parser_not_supported)]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::binary_float_literal_not_supported)]
+#[diag(parser_binary_float_literal_not_supported)]
 pub(crate) struct BinaryFloatLiteralNotSupported {
     #[primary_span]
-    #[label(parser::not_supported)]
+    #[label(parser_not_supported)]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_literal_suffix)]
+#[diag(parser_invalid_literal_suffix)]
 pub(crate) struct InvalidLiteralSuffix {
     #[primary_span]
     #[label]
@@ -755,20 +743,20 @@ pub(crate) struct InvalidLiteralSuffix {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_literal_suffix_on_tuple_index)]
+#[diag(parser_invalid_literal_suffix_on_tuple_index)]
 pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
     #[primary_span]
     #[label]
     pub span: Span,
     pub suffix: Symbol,
-    #[help(parser::tuple_exception_line_1)]
-    #[help(parser::tuple_exception_line_2)]
-    #[help(parser::tuple_exception_line_3)]
+    #[help(tuple_exception_line_1)]
+    #[help(tuple_exception_line_2)]
+    #[help(tuple_exception_line_3)]
     pub exception: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::non_string_abi_literal)]
+#[diag(parser_non_string_abi_literal)]
 pub(crate) struct NonStringAbiLiteral {
     #[primary_span]
     #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
@@ -776,21 +764,21 @@ pub(crate) struct NonStringAbiLiteral {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::mismatched_closing_delimiter)]
+#[diag(parser_mismatched_closing_delimiter)]
 pub(crate) struct MismatchedClosingDelimiter {
     #[primary_span]
     pub spans: Vec<Span>,
     pub delimiter: String,
-    #[label(parser::label_unmatched)]
+    #[label(label_unmatched)]
     pub unmatched: Span,
-    #[label(parser::label_opening_candidate)]
+    #[label(label_opening_candidate)]
     pub opening_candidate: Option<Span>,
-    #[label(parser::label_unclosed)]
+    #[label(label_unclosed)]
     pub unclosed: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::incorrect_visibility_restriction, code = "E0704")]
+#[diag(parser_incorrect_visibility_restriction, code = "E0704")]
 #[help]
 pub(crate) struct IncorrectVisibilityRestriction {
     #[primary_span]
@@ -800,21 +788,21 @@ pub(crate) struct IncorrectVisibilityRestriction {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::assignment_else_not_allowed)]
+#[diag(parser_assignment_else_not_allowed)]
 pub(crate) struct AssignmentElseNotAllowed {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::expected_statement_after_outer_attr)]
+#[diag(parser_expected_statement_after_outer_attr)]
 pub(crate) struct ExpectedStatementAfterOuterAttr {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::doc_comment_does_not_document_anything, code = "E0585")]
+#[diag(parser_doc_comment_does_not_document_anything, code = "E0585")]
 #[help]
 pub(crate) struct DocCommentDoesNotDocumentAnything {
     #[primary_span]
@@ -824,7 +812,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::const_let_mutually_exclusive)]
+#[diag(parser_const_let_mutually_exclusive)]
 pub(crate) struct ConstLetMutuallyExclusive {
     #[primary_span]
     #[suggestion(code = "const", applicability = "maybe-incorrect")]
@@ -832,7 +820,7 @@ pub(crate) struct ConstLetMutuallyExclusive {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_expression_in_let_else)]
+#[diag(parser_invalid_expression_in_let_else)]
 pub(crate) struct InvalidExpressionInLetElse {
     #[primary_span]
     pub span: Span,
@@ -842,7 +830,7 @@ pub(crate) struct InvalidExpressionInLetElse {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_curly_in_let_else)]
+#[diag(parser_invalid_curly_in_let_else)]
 pub(crate) struct InvalidCurlyInLetElse {
     #[primary_span]
     pub span: Span,
@@ -851,7 +839,7 @@ pub(crate) struct InvalidCurlyInLetElse {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::compound_assignment_expression_in_let)]
+#[diag(parser_compound_assignment_expression_in_let)]
 #[help]
 pub(crate) struct CompoundAssignmentExpressionInLet {
     #[primary_span]
@@ -860,7 +848,7 @@ pub(crate) struct CompoundAssignmentExpressionInLet {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::suffixed_literal_in_attribute)]
+#[diag(parser_suffixed_literal_in_attribute)]
 #[help]
 pub(crate) struct SuffixedLiteralInAttribute {
     #[primary_span]
@@ -868,7 +856,7 @@ pub(crate) struct SuffixedLiteralInAttribute {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::invalid_meta_item)]
+#[diag(parser_invalid_meta_item)]
 pub(crate) struct InvalidMetaItem {
     #[primary_span]
     pub span: Span,
@@ -877,7 +865,7 @@ pub(crate) struct InvalidMetaItem {
 
 #[derive(Subdiagnostic)]
 #[suggestion_verbose(
-    parser::sugg_escape_to_use_as_identifier,
+    parser_sugg_escape_to_use_as_identifier,
     applicability = "maybe-incorrect",
     code = "r#"
 )]
@@ -888,7 +876,7 @@ pub(crate) struct SuggEscapeToUseAsIdentifier {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::sugg_remove_comma, applicability = "machine-applicable", code = "")]
+#[suggestion(parser_sugg_remove_comma, applicability = "machine-applicable", code = "")]
 pub(crate) struct SuggRemoveComma {
     #[primary_span]
     pub span: Span,
@@ -896,15 +884,15 @@ pub(crate) struct SuggRemoveComma {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum ExpectedIdentifierFound {
-    #[label(parser::expected_identifier_found_reserved_identifier)]
+    #[label(parser_expected_identifier_found_reserved_identifier)]
     ReservedIdentifier(#[primary_span] Span),
-    #[label(parser::expected_identifier_found_keyword)]
+    #[label(parser_expected_identifier_found_keyword)]
     Keyword(#[primary_span] Span),
-    #[label(parser::expected_identifier_found_reserved_keyword)]
+    #[label(parser_expected_identifier_found_reserved_keyword)]
     ReservedKeyword(#[primary_span] Span),
-    #[label(parser::expected_identifier_found_doc_comment)]
+    #[label(parser_expected_identifier_found_doc_comment)]
     DocComment(#[primary_span] Span),
-    #[label(parser::expected_identifier)]
+    #[label(parser_expected_identifier)]
     Other(#[primary_span] Span),
 }
 
@@ -938,18 +926,16 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
 
         let mut diag = handler.struct_diagnostic(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
-                fluent::parser::expected_identifier_found_reserved_identifier_str
-            }
-            Some(TokenDescription::Keyword) => {
-                fluent::parser::expected_identifier_found_keyword_str
+                fluent::parser_expected_identifier_found_reserved_identifier_str
             }
+            Some(TokenDescription::Keyword) => fluent::parser_expected_identifier_found_keyword_str,
             Some(TokenDescription::ReservedKeyword) => {
-                fluent::parser::expected_identifier_found_reserved_keyword_str
+                fluent::parser_expected_identifier_found_reserved_keyword_str
             }
             Some(TokenDescription::DocComment) => {
-                fluent::parser::expected_identifier_found_doc_comment_str
+                fluent::parser_expected_identifier_found_doc_comment_str
             }
-            None => fluent::parser::expected_identifier_found_str,
+            None => fluent::parser_expected_identifier_found_str,
         });
         diag.set_span(self.span);
         diag.set_arg("token", self.token);
@@ -985,22 +971,22 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
 
         let mut diag = handler.struct_diagnostic(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
-                fluent::parser::expected_semi_found_reserved_identifier_str
+                fluent::parser_expected_semi_found_reserved_identifier_str
             }
-            Some(TokenDescription::Keyword) => fluent::parser::expected_semi_found_keyword_str,
+            Some(TokenDescription::Keyword) => fluent::parser_expected_semi_found_keyword_str,
             Some(TokenDescription::ReservedKeyword) => {
-                fluent::parser::expected_semi_found_reserved_keyword_str
+                fluent::parser_expected_semi_found_reserved_keyword_str
             }
             Some(TokenDescription::DocComment) => {
-                fluent::parser::expected_semi_found_doc_comment_str
+                fluent::parser_expected_semi_found_doc_comment_str
             }
-            None => fluent::parser::expected_semi_found_str,
+            None => fluent::parser_expected_semi_found_str,
         });
         diag.set_span(self.span);
         diag.set_arg("token", self.token);
 
         if let Some(unexpected_token_label) = self.unexpected_token_label {
-            diag.span_label(unexpected_token_label, fluent::parser::label_unexpected_token);
+            diag.span_label(unexpected_token_label, fluent::parser_label_unexpected_token);
         }
 
         self.sugg.add_to_diagnostic(&mut diag);
@@ -1012,17 +998,17 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
 #[derive(Subdiagnostic)]
 pub(crate) enum ExpectedSemiSugg {
     #[suggestion(
-        parser::sugg_change_this_to_semi,
+        parser_sugg_change_this_to_semi,
         code = ";",
         applicability = "machine-applicable"
     )]
     ChangeToSemi(#[primary_span] Span),
-    #[suggestion_short(parser::sugg_add_semi, code = ";", applicability = "machine-applicable")]
+    #[suggestion_short(parser_sugg_add_semi, code = ";", applicability = "machine-applicable")]
     AddSemi(#[primary_span] Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::struct_literal_body_without_path)]
+#[diag(parser_struct_literal_body_without_path)]
 pub(crate) struct StructLiteralBodyWithoutPath {
     #[primary_span]
     pub span: Span,
@@ -1031,7 +1017,7 @@ pub(crate) struct StructLiteralBodyWithoutPath {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "has-placeholders")]
+#[multipart_suggestion(suggestion, applicability = "has-placeholders")]
 pub(crate) struct StructLiteralBodyWithoutPathSugg {
     #[suggestion_part(code = "{{ SomeStruct ")]
     pub before: Span,
@@ -1040,7 +1026,7 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unmatched_angle_brackets)]
+#[diag(parser_unmatched_angle_brackets)]
 pub(crate) struct UnmatchedAngleBrackets {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -1049,7 +1035,7 @@ pub(crate) struct UnmatchedAngleBrackets {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::generic_parameters_without_angle_brackets)]
+#[diag(parser_generic_parameters_without_angle_brackets)]
 pub(crate) struct GenericParamsWithoutAngleBrackets {
     #[primary_span]
     pub span: Span,
@@ -1058,7 +1044,7 @@ pub(crate) struct GenericParamsWithoutAngleBrackets {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
     #[suggestion_part(code = "<")]
     pub left: Span,
@@ -1067,18 +1053,18 @@ pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::comparison_operators_cannot_be_chained)]
+#[diag(parser_comparison_operators_cannot_be_chained)]
 pub(crate) struct ComparisonOperatorsCannotBeChained {
     #[primary_span]
     pub span: Vec<Span>,
     #[suggestion_verbose(
-        parser::sugg_turbofish_syntax,
+        parser_sugg_turbofish_syntax,
         code = "::",
         applicability = "maybe-incorrect"
     )]
     pub suggest_turbofish: Option<Span>,
-    #[help(parser::sugg_turbofish_syntax)]
-    #[help(parser::sugg_parentheses_for_function_args)]
+    #[help(parser_sugg_turbofish_syntax)]
+    #[help(sugg_parentheses_for_function_args)]
     pub help_turbofish: Option<()>,
     #[subdiagnostic]
     pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>,
@@ -1087,7 +1073,7 @@ pub(crate) struct ComparisonOperatorsCannotBeChained {
 #[derive(Subdiagnostic)]
 pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
     #[suggestion_verbose(
-        parser::sugg_split_comparison,
+        sugg_split_comparison,
         code = " && {middle_term}",
         applicability = "maybe-incorrect"
     )]
@@ -1096,7 +1082,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
         span: Span,
         middle_term: String,
     },
-    #[multipart_suggestion(parser::sugg_parenthesize, applicability = "maybe-incorrect")]
+    #[multipart_suggestion(sugg_parenthesize, applicability = "maybe-incorrect")]
     Parenthesize {
         #[suggestion_part(code = "(")]
         left: Span,
@@ -1106,7 +1092,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::question_mark_in_type)]
+#[diag(parser_question_mark_in_type)]
 pub(crate) struct QuestionMarkInType {
     #[primary_span]
     #[label]
@@ -1116,7 +1102,7 @@ pub(crate) struct QuestionMarkInType {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct QuestionMarkInTypeSugg {
     #[suggestion_part(code = "Option<")]
     pub left: Span,
@@ -1125,7 +1111,7 @@ pub(crate) struct QuestionMarkInTypeSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_parentheses_in_for_head)]
+#[diag(parser_unexpected_parentheses_in_for_head)]
 pub(crate) struct ParenthesesInForHead {
     #[primary_span]
     pub span: Vec<Span>,
@@ -1134,7 +1120,7 @@ pub(crate) struct ParenthesesInForHead {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ParenthesesInForHeadSugg {
     #[suggestion_part(code = "")]
     pub left: Span,
@@ -1143,7 +1129,7 @@ pub(crate) struct ParenthesesInForHeadSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::doc_comment_on_param_type)]
+#[diag(parser_doc_comment_on_param_type)]
 pub(crate) struct DocCommentOnParamType {
     #[primary_span]
     #[label]
@@ -1151,7 +1137,7 @@ pub(crate) struct DocCommentOnParamType {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::attribute_on_param_type)]
+#[diag(parser_attribute_on_param_type)]
 pub(crate) struct AttributeOnParamType {
     #[primary_span]
     #[label]
@@ -1159,7 +1145,7 @@ pub(crate) struct AttributeOnParamType {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::pattern_method_param_without_body, code = "E0642")]
+#[diag(parser_pattern_method_param_without_body, code = "E0642")]
 pub(crate) struct PatternMethodParamWithoutBody {
     #[primary_span]
     #[suggestion(code = "_", applicability = "machine-applicable")]
@@ -1167,7 +1153,7 @@ pub(crate) struct PatternMethodParamWithoutBody {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::self_param_not_first)]
+#[diag(parser_self_param_not_first)]
 pub(crate) struct SelfParamNotFirst {
     #[primary_span]
     #[label]
@@ -1175,7 +1161,7 @@ pub(crate) struct SelfParamNotFirst {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::const_generic_without_braces)]
+#[diag(parser_const_generic_without_braces)]
 pub(crate) struct ConstGenericWithoutBraces {
     #[primary_span]
     pub span: Span,
@@ -1184,7 +1170,7 @@ pub(crate) struct ConstGenericWithoutBraces {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
 pub(crate) struct ConstGenericWithoutBracesSugg {
     #[suggestion_part(code = "{{ ")]
     pub left: Span,
@@ -1193,7 +1179,7 @@ pub(crate) struct ConstGenericWithoutBracesSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_const_param_declaration)]
+#[diag(parser_unexpected_const_param_declaration)]
 pub(crate) struct UnexpectedConstParamDeclaration {
     #[primary_span]
     #[label]
@@ -1204,7 +1190,7 @@ pub(crate) struct UnexpectedConstParamDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum UnexpectedConstParamDeclarationSugg {
-    #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
     AddParam {
         #[suggestion_part(code = "<{snippet}>")]
         impl_generics: Span,
@@ -1213,7 +1199,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg {
         snippet: String,
         ident: String,
     },
-    #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
     AppendParam {
         #[suggestion_part(code = ", {snippet}")]
         impl_generics_end: Span,
@@ -1225,7 +1211,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::unexpected_const_in_generic_param)]
+#[diag(parser_unexpected_const_in_generic_param)]
 pub(crate) struct UnexpectedConstInGenericParam {
     #[primary_span]
     pub span: Span,
@@ -1234,7 +1220,7 @@ pub(crate) struct UnexpectedConstInGenericParam {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::async_move_order_incorrect)]
+#[diag(parser_async_move_order_incorrect)]
 pub(crate) struct AsyncMoveOrderIncorrect {
     #[primary_span]
     #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")]
@@ -1242,7 +1228,7 @@ pub(crate) struct AsyncMoveOrderIncorrect {
 }
 
 #[derive(Diagnostic)]
-#[diag(parser::double_colon_in_bound)]
+#[diag(parser_double_colon_in_bound)]
 pub(crate) struct DoubleColonInBound {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 88540e13ef2..462bce16ad7 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -3,7 +3,9 @@ use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult, StashKey,
+};
 use rustc_lexer::unescape::{self, Mode};
 use rustc_lexer::Cursor;
 use rustc_lexer::{Base, DocStyle, RawStrError};
@@ -203,7 +205,10 @@ impl<'a> StringReader<'a> {
                     // this is necessary.
                     let lifetime_name = self.str_from(start);
                     if starts_with_number {
-                        self.err_span_(start, self.pos, "lifetimes cannot start with a number");
+                        let span = self.mk_sp(start, self.pos);
+                        let mut diag = self.sess.struct_err("lifetimes cannot start with a number");
+                        diag.set_span(span);
+                        diag.stash(span, StashKey::LifetimeIsChar);
                     }
                     let ident = Symbol::intern(lifetime_name);
                     token::Lifetime(ident)
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 77c4fadab45..f075de71426 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -113,11 +113,26 @@ pub(crate) fn emit_unescape_error(
                 } else {
                     ("", "if you meant to write a `str` literal, use double quotes")
                 };
-
+                let mut escaped = String::with_capacity(lit.len());
+                let mut chrs = lit.chars().peekable();
+                while let Some(first) = chrs.next() {
+                    match (first, chrs.peek()) {
+                        ('\\', Some('"')) => {
+                            escaped.push('\\');
+                            escaped.push('"');
+                            chrs.next();
+                        }
+                        ('"', _) => {
+                            escaped.push('\\');
+                            escaped.push('"')
+                        }
+                        (c, _) => escaped.push(c),
+                    };
+                }
                 handler.span_suggestion(
                     span_with_quotes,
                     msg,
-                    format!("{}\"{}\"", prefix, lit),
+                    format!("{prefix}\"{escaped}\""),
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 58be348883c..9e45656946b 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -55,7 +55,7 @@ impl<'a> Parser<'a> {
                     let span = self.token.span;
                     let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
                         span,
-                        fluent::parser::inner_doc_comment_not_permitted,
+                        fluent::parser_inner_doc_comment_not_permitted,
                         error_code!(E0753),
                     );
                     if let Some(replacement_span) = self.annotate_following_item_if_applicable(
@@ -66,10 +66,10 @@ impl<'a> Parser<'a> {
                             token::CommentKind::Block => OuterAttributeType::DocBlockComment,
                         },
                     ) {
-                        err.note(fluent::parser::note);
+                        err.note(fluent::note);
                         err.span_suggestion_verbose(
                             replacement_span,
-                            fluent::parser::suggestion,
+                            fluent::suggestion,
                             "",
                             rustc_errors::Applicability::MachineApplicable,
                         );
@@ -173,10 +173,10 @@ impl<'a> Parser<'a> {
             Ok(Some(item)) => {
                 // FIXME(#100717)
                 err.set_arg("item", item.kind.descr());
-                err.span_label(item.span, fluent::parser::label_does_not_annotate_this);
+                err.span_label(item.span, fluent::label_does_not_annotate_this);
                 err.span_suggestion_verbose(
                     replacement_span,
-                    fluent::parser::sugg_change_inner_to_outer,
+                    fluent::sugg_change_inner_to_outer,
                     match attr_type {
                         OuterAttributeType::Attribute => "",
                         OuterAttributeType::DocBlockComment => "*",
@@ -200,27 +200,27 @@ impl<'a> Parser<'a> {
                 Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
                     let mut diag = self.struct_span_err(
                         attr_sp,
-                        fluent::parser::inner_attr_not_permitted_after_outer_doc_comment,
+                        fluent::parser_inner_attr_not_permitted_after_outer_doc_comment,
                     );
-                    diag.span_label(attr_sp, fluent::parser::label_attr)
-                        .span_label(prev_doc_comment_span, fluent::parser::label_prev_doc_comment);
+                    diag.span_label(attr_sp, fluent::label_attr)
+                        .span_label(prev_doc_comment_span, fluent::label_prev_doc_comment);
                     diag
                 }
                 Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
                     let mut diag = self.struct_span_err(
                         attr_sp,
-                        fluent::parser::inner_attr_not_permitted_after_outer_attr,
+                        fluent::parser_inner_attr_not_permitted_after_outer_attr,
                     );
-                    diag.span_label(attr_sp, fluent::parser::label_attr)
-                        .span_label(prev_outer_attr_sp, fluent::parser::label_prev_attr);
+                    diag.span_label(attr_sp, fluent::label_attr)
+                        .span_label(prev_outer_attr_sp, fluent::label_prev_attr);
                     diag
                 }
                 Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
-                    self.struct_span_err(attr_sp, fluent::parser::inner_attr_not_permitted)
+                    self.struct_span_err(attr_sp, fluent::parser_inner_attr_not_permitted)
                 }
             };
 
-            diag.note(fluent::parser::inner_attr_explanation);
+            diag.note(fluent::parser_inner_attr_explanation);
             if self
                 .annotate_following_item_if_applicable(
                     &mut diag,
@@ -229,7 +229,7 @@ impl<'a> Parser<'a> {
                 )
                 .is_some()
             {
-                diag.note(fluent::parser::outer_attr_explanation);
+                diag.note(fluent::parser_outer_attr_explanation);
             };
             diag.emit();
         }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 828b7d2f2f7..887a4a6de33 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -926,7 +926,7 @@ impl<'a> Parser<'a> {
                     if self.eat(&token::Gt) {
                         e.span_suggestion_verbose(
                             binop.span.shrink_to_lo(),
-                            fluent::parser::sugg_turbofish_syntax,
+                            fluent::parser_sugg_turbofish_syntax,
                             "::",
                             Applicability::MaybeIncorrect,
                         )
@@ -1374,9 +1374,17 @@ impl<'a> Parser<'a> {
         kind: IncDecRecovery,
         (pre_span, post_span): (Span, Span),
     ) -> MultiSugg {
+        let mut patches = Vec::new();
+
+        if !pre_span.is_empty() {
+            patches.push((pre_span, String::new()));
+        }
+
+        patches.push((post_span, format!(" {}= 1", kind.op.chr())));
+
         MultiSugg {
             msg: format!("use `{}= 1` instead", kind.op.chr()),
-            patches: vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))],
+            patches,
             applicability: Applicability::MachineApplicable,
         }
     }
@@ -1461,7 +1469,7 @@ impl<'a> Parser<'a> {
         let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
             // Point at the end of the macro call when reaching end of macro arguments.
             (token::Eof, Some(_)) => {
-                let sp = self.sess.source_map().next_point(self.prev_token.span);
+                let sp = self.prev_token.span.shrink_to_hi();
                 (sp, sp)
             }
             // We don't want to point at the following span after DUMMY_SP.
@@ -2039,7 +2047,7 @@ impl<'a> Parser<'a> {
     pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let (span, msg) = match (&self.token.kind, self.subparser_name) {
             (&token::Eof, Some(origin)) => {
-                let sp = self.sess.source_map().next_point(self.prev_token.span);
+                let sp = self.prev_token.span.shrink_to_hi();
                 (sp, format!("expected expression, found end of {origin}"))
             }
             _ => (
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 11301f03e48..98520a446a6 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -42,8 +42,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast::{ClosureBinder, StmtKind};
 use rustc_ast_pretty::pprust;
-use rustc_errors::IntoDiagnostic;
-use rustc_errors::{Applicability, Diagnostic, PResult};
+use rustc_errors::{
+    Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
+    StashKey,
+};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -1513,11 +1515,11 @@ impl<'a> Parser<'a> {
     /// Parse `'label: $expr`. The label is already parsed.
     fn parse_labeled_expr(
         &mut self,
-        label: Label,
+        label_: Label,
         mut consume_colon: bool,
     ) -> PResult<'a, P<Expr>> {
-        let lo = label.ident.span;
-        let label = Some(label);
+        let lo = label_.ident.span;
+        let label = Some(label_);
         let ate_colon = self.eat(&token::Colon);
         let expr = if self.eat_keyword(kw::While) {
             self.parse_while_expr(label, lo)
@@ -1530,6 +1532,19 @@ impl<'a> Parser<'a> {
         {
             self.parse_block_expr(label, lo, BlockCheckMode::Default)
         } else if !ate_colon
+            && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
+                || self.token.is_op())
+        {
+            let lit = self.recover_unclosed_char(label_.ident, |self_| {
+                self_.sess.create_err(UnexpectedTokenAfterLabel {
+                    span: self_.token.span,
+                    remove_label: None,
+                    enclose_in_block: None,
+                })
+            });
+            consume_colon = false;
+            Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
+        } else if !ate_colon
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
@@ -1603,6 +1618,39 @@ impl<'a> Parser<'a> {
         Ok(expr)
     }
 
+    /// Emit an error when a char is parsed as a lifetime because of a missing quote
+    pub(super) fn recover_unclosed_char(
+        &mut self,
+        lifetime: Ident,
+        err: impl FnOnce(&mut Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>,
+    ) -> ast::Lit {
+        if let Some(mut diag) =
+            self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
+        {
+            diag.span_suggestion_verbose(
+                lifetime.span.shrink_to_hi(),
+                "add `'` to close the char literal",
+                "'",
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
+        } else {
+            err(self)
+                .span_suggestion_verbose(
+                    lifetime.span.shrink_to_hi(),
+                    "add `'` to close the char literal",
+                    "'",
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
+        ast::Lit {
+            token_lit: token::Lit::new(token::LitKind::Char, lifetime.name, None),
+            kind: ast::LitKind::Char(lifetime.name.as_str().chars().next().unwrap_or('_')),
+            span: lifetime.span,
+        }
+    }
+
     /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
     fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
@@ -1728,7 +1776,7 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
-        self.parse_opt_lit().ok_or_else(|| {
+        self.parse_opt_lit().ok_or(()).or_else(|()| {
             if let token::Interpolated(inner) = &self.token.kind {
                 let expr = match inner.as_ref() {
                     token::NtExpr(expr) => Some(expr),
@@ -1740,12 +1788,22 @@ impl<'a> Parser<'a> {
                         let mut err = InvalidInterpolatedExpression { span: self.token.span }
                             .into_diagnostic(&self.sess.span_diagnostic);
                         err.downgrade_to_delayed_bug();
-                        return err;
+                        return Err(err);
                     }
                 }
             }
-            let msg = format!("unexpected token: {}", super::token_descr(&self.token));
-            self.struct_span_err(self.token.span, &msg)
+            let token = self.token.clone();
+            let err = |self_: &mut Self| {
+                let msg = format!("unexpected token: {}", super::token_descr(&token));
+                self_.struct_span_err(token.span, &msg)
+            };
+            // On an error path, eagerly consider a lifetime to be an unclosed character lit
+            if self.token.is_lifetime() {
+                let lt = self.expect_lifetime();
+                Ok(self.recover_unclosed_char(lt.ident, err))
+            } else {
+                Err(err(self))
+            }
         })
     }
 
@@ -2051,6 +2109,10 @@ impl<'a> Parser<'a> {
 
         if self.token.kind == TokenKind::Semi
             && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
+            // HACK: This is needed so we can detect whether we're inside a macro,
+            // where regular assumptions about what tokens can follow other tokens
+            // don't necessarily apply.
+            && self.subparser_name.is_none()
         {
             // It is likely that the closure body is a block but where the
             // braces have been removed. We will recover and eat the next
@@ -2172,7 +2234,7 @@ impl<'a> Parser<'a> {
                     },
                 ExprKind::Block(_, None) => {
                     self.sess.emit_err(IfExpressionMissingCondition {
-                        if_span: self.sess.source_map().next_point(lo),
+                        if_span: lo.shrink_to_hi(),
                         block_span: self.sess.source_map().start_point(cond_span),
                     });
                     std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ebcbc75ba32..bda301c52e9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1601,7 +1601,7 @@ impl<'a> Parser<'a> {
                     self.sess.emit_err(err);
                 } else {
                     if !seen_comma {
-                        let sp = self.sess.source_map().next_point(previous_span);
+                        let sp = previous_span.shrink_to_hi();
                         err.missing_comma = Some(sp);
                     }
                     return Err(err.into_diagnostic(&self.sess.span_diagnostic));
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 56efec422d6..52c11b4e35f 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -402,6 +402,25 @@ impl<'a> Parser<'a> {
             } else {
                 PatKind::Path(qself, path)
             }
+        } else if matches!(self.token.kind, token::Lifetime(_))
+            // In pattern position, we're totally fine with using "next token isn't colon"
+            // as a heuristic. We could probably just always try to recover if it's a lifetime,
+            // because we never have `'a: label {}` in a pattern position anyways, but it does
+            // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
+            && !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
+        {
+            // Recover a `'a` as a `'a'` literal
+            let lt = self.expect_lifetime();
+            let lit = self.recover_unclosed_char(lt.ident, |self_| {
+                let expected = expected.unwrap_or("pattern");
+                let msg =
+                    format!("expected {}, found {}", expected, super::token_descr(&self_.token));
+
+                let mut err = self_.struct_span_err(self_.token.span, &msg);
+                err.span_label(self_.token.span, format!("expected {}", expected));
+                err
+            });
+            PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
         } else {
             // Try to parse everything else as literal with optional minus
             match self.parse_literal_maybe_minus() {
@@ -799,6 +818,7 @@ impl<'a> Parser<'a> {
                 || t.kind == token::Dot // e.g. `.5` for recovery;
                 || t.can_begin_literal_maybe_minus() // e.g. `42`.
                 || t.is_whole_expr()
+                || t.is_lifetime() // recover `'a` instead of `'a'`
             })
     }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 3c684fffac8..b19e85427e7 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -822,8 +822,8 @@ impl CheckAttrVisitor<'_> {
             if let Some((prev_inline, prev_span)) = *specified_inline {
                 if do_inline != prev_inline {
                     let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
-                    spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first);
-                    spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second);
+                    spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
+                    spans.push_span_label(meta.span(), fluent::passes_doc_inline_conflict_second);
                     self.tcx.sess.emit_err(errors::DocKeywordConflict { spans });
                     return false;
                 }
@@ -873,7 +873,7 @@ impl CheckAttrVisitor<'_> {
                 INVALID_DOC_ATTRIBUTES,
                 hir_id,
                 meta.span(),
-                fluent::passes::attr_crate_level,
+                fluent::passes_attr_crate_level,
                 |err| {
                     if attr.style == AttrStyle::Outer
                         && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
@@ -882,15 +882,15 @@ impl CheckAttrVisitor<'_> {
                             src.insert(1, '!');
                             err.span_suggestion_verbose(
                                 attr.span,
-                                fluent::passes::suggestion,
+                                fluent::suggestion,
                                 src,
                                 Applicability::MaybeIncorrect,
                             );
                         } else {
-                            err.span_help(attr.span, fluent::passes::help);
+                            err.span_help(attr.span, fluent::help);
                         }
                     }
-                    err.note(fluent::passes::note);
+                    err.note(fluent::note);
                     err
                 },
             );
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index ed548341344..adaaf539242 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -13,37 +13,37 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
 use crate::lang_items::Duplicate;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::outer_crate_level_attr)]
+#[diag(passes_outer_crate_level_attr)]
 pub struct OuterCrateLevelAttr;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::inner_crate_level_attr)]
+#[diag(passes_inner_crate_level_attr)]
 pub struct InnerCrateLevelAttr;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::ignored_attr_with_macro)]
+#[diag(passes_ignored_attr_with_macro)]
 pub struct IgnoredAttrWithMacro<'a> {
     pub sym: &'a str,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::ignored_attr)]
+#[diag(passes_ignored_attr)]
 pub struct IgnoredAttr<'a> {
     pub sym: &'a str,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::inline_ignored_function_prototype)]
+#[diag(passes_inline_ignored_function_prototype)]
 pub struct IgnoredInlineAttrFnProto;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::inline_ignored_constants)]
+#[diag(passes_inline_ignored_constants)]
 #[warning]
 #[note]
 pub struct IgnoredInlineAttrConstants;
 
 #[derive(Diagnostic)]
-#[diag(passes::inline_not_fn_or_closure, code = "E0518")]
+#[diag(passes_inline_not_fn_or_closure, code = "E0518")]
 pub struct InlineNotFnOrClosure {
     #[primary_span]
     pub attr_span: Span,
@@ -52,19 +52,19 @@ pub struct InlineNotFnOrClosure {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_ignored_function_prototype)]
+#[diag(passes_no_coverage_ignored_function_prototype)]
 pub struct IgnoredNoCoverageFnProto;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_propagate)]
+#[diag(passes_no_coverage_propagate)]
 pub struct IgnoredNoCoveragePropagate;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_fn_defn)]
+#[diag(passes_no_coverage_fn_defn)]
 pub struct IgnoredNoCoverageFnDefn;
 
 #[derive(Diagnostic)]
-#[diag(passes::no_coverage_not_coverable, code = "E0788")]
+#[diag(passes_no_coverage_not_coverable, code = "E0788")]
 pub struct IgnoredNoCoverageNotCoverable {
     #[primary_span]
     pub attr_span: Span,
@@ -73,7 +73,7 @@ pub struct IgnoredNoCoverageNotCoverable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_fn)]
+#[diag(passes_should_be_applied_to_fn)]
 pub struct AttrShouldBeAppliedToFn {
     #[primary_span]
     pub attr_span: Span,
@@ -82,14 +82,14 @@ pub struct AttrShouldBeAppliedToFn {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_tracked_caller, code = "E0736")]
+#[diag(passes_naked_tracked_caller, code = "E0736")]
 pub struct NakedTrackedCaller {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_fn, code = "E0739")]
+#[diag(passes_should_be_applied_to_fn, code = "E0739")]
 pub struct TrackedCallerWrongLocation {
     #[primary_span]
     pub attr_span: Span,
@@ -98,7 +98,7 @@ pub struct TrackedCallerWrongLocation {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_struct_enum, code = "E0701")]
+#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")]
 pub struct NonExhaustiveWrongLocation {
     #[primary_span]
     pub attr_span: Span,
@@ -107,7 +107,7 @@ pub struct NonExhaustiveWrongLocation {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_trait)]
+#[diag(passes_should_be_applied_to_trait)]
 pub struct AttrShouldBeAppliedToTrait {
     #[primary_span]
     pub attr_span: Span,
@@ -116,11 +116,11 @@ pub struct AttrShouldBeAppliedToTrait {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::target_feature_on_statement)]
+#[diag(passes_target_feature_on_statement)]
 pub struct TargetFeatureOnStatement;
 
 #[derive(Diagnostic)]
-#[diag(passes::should_be_applied_to_static)]
+#[diag(passes_should_be_applied_to_static)]
 pub struct AttrShouldBeAppliedToStatic {
     #[primary_span]
     pub attr_span: Span,
@@ -129,7 +129,7 @@ pub struct AttrShouldBeAppliedToStatic {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_expect_str)]
+#[diag(passes_doc_expect_str)]
 pub struct DocExpectStr<'a> {
     #[primary_span]
     pub attr_span: Span,
@@ -137,7 +137,7 @@ pub struct DocExpectStr<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_empty)]
+#[diag(passes_doc_alias_empty)]
 pub struct DocAliasEmpty<'a> {
     #[primary_span]
     pub span: Span,
@@ -145,7 +145,7 @@ pub struct DocAliasEmpty<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_bad_char)]
+#[diag(passes_doc_alias_bad_char)]
 pub struct DocAliasBadChar<'a> {
     #[primary_span]
     pub span: Span,
@@ -154,7 +154,7 @@ pub struct DocAliasBadChar<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_start_end)]
+#[diag(passes_doc_alias_start_end)]
 pub struct DocAliasStartEnd<'a> {
     #[primary_span]
     pub span: Span,
@@ -162,7 +162,7 @@ pub struct DocAliasStartEnd<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_bad_location)]
+#[diag(passes_doc_alias_bad_location)]
 pub struct DocAliasBadLocation<'a> {
     #[primary_span]
     pub span: Span,
@@ -171,7 +171,7 @@ pub struct DocAliasBadLocation<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_not_an_alias)]
+#[diag(passes_doc_alias_not_an_alias)]
 pub struct DocAliasNotAnAlias<'a> {
     #[primary_span]
     pub span: Span,
@@ -179,42 +179,42 @@ pub struct DocAliasNotAnAlias<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_alias_duplicated)]
+#[diag(passes_doc_alias_duplicated)]
 pub struct DocAliasDuplicated {
     #[label]
     pub first_defn: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_not_string_literal)]
+#[diag(passes_doc_alias_not_string_literal)]
 pub struct DocAliasNotStringLiteral {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_alias_malformed)]
+#[diag(passes_doc_alias_malformed)]
 pub struct DocAliasMalformed {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_empty_mod)]
+#[diag(passes_doc_keyword_empty_mod)]
 pub struct DocKeywordEmptyMod {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_not_mod)]
+#[diag(passes_doc_keyword_not_mod)]
 pub struct DocKeywordNotMod {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_invalid_ident)]
+#[diag(passes_doc_keyword_invalid_ident)]
 pub struct DocKeywordInvalidIdent {
     #[primary_span]
     pub span: Span,
@@ -222,21 +222,21 @@ pub struct DocKeywordInvalidIdent {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_fake_variadic_not_valid)]
+#[diag(passes_doc_fake_variadic_not_valid)]
 pub struct DocFakeVariadicNotValid {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_keyword_only_impl)]
+#[diag(passes_doc_keyword_only_impl)]
 pub struct DocKeywordOnlyImpl {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_inline_conflict)]
+#[diag(passes_doc_inline_conflict)]
 #[help]
 pub struct DocKeywordConflict {
     #[primary_span]
@@ -244,17 +244,17 @@ pub struct DocKeywordConflict {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_inline_only_use)]
+#[diag(passes_doc_inline_only_use)]
 #[note]
 pub struct DocInlineOnlyUse {
     #[label]
     pub attr_span: Span,
-    #[label(passes::not_a_use_item_label)]
+    #[label(not_a_use_item_label)]
     pub item_span: Option<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::doc_attr_not_crate_level)]
+#[diag(passes_doc_attr_not_crate_level)]
 pub struct DocAttrNotCrateLevel<'a> {
     #[primary_span]
     pub span: Span,
@@ -262,33 +262,33 @@ pub struct DocAttrNotCrateLevel<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown)]
+#[diag(passes_doc_test_unknown)]
 pub struct DocTestUnknown {
     pub path: String,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_takes_list)]
+#[diag(passes_doc_test_takes_list)]
 pub struct DocTestTakesList;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_cfg_hide_takes_list)]
+#[diag(passes_doc_cfg_hide_takes_list)]
 pub struct DocCfgHideTakesList;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_primitive)]
+#[diag(passes_doc_primitive)]
 pub struct DocPrimitive;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_any)]
+#[diag(passes_doc_test_unknown_any)]
 pub struct DocTestUnknownAny {
     pub path: String,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_spotlight)]
+#[diag(passes_doc_test_unknown_spotlight)]
 #[note]
-#[note(passes::no_op_note)]
+#[note(no_op_note)]
 pub struct DocTestUnknownSpotlight {
     pub path: String,
     #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")]
@@ -296,7 +296,7 @@ pub struct DocTestUnknownSpotlight {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_include)]
+#[diag(passes_doc_test_unknown_include)]
 pub struct DocTestUnknownInclude {
     pub path: String,
     pub value: String,
@@ -306,11 +306,11 @@ pub struct DocTestUnknownInclude {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::doc_invalid)]
+#[diag(passes_doc_invalid)]
 pub struct DocInvalid;
 
 #[derive(Diagnostic)]
-#[diag(passes::pass_by_value)]
+#[diag(passes_pass_by_value)]
 pub struct PassByValue {
     #[primary_span]
     pub attr_span: Span,
@@ -319,7 +319,7 @@ pub struct PassByValue {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::allow_incoherent_impl)]
+#[diag(passes_allow_incoherent_impl)]
 pub struct AllowIncoherentImpl {
     #[primary_span]
     pub attr_span: Span,
@@ -328,7 +328,7 @@ pub struct AllowIncoherentImpl {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::has_incoherent_inherent_impl)]
+#[diag(passes_has_incoherent_inherent_impl)]
 pub struct HasIncoherentInherentImpl {
     #[primary_span]
     pub attr_span: Span,
@@ -337,21 +337,21 @@ pub struct HasIncoherentInherentImpl {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::must_use_async)]
+#[diag(passes_must_use_async)]
 pub struct MustUseAsync {
     #[label]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::must_use_no_effect)]
+#[diag(passes_must_use_no_effect)]
 pub struct MustUseNoEffect {
     pub article: &'static str,
     pub target: rustc_hir::Target,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::must_not_suspend)]
+#[diag(passes_must_not_suspend)]
 pub struct MustNotSuspend {
     #[primary_span]
     pub attr_span: Span,
@@ -360,7 +360,7 @@ pub struct MustNotSuspend {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::cold)]
+#[diag(passes_cold)]
 #[warning]
 pub struct Cold {
     #[label]
@@ -368,7 +368,7 @@ pub struct Cold {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::link)]
+#[diag(passes_link)]
 #[warning]
 pub struct Link {
     #[label]
@@ -376,7 +376,7 @@ pub struct Link {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::link_name)]
+#[diag(passes_link_name)]
 #[warning]
 pub struct LinkName<'a> {
     #[help]
@@ -387,7 +387,7 @@ pub struct LinkName<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::no_link)]
+#[diag(passes_no_link)]
 pub struct NoLink {
     #[primary_span]
     pub attr_span: Span,
@@ -396,7 +396,7 @@ pub struct NoLink {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::export_name)]
+#[diag(passes_export_name)]
 pub struct ExportName {
     #[primary_span]
     pub attr_span: Span,
@@ -405,7 +405,7 @@ pub struct ExportName {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_layout_scalar_valid_range_not_struct)]
+#[diag(passes_rustc_layout_scalar_valid_range_not_struct)]
 pub struct RustcLayoutScalarValidRangeNotStruct {
     #[primary_span]
     pub attr_span: Span,
@@ -414,14 +414,14 @@ pub struct RustcLayoutScalarValidRangeNotStruct {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_layout_scalar_valid_range_arg)]
+#[diag(passes_rustc_layout_scalar_valid_range_arg)]
 pub struct RustcLayoutScalarValidRangeArg {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_only)]
+#[diag(passes_rustc_legacy_const_generics_only)]
 pub struct RustcLegacyConstGenericsOnly {
     #[primary_span]
     pub attr_span: Span,
@@ -430,7 +430,7 @@ pub struct RustcLegacyConstGenericsOnly {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index)]
+#[diag(passes_rustc_legacy_const_generics_index)]
 pub struct RustcLegacyConstGenericsIndex {
     #[primary_span]
     pub attr_span: Span,
@@ -439,7 +439,7 @@ pub struct RustcLegacyConstGenericsIndex {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index_exceed)]
+#[diag(passes_rustc_legacy_const_generics_index_exceed)]
 pub struct RustcLegacyConstGenericsIndexExceed {
     #[primary_span]
     #[label]
@@ -448,21 +448,21 @@ pub struct RustcLegacyConstGenericsIndexExceed {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index_negative)]
+#[diag(passes_rustc_legacy_const_generics_index_negative)]
 pub struct RustcLegacyConstGenericsIndexNegative {
     #[primary_span]
     pub invalid_args: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_dirty_clean)]
+#[diag(passes_rustc_dirty_clean)]
 pub struct RustcDirtyClean {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::link_section)]
+#[diag(passes_link_section)]
 #[warning]
 pub struct LinkSection {
     #[label]
@@ -470,7 +470,7 @@ pub struct LinkSection {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_mangle_foreign)]
+#[diag(passes_no_mangle_foreign)]
 #[warning]
 #[note]
 pub struct NoMangleForeign {
@@ -482,7 +482,7 @@ pub struct NoMangleForeign {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::no_mangle)]
+#[diag(passes_no_mangle)]
 #[warning]
 pub struct NoMangle {
     #[label]
@@ -490,32 +490,32 @@ pub struct NoMangle {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::repr_ident, code = "E0565")]
+#[diag(passes_repr_ident, code = "E0565")]
 pub struct ReprIdent {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::repr_conflicting, code = "E0566")]
+#[diag(passes_repr_conflicting, code = "E0566")]
 pub struct ReprConflicting;
 
 #[derive(Diagnostic)]
-#[diag(passes::used_static)]
+#[diag(passes_used_static)]
 pub struct UsedStatic {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::used_compiler_linker)]
+#[diag(passes_used_compiler_linker)]
 pub struct UsedCompilerLinker {
     #[primary_span]
     pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::allow_internal_unstable)]
+#[diag(passes_allow_internal_unstable)]
 pub struct AllowInternalUnstable {
     #[primary_span]
     pub attr_span: Span,
@@ -524,24 +524,24 @@ pub struct AllowInternalUnstable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::debug_visualizer_placement)]
+#[diag(passes_debug_visualizer_placement)]
 pub struct DebugVisualizerPlacement {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::debug_visualizer_invalid)]
-#[note(passes::note_1)]
-#[note(passes::note_2)]
-#[note(passes::note_3)]
+#[diag(passes_debug_visualizer_invalid)]
+#[note(note_1)]
+#[note(note_2)]
+#[note(note_3)]
 pub struct DebugVisualizerInvalid {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::debug_visualizer_unreadable)]
+#[diag(passes_debug_visualizer_unreadable)]
 pub struct DebugVisualizerUnreadable<'a> {
     #[primary_span]
     pub span: Span,
@@ -550,7 +550,7 @@ pub struct DebugVisualizerUnreadable<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_allow_const_fn_unstable)]
+#[diag(passes_rustc_allow_const_fn_unstable)]
 pub struct RustcAllowConstFnUnstable {
     #[primary_span]
     pub attr_span: Span,
@@ -559,7 +559,7 @@ pub struct RustcAllowConstFnUnstable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_std_internal_symbol)]
+#[diag(passes_rustc_std_internal_symbol)]
 pub struct RustcStdInternalSymbol {
     #[primary_span]
     pub attr_span: Span,
@@ -568,56 +568,56 @@ pub struct RustcStdInternalSymbol {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::const_trait)]
+#[diag(passes_const_trait)]
 pub struct ConstTrait {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::link_ordinal)]
+#[diag(passes_link_ordinal)]
 pub struct LinkOrdinal {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::stability_promotable)]
+#[diag(passes_stability_promotable)]
 pub struct StabilityPromotable {
     #[primary_span]
     pub attr_span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::deprecated)]
+#[diag(passes_deprecated)]
 pub struct Deprecated;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::macro_use)]
+#[diag(passes_macro_use)]
 pub struct MacroUse {
     pub name: Symbol,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::macro_export)]
+#[diag(passes_macro_export)]
 pub struct MacroExport;
 
 #[derive(LintDiagnostic)]
-#[diag(passes::plugin_registrar)]
+#[diag(passes_plugin_registrar)]
 pub struct PluginRegistrar;
 
 #[derive(Subdiagnostic)]
 pub enum UnusedNote {
-    #[note(passes::unused_empty_lints_note)]
+    #[note(passes_unused_empty_lints_note)]
     EmptyList { name: Symbol },
-    #[note(passes::unused_no_lints_note)]
+    #[note(passes_unused_no_lints_note)]
     NoLints { name: Symbol },
-    #[note(passes::unused_default_method_body_const_note)]
+    #[note(passes_unused_default_method_body_const_note)]
     DefaultMethodBodyConst,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::unused)]
+#[diag(passes_unused)]
 pub struct Unused {
     #[suggestion(code = "", applicability = "machine-applicable")]
     pub attr_span: Span,
@@ -626,7 +626,7 @@ pub struct Unused {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::non_exported_macro_invalid_attrs, code = "E0518")]
+#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")]
 pub struct NonExportedMacroInvalidAttrs {
     #[primary_span]
     #[label]
@@ -634,7 +634,7 @@ pub struct NonExportedMacroInvalidAttrs {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::unused_duplicate)]
+#[diag(passes_unused_duplicate)]
 pub struct UnusedDuplicate {
     #[suggestion(code = "", applicability = "machine-applicable")]
     pub this: Span,
@@ -645,7 +645,7 @@ pub struct UnusedDuplicate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unused_multiple)]
+#[diag(passes_unused_multiple)]
 pub struct UnusedMultiple {
     #[primary_span]
     #[suggestion(code = "", applicability = "machine-applicable")]
@@ -656,7 +656,7 @@ pub struct UnusedMultiple {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_lint_opt_ty)]
+#[diag(passes_rustc_lint_opt_ty)]
 pub struct RustcLintOptTy {
     #[primary_span]
     pub attr_span: Span,
@@ -665,7 +665,7 @@ pub struct RustcLintOptTy {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::rustc_lint_opt_deny_field_access)]
+#[diag(passes_rustc_lint_opt_deny_field_access)]
 pub struct RustcLintOptDenyFieldAccess {
     #[primary_span]
     pub attr_span: Span,
@@ -674,7 +674,7 @@ pub struct RustcLintOptDenyFieldAccess {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::collapse_debuginfo)]
+#[diag(passes_collapse_debuginfo)]
 pub struct CollapseDebuginfo {
     #[primary_span]
     pub attr_span: Span,
@@ -683,14 +683,14 @@ pub struct CollapseDebuginfo {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::deprecated_annotation_has_no_effect)]
+#[diag(passes_deprecated_annotation_has_no_effect)]
 pub struct DeprecatedAnnotationHasNoEffect {
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unknown_external_lang_item, code = "E0264")]
+#[diag(passes_unknown_external_lang_item, code = "E0264")]
 pub struct UnknownExternLangItem {
     #[primary_span]
     pub span: Span,
@@ -698,19 +698,19 @@ pub struct UnknownExternLangItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_panic_handler)]
+#[diag(passes_missing_panic_handler)]
 pub struct MissingPanicHandler;
 
 #[derive(Diagnostic)]
-#[diag(passes::alloc_func_required)]
+#[diag(passes_alloc_func_required)]
 pub struct AllocFuncRequired;
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_alloc_error_handler)]
+#[diag(passes_missing_alloc_error_handler)]
 pub struct MissingAllocErrorHandler;
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_lang_item)]
+#[diag(passes_missing_lang_item)]
 #[note]
 #[help]
 pub struct MissingLangItem {
@@ -718,7 +718,7 @@ pub struct MissingLangItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::lang_item_on_incorrect_target, code = "E0718")]
+#[diag(passes_lang_item_on_incorrect_target, code = "E0718")]
 pub struct LangItemOnIncorrectTarget {
     #[primary_span]
     #[label]
@@ -729,7 +729,7 @@ pub struct LangItemOnIncorrectTarget {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unknown_lang_item, code = "E0522")]
+#[diag(passes_unknown_lang_item, code = "E0522")]
 pub struct UnknownLangItem {
     #[primary_span]
     #[label]
@@ -748,8 +748,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag =
-            handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level);
+        let mut diag = handler.struct_err(rustc_errors::fluent::passes_invalid_attr_at_crate_level);
         diag.set_span(self.span);
         diag.set_arg("name", self.name);
         // Only emit an error with a suggestion if we can create a string out
@@ -758,7 +757,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
             let replacement = src.replace("#!", "#");
             diag.span_suggestion_verbose(
                 self.span,
-                rustc_errors::fluent::passes::suggestion,
+                rustc_errors::fluent::suggestion,
                 replacement,
                 rustc_errors::Applicability::MachineApplicable,
             );
@@ -768,7 +767,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::duplicate_diagnostic_item)]
+#[diag(passes_duplicate_diagnostic_item)]
 pub struct DuplicateDiagnosticItem {
     #[primary_span]
     pub span: Span,
@@ -776,9 +775,9 @@ pub struct DuplicateDiagnosticItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::duplicate_diagnostic_item_in_crate)]
+#[diag(passes_duplicate_diagnostic_item_in_crate)]
 pub struct DuplicateDiagnosticItemInCrate {
-    #[note(passes::diagnostic_item_first_defined)]
+    #[note(passes_diagnostic_item_first_defined)]
     pub span: Option<Span>,
     pub orig_crate_name: Symbol,
     #[note]
@@ -788,7 +787,7 @@ pub struct DuplicateDiagnosticItemInCrate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::abi)]
+#[diag(passes_abi)]
 pub struct Abi {
     #[primary_span]
     pub span: Span,
@@ -796,7 +795,7 @@ pub struct Abi {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::align)]
+#[diag(passes_align)]
 pub struct Align {
     #[primary_span]
     pub span: Span,
@@ -804,7 +803,7 @@ pub struct Align {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::size)]
+#[diag(passes_size)]
 pub struct Size {
     #[primary_span]
     pub span: Span,
@@ -812,7 +811,7 @@ pub struct Size {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::homogeneous_aggregate)]
+#[diag(passes_homogeneous_aggregate)]
 pub struct HomogeneousAggregate {
     #[primary_span]
     pub span: Span,
@@ -820,7 +819,7 @@ pub struct HomogeneousAggregate {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::layout_of)]
+#[diag(passes_layout_of)]
 pub struct LayoutOf {
     #[primary_span]
     pub span: Span,
@@ -829,7 +828,7 @@ pub struct LayoutOf {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unrecognized_field)]
+#[diag(passes_unrecognized_field)]
 pub struct UnrecognizedField {
     #[primary_span]
     pub span: Span,
@@ -837,7 +836,7 @@ pub struct UnrecognizedField {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::feature_stable_twice, code = "E0711")]
+#[diag(passes_feature_stable_twice, code = "E0711")]
 pub struct FeatureStableTwice {
     #[primary_span]
     pub span: Span,
@@ -847,7 +846,7 @@ pub struct FeatureStableTwice {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::feature_previously_declared, code = "E0711")]
+#[diag(passes_feature_previously_declared, code = "E0711")]
 pub struct FeaturePreviouslyDeclared<'a, 'b> {
     #[primary_span]
     pub span: Span,
@@ -857,7 +856,7 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::expr_not_allowed_in_context, code = "E0744")]
+#[diag(passes_expr_not_allowed_in_context, code = "E0744")]
 pub struct ExprNotAllowedInContext<'a> {
     #[primary_span]
     pub span: Span,
@@ -883,17 +882,17 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::passes::break_non_loop,
+            rustc_errors::fluent::passes_break_non_loop,
             error_code!(E0571),
         );
         diag.set_arg("kind", self.kind);
-        diag.span_label(self.span, rustc_errors::fluent::passes::label);
+        diag.span_label(self.span, rustc_errors::fluent::label);
         if let Some(head) = self.head {
-            diag.span_label(head, rustc_errors::fluent::passes::label2);
+            diag.span_label(head, rustc_errors::fluent::label2);
         }
         diag.span_suggestion(
             self.span,
-            rustc_errors::fluent::passes::suggestion,
+            rustc_errors::fluent::suggestion,
             self.suggestion,
             Applicability::MaybeIncorrect,
         );
@@ -911,7 +910,7 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
                 _ => {
                     diag.span_suggestion(
                         self.break_expr_span,
-                        rustc_errors::fluent::passes::break_expr_suggestion,
+                        rustc_errors::fluent::break_expr_suggestion,
                         label.ident,
                         Applicability::MaybeIncorrect,
                     );
@@ -923,39 +922,39 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::continue_labeled_block, code = "E0696")]
+#[diag(passes_continue_labeled_block, code = "E0696")]
 pub struct ContinueLabeledBlock {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::block_label)]
+    #[label(block_label)]
     pub block_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::break_inside_closure, code = "E0267")]
+#[diag(passes_break_inside_closure, code = "E0267")]
 pub struct BreakInsideClosure<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::closure_label)]
+    #[label(closure_label)]
     pub closure_span: Span,
     pub name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::break_inside_async_block, code = "E0267")]
+#[diag(passes_break_inside_async_block, code = "E0267")]
 pub struct BreakInsideAsyncBlock<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::async_block_label)]
+    #[label(async_block_label)]
     pub closure_span: Span,
     pub name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::outside_loop, code = "E0268")]
+#[diag(passes_outside_loop, code = "E0268")]
 pub struct OutsideLoop<'a> {
     #[primary_span]
     #[label]
@@ -964,7 +963,7 @@ pub struct OutsideLoop<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unlabeled_in_labeled_block, code = "E0695")]
+#[diag(passes_unlabeled_in_labeled_block, code = "E0695")]
 pub struct UnlabeledInLabeledBlock<'a> {
     #[primary_span]
     #[label]
@@ -973,7 +972,7 @@ pub struct UnlabeledInLabeledBlock<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unlabeled_cf_in_while_condition, code = "E0590")]
+#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")]
 pub struct UnlabeledCfInWhileCondition<'a> {
     #[primary_span]
     #[label]
@@ -982,25 +981,25 @@ pub struct UnlabeledCfInWhileCondition<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::cannot_inline_naked_function)]
+#[diag(passes_cannot_inline_naked_function)]
 pub struct CannotInlineNakedFunction {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::undefined_naked_function_abi)]
+#[diag(passes_undefined_naked_function_abi)]
 pub struct UndefinedNakedFunctionAbi;
 
 #[derive(Diagnostic)]
-#[diag(passes::no_patterns)]
+#[diag(passes_no_patterns)]
 pub struct NoPatterns {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::params_not_allowed)]
+#[diag(passes_params_not_allowed)]
 #[help]
 pub struct ParamsNotAllowed {
     #[primary_span]
@@ -1020,28 +1019,28 @@ impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::passes::naked_functions_asm_block,
+            rustc_errors::fluent::passes_naked_functions_asm_block,
             error_code!(E0787),
         );
         for span in self.multiple_asms.iter() {
-            diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm);
+            diag.span_label(*span, rustc_errors::fluent::label_multiple_asm);
         }
         for span in self.non_asms.iter() {
-            diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm);
+            diag.span_label(*span, rustc_errors::fluent::label_non_asm);
         }
         diag
     }
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_functions_operands, code = "E0787")]
+#[diag(passes_naked_functions_operands, code = "E0787")]
 pub struct NakedFunctionsOperands {
     #[primary_span]
     pub unsupported_operands: Vec<Span>,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_functions_asm_options, code = "E0787")]
+#[diag(passes_naked_functions_asm_options, code = "E0787")]
 pub struct NakedFunctionsAsmOptions {
     #[primary_span]
     pub span: Span,
@@ -1049,7 +1048,7 @@ pub struct NakedFunctionsAsmOptions {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")]
+#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")]
 pub struct NakedFunctionsMustUseNoreturn {
     #[primary_span]
     pub span: Span,
@@ -1058,7 +1057,7 @@ pub struct NakedFunctionsMustUseNoreturn {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::attr_only_on_main)]
+#[diag(passes_attr_only_on_main)]
 pub struct AttrOnlyOnMain {
     #[primary_span]
     pub span: Span,
@@ -1066,7 +1065,7 @@ pub struct AttrOnlyOnMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::attr_only_on_root_main)]
+#[diag(passes_attr_only_on_root_main)]
 pub struct AttrOnlyOnRootMain {
     #[primary_span]
     pub span: Span,
@@ -1074,7 +1073,7 @@ pub struct AttrOnlyOnRootMain {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::attr_only_in_functions)]
+#[diag(passes_attr_only_in_functions)]
 pub struct AttrOnlyInFunctions {
     #[primary_span]
     pub span: Span,
@@ -1082,43 +1081,43 @@ pub struct AttrOnlyInFunctions {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::multiple_rustc_main, code = "E0137")]
+#[diag(passes_multiple_rustc_main, code = "E0137")]
 pub struct MultipleRustcMain {
     #[primary_span]
     pub span: Span,
-    #[label(passes::first)]
+    #[label(first)]
     pub first: Span,
-    #[label(passes::additional)]
+    #[label(additional)]
     pub additional: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::multiple_start_functions, code = "E0138")]
+#[diag(passes_multiple_start_functions, code = "E0138")]
 pub struct MultipleStartFunctions {
     #[primary_span]
     pub span: Span,
     #[label]
     pub labeled: Span,
-    #[label(passes::previous)]
+    #[label(previous)]
     pub previous: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::extern_main)]
+#[diag(passes_extern_main)]
 pub struct ExternMain {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unix_sigpipe_values)]
+#[diag(passes_unix_sigpipe_values)]
 pub struct UnixSigpipeValues {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::no_main_function, code = "E0601")]
+#[diag(passes_no_main_function, code = "E0601")]
 pub struct NoMainFunction {
     #[primary_span]
     pub span: Span,
@@ -1143,7 +1142,7 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             DUMMY_SP,
-            rustc_errors::fluent::passes::no_main_function,
+            rustc_errors::fluent::passes_no_main_function,
             error_code!(E0601),
         );
         diag.set_arg("crate_name", self.crate_name);
@@ -1151,16 +1150,16 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
         diag.set_arg("has_filename", self.has_filename);
         let note = if !self.non_main_fns.is_empty() {
             for &span in &self.non_main_fns {
-                diag.span_note(span, rustc_errors::fluent::passes::here_is_main);
+                diag.span_note(span, rustc_errors::fluent::here_is_main);
             }
-            diag.note(rustc_errors::fluent::passes::one_or_more_possible_main);
-            diag.help(rustc_errors::fluent::passes::consider_moving_main);
+            diag.note(rustc_errors::fluent::one_or_more_possible_main);
+            diag.help(rustc_errors::fluent::consider_moving_main);
             // There were some functions named `main` though. Try to give the user a hint.
-            rustc_errors::fluent::passes::main_must_be_defined_at_crate
+            rustc_errors::fluent::main_must_be_defined_at_crate
         } else if self.has_filename {
-            rustc_errors::fluent::passes::consider_adding_main_to_file
+            rustc_errors::fluent::consider_adding_main_to_file
         } else {
-            rustc_errors::fluent::passes::consider_adding_main_at_crate
+            rustc_errors::fluent::consider_adding_main_at_crate
         };
         if self.file_empty {
             diag.note(note);
@@ -1171,11 +1170,11 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
 
         if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
             // There is something at `crate::main`, but it is not a function definition.
-            diag.span_label(main_def.span, rustc_errors::fluent::passes::non_function_main);
+            diag.span_label(main_def.span, rustc_errors::fluent::non_function_main);
         }
 
         if self.add_teach_note {
-            diag.note(rustc_errors::fluent::passes::teach_note);
+            diag.note(rustc_errors::fluent::teach_note);
         }
         diag
     }
@@ -1203,11 +1202,11 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_err_with_code(
             match self.duplicate {
-                Duplicate::Plain => rustc_errors::fluent::passes::duplicate_lang_item,
+                Duplicate::Plain => rustc_errors::fluent::passes_duplicate_lang_item,
 
-                Duplicate::Crate => rustc_errors::fluent::passes::duplicate_lang_item_crate,
+                Duplicate::Crate => rustc_errors::fluent::passes_duplicate_lang_item_crate,
                 Duplicate::CrateDepends => {
-                    rustc_errors::fluent::passes::duplicate_lang_item_crate_depends
+                    rustc_errors::fluent::passes_duplicate_lang_item_crate_depends
                 }
             },
             error_code!(E0152),
@@ -1223,24 +1222,24 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
             diag.set_span(span);
         }
         if let Some(span) = self.first_defined_span {
-            diag.span_note(span, rustc_errors::fluent::passes::first_defined_span);
+            diag.span_note(span, rustc_errors::fluent::first_defined_span);
         } else {
             if self.orig_dependency_of.is_empty() {
-                diag.note(rustc_errors::fluent::passes::first_defined_crate);
+                diag.note(rustc_errors::fluent::first_defined_crate);
             } else {
-                diag.note(rustc_errors::fluent::passes::first_defined_crate_depends);
+                diag.note(rustc_errors::fluent::first_defined_crate_depends);
             }
 
             if self.orig_is_local {
-                diag.note(rustc_errors::fluent::passes::first_definition_local);
+                diag.note(rustc_errors::fluent::first_definition_local);
             } else {
-                diag.note(rustc_errors::fluent::passes::first_definition_path);
+                diag.note(rustc_errors::fluent::first_definition_path);
             }
 
             if self.is_local {
-                diag.note(rustc_errors::fluent::passes::second_definition_local);
+                diag.note(rustc_errors::fluent::second_definition_local);
             } else {
-                diag.note(rustc_errors::fluent::passes::second_definition_path);
+                diag.note(rustc_errors::fluent::second_definition_path);
             }
         }
         diag
@@ -1248,7 +1247,7 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::incorrect_target, code = "E0718")]
+#[diag(passes_incorrect_target, code = "E0718")]
 pub struct IncorrectTarget<'a> {
     #[primary_span]
     pub span: Span,
@@ -1262,21 +1261,21 @@ pub struct IncorrectTarget<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::useless_assignment)]
+#[diag(passes_useless_assignment)]
 pub struct UselessAssignment<'a> {
     pub is_field_assign: bool,
     pub ty: Ty<'a>,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(passes::only_has_effect_on)]
+#[diag(passes_only_has_effect_on)]
 pub struct OnlyHasEffectOn {
     pub attr_name: Symbol,
     pub target_name: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::object_lifetime_err)]
+#[diag(passes_object_lifetime_err)]
 pub struct ObjectLifetimeErr {
     #[primary_span]
     pub span: Span,
@@ -1284,7 +1283,7 @@ pub struct ObjectLifetimeErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unrecognized_repr_hint, code = "E0552")]
+#[diag(passes_unrecognized_repr_hint, code = "E0552")]
 #[help]
 pub struct UnrecognizedReprHint {
     #[primary_span]
@@ -1293,35 +1292,35 @@ pub struct UnrecognizedReprHint {
 
 #[derive(Diagnostic)]
 pub enum AttrApplication {
-    #[diag(passes::attr_application_enum, code = "E0517")]
+    #[diag(passes_attr_application_enum, code = "E0517")]
     Enum {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct, code = "E0517")]
+    #[diag(passes_attr_application_struct, code = "E0517")]
     Struct {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct_union, code = "E0517")]
+    #[diag(passes_attr_application_struct_union, code = "E0517")]
     StructUnion {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct_enum_union, code = "E0517")]
+    #[diag(passes_attr_application_struct_enum_union, code = "E0517")]
     StructEnumUnion {
         #[primary_span]
         hint_span: Span,
         #[label]
         span: Span,
     },
-    #[diag(passes::attr_application_struct_enum_function_union, code = "E0517")]
+    #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")]
     StructEnumFunctionUnion {
         #[primary_span]
         hint_span: Span,
@@ -1331,7 +1330,7 @@ pub enum AttrApplication {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::transparent_incompatible, code = "E0692")]
+#[diag(passes_transparent_incompatible, code = "E0692")]
 pub struct TransparentIncompatible {
     #[primary_span]
     pub hint_spans: Vec<Span>,
@@ -1339,54 +1338,54 @@ pub struct TransparentIncompatible {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::deprecated_attribute, code = "E0549")]
+#[diag(passes_deprecated_attribute, code = "E0549")]
 pub struct DeprecatedAttribute {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::useless_stability)]
+#[diag(passes_useless_stability)]
 pub struct UselessStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::invalid_stability)]
+#[diag(passes_invalid_stability)]
 pub struct InvalidStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::cannot_stabilize_deprecated)]
+#[diag(passes_cannot_stabilize_deprecated)]
 pub struct CannotStabilizeDeprecated {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::invalid_deprecation_version)]
+#[diag(passes_invalid_deprecation_version)]
 pub struct InvalidDeprecationVersion {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes::item)]
+    #[label(item)]
     pub item_sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_stability_attr)]
+#[diag(passes_missing_stability_attr)]
 pub struct MissingStabilityAttr<'a> {
     #[primary_span]
     pub span: Span,
@@ -1394,7 +1393,7 @@ pub struct MissingStabilityAttr<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::missing_const_stab_attr)]
+#[diag(passes_missing_const_stab_attr)]
 pub struct MissingConstStabAttr<'a> {
     #[primary_span]
     pub span: Span,
@@ -1402,7 +1401,7 @@ pub struct MissingConstStabAttr<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::trait_impl_const_stable)]
+#[diag(passes_trait_impl_const_stable)]
 #[note]
 pub struct TraitImplConstStable {
     #[primary_span]
@@ -1410,7 +1409,7 @@ pub struct TraitImplConstStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::feature_only_on_nightly, code = "E0554")]
+#[diag(passes_feature_only_on_nightly, code = "E0554")]
 pub struct FeatureOnlyOnNightly {
     #[primary_span]
     pub span: Span,
@@ -1418,7 +1417,7 @@ pub struct FeatureOnlyOnNightly {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::unknown_feature, code = "E0635")]
+#[diag(passes_unknown_feature, code = "E0635")]
 pub struct UnknownFeature {
     #[primary_span]
     pub span: Span,
@@ -1426,7 +1425,7 @@ pub struct UnknownFeature {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::implied_feature_not_exist)]
+#[diag(passes_implied_feature_not_exist)]
 pub struct ImpliedFeatureNotExist {
     #[primary_span]
     pub span: Span,
@@ -1435,14 +1434,14 @@ pub struct ImpliedFeatureNotExist {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes::duplicate_feature_err, code = "E0636")]
+#[diag(passes_duplicate_feature_err, code = "E0636")]
 pub struct DuplicateFeatureErr {
     #[primary_span]
     pub span: Span,
     pub feature: Symbol,
 }
 #[derive(Diagnostic)]
-#[diag(passes::missing_const_err)]
+#[diag(passes_missing_const_err)]
 pub struct MissingConstErr {
     #[primary_span]
     #[help]
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index cfd6acd8d7c..9591aeb881f 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -891,8 +891,25 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
         if let TyKind::Never = t.kind {
             self.fully_stable = false;
         }
+        if let TyKind::BareFn(f) = t.kind {
+            if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() {
+                self.fully_stable = false;
+            }
+        }
         intravisit::walk_ty(self, t)
     }
+
+    fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
+        for ty in fd.inputs {
+            self.visit_ty(ty)
+        }
+        if let hir::FnRetTy::Return(output_ty) = fd.output {
+            match output_ty.kind {
+                TyKind::Never => {} // `-> !` is stable
+                _ => self.visit_ty(output_ty),
+            }
+        }
+    }
 }
 
 /// Given the list of enabled features that were not language features (i.e., that
diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs
index 07ce92a9b26..e6a7fc86bee 100644
--- a/compiler/rustc_plugin_impl/src/errors.rs
+++ b/compiler/rustc_plugin_impl/src/errors.rs
@@ -4,7 +4,7 @@ use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(plugin_impl::load_plugin_error)]
+#[diag(plugin_impl_load_plugin_error)]
 pub struct LoadPluginError {
     #[primary_span]
     pub span: Span,
@@ -12,7 +12,7 @@ pub struct LoadPluginError {
 }
 
 #[derive(Diagnostic)]
-#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")]
+#[diag(plugin_impl_malformed_plugin_attribute, code = "E0498")]
 pub struct MalformedPluginAttribute {
     #[primary_span]
     #[label]
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index f3a617c2f0f..a6c95f1a815 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -3,7 +3,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(privacy::field_is_private, code = "E0451")]
+#[diag(privacy_field_is_private, code = "E0451")]
 pub struct FieldIsPrivate {
     #[primary_span]
     pub span: Span,
@@ -16,13 +16,13 @@ pub struct FieldIsPrivate {
 
 #[derive(Subdiagnostic)]
 pub enum FieldIsPrivateLabel {
-    #[label(privacy::field_is_private_is_update_syntax_label)]
+    #[label(privacy_field_is_private_is_update_syntax_label)]
     IsUpdateSyntax {
         #[primary_span]
         span: Span,
         field_name: Symbol,
     },
-    #[label(privacy::field_is_private_label)]
+    #[label(privacy_field_is_private_label)]
     Other {
         #[primary_span]
         span: Span,
@@ -30,7 +30,7 @@ pub enum FieldIsPrivateLabel {
 }
 
 #[derive(Diagnostic)]
-#[diag(privacy::item_is_private)]
+#[diag(privacy_item_is_private)]
 pub struct ItemIsPrivate<'a> {
     #[primary_span]
     #[label]
@@ -40,7 +40,7 @@ pub struct ItemIsPrivate<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(privacy::unnamed_item_is_private)]
+#[diag(privacy_unnamed_item_is_private)]
 pub struct UnnamedItemIsPrivate {
     #[primary_span]
     pub span: Span,
@@ -49,7 +49,7 @@ pub struct UnnamedItemIsPrivate {
 
 // Duplicate of `InPublicInterface` but with a different error code, shares the same slug.
 #[derive(Diagnostic)]
-#[diag(privacy::in_public_interface, code = "E0445")]
+#[diag(privacy_in_public_interface, code = "E0445")]
 pub struct InPublicInterfaceTraits<'a> {
     #[primary_span]
     #[label]
@@ -57,13 +57,13 @@ pub struct InPublicInterfaceTraits<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
-    #[label(privacy::visibility_label)]
+    #[label(visibility_label)]
     pub vis_span: Span,
 }
 
 // Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug.
 #[derive(Diagnostic)]
-#[diag(privacy::in_public_interface, code = "E0446")]
+#[diag(privacy_in_public_interface, code = "E0446")]
 pub struct InPublicInterface<'a> {
     #[primary_span]
     #[label]
@@ -71,12 +71,12 @@ pub struct InPublicInterface<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
-    #[label(privacy::visibility_label)]
+    #[label(visibility_label)]
     pub vis_span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(privacy::report_effective_visibility)]
+#[diag(privacy_report_effective_visibility)]
 pub struct ReportEffectiveVisibility {
     #[primary_span]
     pub span: Span,
@@ -84,7 +84,7 @@ pub struct ReportEffectiveVisibility {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(privacy::from_private_dep_in_public_interface)]
+#[diag(privacy_from_private_dep_in_public_interface)]
 pub struct FromPrivateDependencyInPublicInterface<'a> {
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
@@ -92,7 +92,7 @@ pub struct FromPrivateDependencyInPublicInterface<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(privacy::private_in_public_lint)]
+#[diag(privacy_private_in_public_lint)]
 pub struct PrivateInPublicLint<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e904fab4d76..2636db6dbe1 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -159,34 +159,12 @@ where
                 ty.visit_with(self)
             }
             ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
-            ty::PredicateKind::ConstEvaluatable(uv)
-                if self.def_id_visitor.tcx().features().generic_const_exprs =>
-            {
-                let tcx = self.def_id_visitor.tcx();
-                if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
-                    self.visit_abstract_const_expr(tcx, ct)?;
-                }
-                ControlFlow::CONTINUE
-            }
+            ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
             ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
             _ => bug!("unexpected predicate: {:?}", predicate),
         }
     }
 
-    fn visit_abstract_const_expr(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        ct: AbstractConst<'tcx>,
-    ) -> ControlFlow<V::BreakTy> {
-        walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
-            ACNode::Leaf(leaf) => self.visit_const(leaf),
-            ACNode::Cast(_, _, ty) => self.visit_ty(ty),
-            ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
-                ControlFlow::CONTINUE
-            }
-        })
-    }
-
     fn visit_predicates(
         &mut self,
         predicates: ty::GenericPredicates<'tcx>,
@@ -309,9 +287,16 @@ where
         self.visit_ty(c.ty())?;
         let tcx = self.def_id_visitor.tcx();
         if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
-            self.visit_abstract_const_expr(tcx, ct)?;
+            walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+                ACNode::Leaf(leaf) => self.visit_const(leaf),
+                ACNode::Cast(_, _, ty) => self.visit_ty(ty),
+                ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
+                    ControlFlow::CONTINUE
+                }
+            })
+        } else {
+            ControlFlow::CONTINUE
         }
-        ControlFlow::CONTINUE
     }
 }
 
@@ -444,7 +429,11 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         let old_level = self.get(def_id);
         // Accessibility levels can only grow.
         if level > old_level {
-            self.access_levels.set_access_level(def_id, level.unwrap());
+            self.access_levels.set_access_level(
+                def_id,
+                || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
+                level.unwrap(),
+            );
             self.changed = true;
             level
         } else {
@@ -932,31 +921,30 @@ pub struct TestReachabilityVisitor<'tcx, 'a> {
 
 impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
     fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
-        let span = self.tcx.def_span(def_id.to_def_id());
         if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
-            let mut error_msg = String::new();
-
-            let effective_vis =
-                self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default();
-            for level in [
-                AccessLevel::Public,
-                AccessLevel::Exported,
-                AccessLevel::Reachable,
-                AccessLevel::ReachableFromImplTrait,
-            ] {
-                let vis_str = match effective_vis.get(level) {
-                    Some(ty::Visibility::Restricted(restricted_id)) => {
-                        format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
+            if let Some(effective_vis) = self.access_levels.get_effective_vis(def_id) {
+                let mut error_msg = String::new();
+                let span = self.tcx.def_span(def_id.to_def_id());
+                for level in AccessLevel::all_levels() {
+                    let vis_str = match effective_vis.get(level) {
+                        ty::Visibility::Restricted(restricted_id) => {
+                            if restricted_id.is_top_level_module() {
+                                "pub(crate)".to_string()
+                            } else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) {
+                                "pub(self)".to_string()
+                            } else {
+                                format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
+                            }
+                        }
+                        ty::Visibility::Public => "pub".to_string(),
+                    };
+                    if level != AccessLevel::Public {
+                        error_msg.push_str(", ");
                     }
-                    Some(ty::Visibility::Public) => "pub".to_string(),
-                    None => "pub(self)".to_string(),
-                };
-                if level != AccessLevel::Public {
-                    error_msg.push_str(", ");
+                    error_msg.push_str(&format!("{:?}: {}", level, vis_str));
                 }
-                error_msg.push_str(&format!("{:?}: {}", level, vis_str));
+                self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
             }
-            self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
         }
     }
 }
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index e96ea682cae..a5921650112 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -848,6 +848,7 @@ impl_ref_decoder! {<'tcx>
     rustc_span::def_id::DefId,
     rustc_span::def_id::LocalDefId,
     (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+    ty::DeducedParamAttrs,
 }
 
 //- ENCODING -------------------------------------------------------------------
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index 1e74e0e2990..7a20eaceba0 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -3,7 +3,7 @@ use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
 #[derive(Subdiagnostic)]
-#[note(query_system::cycle_stack_middle)]
+#[note(query_system_cycle_stack_middle)]
 pub struct CycleStack {
     #[primary_span]
     pub span: Span,
@@ -19,24 +19,24 @@ pub enum HandleCycleError {
 
 #[derive(Subdiagnostic)]
 pub enum StackCount {
-    #[note(query_system::cycle_stack_single)]
+    #[note(query_system_cycle_stack_single)]
     Single,
-    #[note(query_system::cycle_stack_multiple)]
+    #[note(query_system_cycle_stack_multiple)]
     Multiple,
 }
 
 #[derive(Subdiagnostic)]
 pub enum Alias {
-    #[note(query_system::cycle_recursive_ty_alias)]
-    #[help(query_system::cycle_recursive_ty_alias_help1)]
-    #[help(query_system::cycle_recursive_ty_alias_help2)]
+    #[note(query_system_cycle_recursive_ty_alias)]
+    #[help(query_system_cycle_recursive_ty_alias_help1)]
+    #[help(query_system_cycle_recursive_ty_alias_help2)]
     Ty,
-    #[note(query_system::cycle_recursive_trait_alias)]
+    #[note(query_system_cycle_recursive_trait_alias)]
     Trait,
 }
 
 #[derive(Subdiagnostic)]
-#[note(query_system::cycle_usage)]
+#[note(query_system_cycle_usage)]
 pub struct CycleUsage {
     #[primary_span]
     pub span: Span,
@@ -44,7 +44,7 @@ pub struct CycleUsage {
 }
 
 #[derive(Diagnostic)]
-#[diag(query_system::cycle, code = "E0391")]
+#[diag(query_system_cycle, code = "E0391")]
 pub struct Cycle {
     #[primary_span]
     pub span: Span,
@@ -60,14 +60,14 @@ pub struct Cycle {
 }
 
 #[derive(Diagnostic)]
-#[diag(query_system::reentrant)]
+#[diag(query_system_reentrant)]
 pub struct Reentrant;
 
 #[derive(Diagnostic)]
-#[diag(query_system::increment_compilation)]
+#[diag(query_system_increment_compilation)]
 #[help]
-#[note(query_system::increment_compilation_note1)]
-#[note(query_system::increment_compilation_note2)]
+#[note(query_system_increment_compilation_note1)]
+#[note(query_system_increment_compilation_note2)]
 pub struct IncrementCompilation {
     pub run_cmd: String,
     pub dep_node: String,
@@ -75,7 +75,7 @@ pub struct IncrementCompilation {
 
 #[derive(Diagnostic)]
 #[help]
-#[diag(query_system::query_overflow)]
+#[diag(query_system_query_overflow)]
 pub struct QueryOverflow {
     #[primary_span]
     pub span: Option<Span>,
@@ -86,7 +86,7 @@ pub struct QueryOverflow {
 }
 
 #[derive(Subdiagnostic)]
-#[note(query_system::layout_of_depth)]
+#[note(query_system_layout_of_depth)]
 pub struct LayoutOfDepth {
     pub desc: String,
     pub depth: usize,
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
index d806441716f..257784341e3 100644
--- a/compiler/rustc_resolve/src/access_levels.rs
+++ b/compiler/rustc_resolve/src/access_levels.rs
@@ -1,17 +1,13 @@
-use crate::NameBinding;
-use crate::NameBindingKind;
-use crate::Resolver;
+use crate::{ImportKind, NameBindingKind, Resolver};
 use rustc_ast::ast;
 use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
 use rustc_ast::Crate;
 use rustc_ast::EnumDef;
-use rustc_ast::NodeId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::DefIdTree;
-use rustc_span::sym;
+use rustc_middle::ty::{DefIdTree, Visibility};
 
 pub struct AccessLevelsVisitor<'r, 'a> {
     r: &'r mut Resolver<'a>,
@@ -25,7 +21,7 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
     pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
         let mut visitor = AccessLevelsVisitor { r, changed: false };
 
-        visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
+        visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, AccessLevel::Public);
         visitor.set_bindings_access_level(CRATE_DEF_ID);
 
         while visitor.changed {
@@ -45,67 +41,81 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
     /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
     fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
         assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
-        let module_level = self.r.access_levels.get_access_level(module_id);
-        if !module_level.is_some() {
-            return;
-        }
-        // Set the given binding access level to `AccessLevel::Public` and
-        // sets the rest of the `use` chain to `AccessLevel::Exported` until
-        // we hit the actual exported item.
-        let set_import_binding_access_level =
-            |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level, ns| {
-                while let NameBindingKind::Import { binding: nested_binding, import, .. } =
-                    binding.kind
-                {
-                    this.set_access_level(this.r.import_id_for_ns(import, ns), access_level);
-
-                    access_level = Some(AccessLevel::Exported);
-                    binding = nested_binding;
-                }
-            };
-
         let module = self.r.get_module(module_id.to_def_id()).unwrap();
         let resolutions = self.r.resolutions(module);
 
-        for (key, name_resolution) in resolutions.borrow().iter() {
-            if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() {
-                let access_level = match binding.is_import() {
-                    true => {
-                        set_import_binding_access_level(self, binding, module_level, key.ns);
-                        Some(AccessLevel::Exported)
-                    },
-                    false => module_level,
-                };
+        for (_, name_resolution) in resolutions.borrow().iter() {
+            if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
+                // Set the given binding access level to `AccessLevel::Public` and
+                // sets the rest of the `use` chain to `AccessLevel::Exported` until
+                // we hit the actual exported item.
+
+                // FIXME: tag and is_public() condition should be removed, but assertions occur.
+                let tag = if binding.is_import() { AccessLevel::Exported } else { AccessLevel::Public };
+                if binding.vis.is_public() {
+                    let mut prev_parent_id = module_id;
+                    let mut level = AccessLevel::Public;
+                    while let NameBindingKind::Import { binding: nested_binding, import, .. } =
+                        binding.kind
+                    {
+                        let mut update = |node_id| self.update(
+                            self.r.local_def_id(node_id),
+                            binding.vis.expect_local(),
+                            prev_parent_id,
+                            level,
+                        );
+                        // In theory all the import IDs have individual visibilities and effective
+                        // visibilities, but in practice these IDs go straigth to HIR where all
+                        // their few uses assume that their (effective) visibility applies to the
+                        // whole syntactic `use` item. So we update them all to the maximum value
+                        // among the potential individual effective visibilities. Maybe HIR for
+                        // imports shouldn't use three IDs at all.
+                        update(import.id);
+                        if let ImportKind::Single { additional_ids, .. } = import.kind {
+                            update(additional_ids.0);
+                            update(additional_ids.1);
+                        }
+
+                        level = AccessLevel::Exported;
+                        prev_parent_id = self.r.local_def_id(import.id);
+                        binding = nested_binding;
+                    }
+                }
+
                 if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
-                    self.set_access_level_def_id(def_id, access_level);
+                    self.update(def_id, binding.vis.expect_local(), module_id, tag);
                 }
             }
         }
     }
 
-    /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`.
-    /// This function will panic if the `NodeId` does not have a `LocalDefId`
-    fn set_access_level(
-        &mut self,
-        node_id: NodeId,
-        access_level: Option<AccessLevel>,
-    ) -> Option<AccessLevel> {
-        self.set_access_level_def_id(self.r.local_def_id(node_id), access_level)
-    }
-
-    fn set_access_level_def_id(
+    fn update(
         &mut self,
         def_id: LocalDefId,
-        access_level: Option<AccessLevel>,
-    ) -> Option<AccessLevel> {
-        let old_level = self.r.access_levels.get_access_level(def_id);
-        if old_level < access_level {
-            self.r.access_levels.set_access_level(def_id, access_level.unwrap());
-            self.changed = true;
-            access_level
+        nominal_vis: Visibility,
+        parent_id: LocalDefId,
+        tag: AccessLevel,
+    ) {
+        let mut access_levels = std::mem::take(&mut self.r.access_levels);
+        let module_id =
+            self.r.get_nearest_non_block_module(def_id.to_def_id()).def_id().expect_local();
+        let res = access_levels.update(
+            def_id,
+            nominal_vis,
+            || Visibility::Restricted(module_id),
+            parent_id,
+            tag,
+            &*self.r,
+        );
+        if let Ok(changed) = res {
+            self.changed |= changed;
         } else {
-            old_level
+            self.r.session.delay_span_bug(
+                self.r.opt_span(def_id.to_def_id()).unwrap(),
+                "Can't update effective visibility",
+            );
         }
+        self.r.access_levels = access_levels;
     }
 }
 
@@ -125,16 +135,15 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
 
             // Foreign modules inherit level from parents.
             ast::ItemKind::ForeignMod(..) => {
-                let parent_level =
-                    self.r.access_levels.get_access_level(self.r.local_parent(def_id));
-                self.set_access_level(item.id, parent_level);
+                let parent_id = self.r.local_parent(def_id);
+                self.update(def_id, Visibility::Public, parent_id, AccessLevel::Public);
             }
 
             // Only exported `macro_rules!` items are public, but they always are
             ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
-                if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) {
-                    self.set_access_level(item.id, Some(AccessLevel::Public));
-                }
+                let parent_id = self.r.local_parent(def_id);
+                let vis = self.r.visibilities[&def_id];
+                self.update(def_id, vis, parent_id, AccessLevel::Public);
             }
 
             ast::ItemKind::Mod(..) => {
@@ -146,19 +155,19 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
                 self.set_bindings_access_level(def_id);
                 for variant in variants {
                     let variant_def_id = self.r.local_def_id(variant.id);
-                    let variant_level = self.r.access_levels.get_access_level(variant_def_id);
                     for field in variant.data.fields() {
-                        self.set_access_level(field.id, variant_level);
+                        let field_def_id = self.r.local_def_id(field.id);
+                        let vis = self.r.visibilities[&field_def_id];
+                        self.update(field_def_id, vis, variant_def_id, AccessLevel::Public);
                     }
                 }
             }
 
             ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
-                let inherited_level = self.r.access_levels.get_access_level(def_id);
                 for field in def.fields() {
-                    if field.vis.kind.is_pub() {
-                        self.set_access_level(field.id, inherited_level);
-                    }
+                    let field_def_id = self.r.local_def_id(field.id);
+                    let vis = self.r.visibilities[&field_def_id];
+                    self.update(field_def_id, vis, def_id, AccessLevel::Public);
                 }
             }
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index c4644d4f076..5d868ebec94 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, SyntaxContext};
 
 use crate::imports::{Import, ImportKind, ImportResolver};
 use crate::late::{PatternSource, Rib};
@@ -47,6 +47,7 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
 /// similarly named label and whether or not it is reachable.
 pub(crate) type LabelSuggestion = (Ident, bool);
 
+#[derive(Debug)]
 pub(crate) enum SuggestionTarget {
     /// The target has a similar name as the name used by the programmer (probably a typo)
     SimilarlyNamed,
@@ -54,6 +55,7 @@ pub(crate) enum SuggestionTarget {
     SingleItem,
 }
 
+#[derive(Debug)]
 pub(crate) struct TypoSuggestion {
     pub candidate: Symbol,
     pub res: Res,
@@ -482,11 +484,12 @@ impl<'a> Resolver<'a> {
         module: Module<'a>,
         names: &mut Vec<TypoSuggestion>,
         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) {
+                if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
                     names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
                 }
             }
@@ -1181,10 +1184,10 @@ impl<'a> Resolver<'a> {
                 Scope::CrateRoot => {
                     let root_ident = Ident::new(kw::PathRoot, ident.span);
                     let root_module = this.resolve_crate_root(root_ident);
-                    this.add_module_candidates(root_module, &mut suggestions, filter_fn);
+                    this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
                 }
                 Scope::Module(module, _) => {
-                    this.add_module_candidates(module, &mut suggestions, filter_fn);
+                    this.add_module_candidates(module, &mut suggestions, filter_fn, None);
                 }
                 Scope::MacroUsePrelude => {
                     suggestions.extend(this.macro_use_prelude.iter().filter_map(
@@ -1221,7 +1224,7 @@ impl<'a> Resolver<'a> {
                 Scope::StdLibPrelude => {
                     if let Some(prelude) = this.prelude {
                         let mut tmp_suggestions = Vec::new();
-                        this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
+                        this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
                         suggestions.extend(
                             tmp_suggestions
                                 .into_iter()
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 9e2234ae4a5..f2cc50c199f 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -2,7 +2,7 @@
 
 use crate::diagnostics::{import_candidates, Suggestion};
 use crate::Determinacy::{self, *};
-use crate::Namespace::{self, *};
+use crate::Namespace::*;
 use crate::{module_to_string, names_to_string, ImportSuggestion};
 use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
 use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
@@ -252,7 +252,7 @@ impl<'a> Resolver<'a> {
         self.set_binding_parent_module(binding, module);
         self.update_resolution(module, key, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
-                if res == Res::Err {
+                if res == Res::Err && old_binding.res() != Res::Err {
                     // Do not override real bindings with `Res::Err`s from error recovery.
                     return Ok(());
                 }
@@ -371,31 +371,6 @@ impl<'a> Resolver<'a> {
             self.used_imports.insert(import.id);
         }
     }
-
-    /// Take primary and additional node IDs from an import and select one that corresponds to the
-    /// given namespace. The logic must match the corresponding logic from `fn lower_use_tree` that
-    /// assigns resolutons to IDs.
-    pub(crate) fn import_id_for_ns(&self, import: &Import<'_>, ns: Namespace) -> NodeId {
-        if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind {
-            if let Some(resolutions) = self.import_res_map.get(&import.id) {
-                assert!(resolutions[ns].is_some(), "incorrectly finalized import");
-                return match ns {
-                    TypeNS => import.id,
-                    ValueNS => match resolutions.type_ns {
-                        Some(_) => id1,
-                        None => import.id,
-                    },
-                    MacroNS => match (resolutions.type_ns, resolutions.value_ns) {
-                        (Some(_), Some(_)) => id2,
-                        (Some(_), None) | (None, Some(_)) => id1,
-                        (None, None) => import.id,
-                    },
-                };
-            }
-        }
-
-        import.id
-    }
 }
 
 /// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 77ba7a82672..58853346a92 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -524,6 +524,9 @@ struct DiagnosticMetadata<'ast> {
     /// Used to detect possible `if let` written without `let` and to provide structured suggestion.
     in_if_condition: Option<&'ast Expr>,
 
+    /// Used to detect possible new binding written without `let` and to provide structured suggestion.
+    in_assignment: Option<&'ast Expr>,
+
     /// If we are currently in a trait object definition. Used to point at the bounds when
     /// encountering a struct or enum.
     current_trait_object: Option<&'ast [ast::GenericBound]>,
@@ -1862,9 +1865,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
         for (index, (pat, ty)) in inputs.enumerate() {
             debug!(?pat, ?ty);
-            if let Some(pat) = pat {
-                self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
-            }
+            self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+                if let Some(pat) = pat {
+                    this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+                }
+            });
             self.visit_ty(ty);
 
             if let Some(ref candidates) = self.lifetime_elision_candidates {
@@ -1937,11 +1942,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 match ty.kind {
                     TyKind::ImplicitSelf => true,
                     TyKind::Path(None, _) => {
-                        let path_res = self.r.partial_res_map[&ty.id].expect_full_res();
-                        if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res {
+                        let path_res = self.r.partial_res_map[&ty.id].full_res();
+                        if let Some(Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }) = path_res {
                             return true;
                         }
-                        Some(path_res) == self.impl_self
+                        self.impl_self.is_some() && path_res == self.impl_self
                     }
                     _ => false,
                 }
@@ -2834,10 +2839,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
     fn resolve_params(&mut self, params: &'ast [Param]) {
         let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
-        for Param { pat, ty, .. } in params {
-            self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+        self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+            for Param { pat, .. } in params {
+                this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+            }
+        });
+        for Param { ty, .. } in params {
             self.visit_ty(ty);
-            debug!("(resolving function / closure) recorded parameter");
         }
     }
 
@@ -3900,6 +3908,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 self.resolve_expr(elem, Some(expr));
                 self.visit_expr(idx);
             }
+            ExprKind::Assign(..) => {
+                let old = self.diagnostic_metadata.in_assignment.replace(expr);
+                visit::walk_expr(self, expr);
+                self.diagnostic_metadata.in_assignment = old;
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 13cd7987e92..23c5fac8b71 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate {
 }
 
 /// Only used for diagnostics.
+#[derive(Debug)]
 struct BaseError {
     msg: String,
     fallback_label: String,
@@ -140,6 +141,22 @@ struct BaseError {
     suggestion: Option<(Span, &'static str, String)>,
 }
 
+#[derive(Debug)]
+enum TypoCandidate {
+    Typo(TypoSuggestion),
+    Shadowed(Res),
+    None,
+}
+
+impl TypoCandidate {
+    fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
+        match self {
+            TypoCandidate::Typo(sugg) => Some(sugg),
+            TypoCandidate::Shadowed(_) | TypoCandidate::None => None,
+        }
+    }
+}
+
 impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
@@ -496,7 +513,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         }
 
         // Try Levenshtein algorithm.
-        let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+        let typo_sugg =
+            self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
         if path.len() == 1 && self.self_type_is_available() {
             if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
                 let self_is_available = self.self_value_is_available(path[0].ident.span);
@@ -660,7 +678,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         let is_expected = &|res| source.is_expected(res);
         let ident_span = path.last().map_or(span, |ident| ident.ident.span);
         let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+        if let TypoCandidate::Shadowed(res) = typo_sugg
+            && let Some(id) = res.opt_def_id()
+            && let Some(sugg_span) = self.r.opt_span(id)
+        {
+            err.span_label(
+                sugg_span,
+                format!("you might have meant to refer to this {}", res.descr()),
+            );
+            return true;
+        }
         let mut fallback = false;
+        let typo_sugg = typo_sugg.to_opt_suggestion();
         if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
             fallback = true;
             match self.diagnostic_metadata.current_let_binding {
@@ -679,7 +708,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
             // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
             let suggestion = self.get_single_associated_item(&path, &source, is_expected);
-            self.r.add_typo_suggestion(err, suggestion, ident_span);
+            if !self.r.add_typo_suggestion(err, suggestion, ident_span) {
+                fallback = !self.let_binding_suggestion(err, ident_span);
+            }
         }
         fallback
     }
@@ -1076,41 +1107,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         // where a brace being opened means a block is being started. Look
         // ahead for the next text to see if `span` is followed by a `{`.
         let sm = self.r.session.source_map();
-        let mut sp = span;
-        loop {
-            sp = sm.next_point(sp);
-            match sm.span_to_snippet(sp) {
-                Ok(ref snippet) => {
-                    if snippet.chars().any(|c| !c.is_whitespace()) {
-                        break;
-                    }
-                }
-                _ => break,
-            }
-        }
+        let sp = sm.span_look_ahead(span, None, Some(50));
         let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
         // In case this could be a struct literal that needs to be surrounded
         // by parentheses, find the appropriate span.
-        let mut i = 0;
-        let mut closing_brace = None;
-        loop {
-            sp = sm.next_point(sp);
-            match sm.span_to_snippet(sp) {
-                Ok(ref snippet) => {
-                    if snippet == "}" {
-                        closing_brace = Some(span.to(sp));
-                        break;
-                    }
-                }
-                _ => break,
-            }
-            i += 1;
-            // The bigger the span, the more likely we're incorrect --
-            // bound it to 100 chars long.
-            if i > 100 {
-                break;
-            }
-        }
+        let closing_span = sm.span_look_ahead(span, Some("}"), Some(50));
+        let closing_brace: Option<Span> = sm
+            .span_to_snippet(closing_span)
+            .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None });
         (followed_by_brace, closing_brace)
     }
 
@@ -1581,22 +1585,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         path: &[Segment],
         ns: Namespace,
         filter_fn: &impl Fn(Res) -> bool,
-    ) -> Option<TypoSuggestion> {
+    ) -> TypoCandidate {
         let mut names = Vec::new();
         if path.len() == 1 {
+            let mut ctxt = path.last().unwrap().ident.span.ctxt();
+
             // Search in lexical scope.
             // Walk backwards up the ribs in scope and collect candidates.
             for rib in self.ribs[ns].iter().rev() {
+                let rib_ctxt = if rib.kind.contains_params() {
+                    ctxt.normalize_to_macros_2_0()
+                } else {
+                    ctxt.normalize_to_macro_rules()
+                };
+
                 // Locals and type parameters
                 for (ident, &res) in &rib.bindings {
-                    if filter_fn(res) {
+                    if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
                         names.push(TypoSuggestion::typo_from_res(ident.name, res));
                     }
                 }
+
+                if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) {
+                    // If an invocation of this macro created `ident`, give up on `ident`
+                    // and switch to `ident`'s source from the macro definition.
+                    ctxt.remove_mark();
+                    continue;
+                }
+
                 // Items in scope
                 if let RibKind::ModuleRibKind(module) = rib.kind {
                     // Items from this module
-                    self.r.add_module_candidates(module, &mut names, &filter_fn);
+                    self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
 
                     if let ModuleKind::Block = module.kind {
                         // We can see through blocks
@@ -1622,7 +1642,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                             }));
 
                             if let Some(prelude) = self.r.prelude {
-                                self.r.add_module_candidates(prelude, &mut names, &filter_fn);
+                                self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
                             }
                         }
                         break;
@@ -1641,7 +1661,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
                 self.resolve_path(mod_path, Some(TypeNS), None)
             {
-                self.r.add_module_candidates(module, &mut names, &filter_fn);
+                self.r.add_module_candidates(module, &mut names, &filter_fn, None);
             }
         }
 
@@ -1654,10 +1674,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             name,
             None,
         ) {
-            Some(found) if found != name => {
-                names.into_iter().find(|suggestion| suggestion.candidate == found)
+            Some(found) => {
+                let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else {
+                    return TypoCandidate::None;
+                };
+                if found == name {
+                    TypoCandidate::Shadowed(sugg.res)
+                } else {
+                    TypoCandidate::Typo(sugg)
+                }
             }
-            _ => None,
+            _ => TypoCandidate::None,
         }
     }
 
@@ -1727,26 +1754,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                             }
                         }
                         if let Ok(base_snippet) = base_snippet {
-                            let mut sp = after_colon_sp;
-                            for _ in 0..100 {
-                                // Try to find an assignment
-                                sp = sm.next_point(sp);
-                                let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
-                                match snippet {
-                                    Ok(ref x) if x.as_str() == "=" => {
-                                        err.span_suggestion(
-                                            base_span,
-                                            "maybe you meant to write an assignment here",
-                                            format!("let {}", base_snippet),
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                        show_label = false;
-                                        break;
-                                    }
-                                    Ok(ref x) if x.as_str() == "\n" => break,
-                                    Err(_) => break,
-                                    Ok(_) => {}
-                                }
+                            // Try to find an assignment
+                            let eq_span = sm.span_look_ahead(after_colon_sp, Some("="), Some(50));
+                            if let Ok(ref snippet) = sm.span_to_snippet(eq_span) && snippet == "=" {
+                                err.span_suggestion(
+                                    base_span,
+                                    "maybe you meant to write an assignment here",
+                                    format!("let {}", base_snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                show_label = false;
                             }
                         }
                     }
@@ -1763,6 +1780,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         false
     }
 
+    fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool {
+        // try to give a suggestion for this pattern: `name = 1`, which is common in other languages
+        let mut added_suggestion = false;
+        if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment &&
+            let ast::ExprKind::Path(None, _) = lhs.kind {
+                let sm = self.r.session.source_map();
+                let line_span = sm.span_extend_to_line(ident_span);
+                let ident_name = sm.span_to_snippet(ident_span).unwrap();
+                // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
+                if sm
+                    .span_to_snippet(line_span)
+                    .map_or(false, |s| s.trim().starts_with(&ident_name))
+                {
+                    err.span_suggestion_verbose(
+                        ident_span.shrink_to_lo(),
+                        "you might have meant to introduce a new binding",
+                        "let ".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    added_suggestion = true;
+                }
+            }
+        added_suggestion
+    }
+
     fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
         let mut result = None;
         let mut seen_modules = FxHashSet::default();
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index f6f0b3c1139..9526296f951 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,7 +12,7 @@ use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
@@ -694,7 +694,19 @@ impl<'a> Resolver<'a> {
                     check_consistency(self, &path, path_span, kind, initial_res, res)
                 }
                 path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
+                    let mut suggestion = None;
                     let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
+                        // try to suggest if it's not a macro, maybe a function
+                        if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+                            && partial_res.unresolved_segments() == 0 {
+                            let sm = self.session.source_map();
+                            let exclamation_span = sm.next_point(span);
+                            suggestion = Some((
+                                vec![(exclamation_span, "".to_string())],
+                                    format!("{} is not a macro, but a {}, try to remove `!`", Segment::names_to_string(&path), partial_res.base_res().descr()),
+                                    Applicability::MaybeIncorrect
+                                ));
+                        }
                         (span, label)
                     } else {
                         (
@@ -708,7 +720,7 @@ impl<'a> Resolver<'a> {
                     };
                     self.report_error(
                         span,
-                        ResolutionError::FailedToResolve { label, suggestion: None },
+                        ResolutionError::FailedToResolve { label, suggestion },
                     );
                 }
                 PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
diff --git a/compiler/rustc_save_analysis/src/errors.rs b/compiler/rustc_save_analysis/src/errors.rs
index 8a15ba63661..585aac8c1c3 100644
--- a/compiler/rustc_save_analysis/src/errors.rs
+++ b/compiler/rustc_save_analysis/src/errors.rs
@@ -3,7 +3,7 @@ use rustc_macros::Diagnostic;
 use std::path::Path;
 
 #[derive(Diagnostic)]
-#[diag(save_analysis::could_not_open)]
+#[diag(save_analysis_could_not_open)]
 pub(crate) struct CouldNotOpen<'a> {
     pub file_name: &'a Path,
     pub err: std::io::Error,
diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs
index a5c94118a47..53692ad7cc9 100644
--- a/compiler/rustc_session/src/config/sigpipe.rs
+++ b/compiler/rustc_session/src/config/sigpipe.rs
@@ -1,5 +1,13 @@
 //! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`!
 
+/// The default value if `#[unix_sigpipe]` is not specified. This resolves
+/// to `SIG_IGN` in `library/std/src/sys/unix/mod.rs`.
+///
+/// Note that `SIG_IGN` has been the Rust default since 2014. See
+/// <https://github.com/rust-lang/rust/issues/62569>.
+#[allow(dead_code)]
+pub const DEFAULT: u8 = 0;
+
 /// Do not touch `SIGPIPE`. Use whatever the parent process uses.
 #[allow(dead_code)]
 pub const INHERIT: u8 = 1;
@@ -15,8 +23,3 @@ pub const SIG_IGN: u8 = 2;
 /// such as `head -n 1`.
 #[allow(dead_code)]
 pub const SIG_DFL: u8 = 3;
-
-/// `SIG_IGN` has been the Rust default since 2014. See
-/// <https://github.com/rust-lang/rust/issues/62569>.
-#[allow(dead_code)]
-pub const DEFAULT: u8 = SIG_IGN;
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index d12796f289e..bf542faec41 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -1,15 +1,13 @@
 use std::num::NonZeroU32;
 
 use crate::cgu_reuse_tracker::CguReuse;
-use rustc_errors::{
-    fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan,
-};
+use rustc_errors::MultiSpan;
 use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(Diagnostic)]
-#[diag(session::incorrect_cgu_reuse_type)]
+#[diag(session_incorrect_cgu_reuse_type)]
 pub struct IncorrectCguReuseType<'a> {
     #[primary_span]
     pub span: Span,
@@ -20,14 +18,14 @@ pub struct IncorrectCguReuseType<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(session::cgu_not_recorded)]
+#[diag(session_cgu_not_recorded)]
 pub struct CguNotRecorded<'a> {
     pub cgu_user_name: &'a str,
     pub cgu_name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::feature_gate_error, code = "E0658")]
+#[diag(session_feature_gate_error, code = "E0658")]
 pub struct FeatureGateError<'a> {
     #[primary_span]
     pub span: MultiSpan,
@@ -35,99 +33,99 @@ pub struct FeatureGateError<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[note(session::feature_diagnostic_for_issue)]
+#[note(session_feature_diagnostic_for_issue)]
 pub struct FeatureDiagnosticForIssue {
     pub n: NonZeroU32,
 }
 
 #[derive(Subdiagnostic)]
-#[help(session::feature_diagnostic_help)]
+#[help(session_feature_diagnostic_help)]
 pub struct FeatureDiagnosticHelp {
     pub feature: Symbol,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::not_circumvent_feature)]
+#[diag(session_not_circumvent_feature)]
 pub struct NotCircumventFeature;
 
 #[derive(Diagnostic)]
-#[diag(session::linker_plugin_lto_windows_not_supported)]
+#[diag(session_linker_plugin_lto_windows_not_supported)]
 pub struct LinkerPluginToWindowsNotSupported;
 
 #[derive(Diagnostic)]
-#[diag(session::profile_use_file_does_not_exist)]
+#[diag(session_profile_use_file_does_not_exist)]
 pub struct ProfileUseFileDoesNotExist<'a> {
     pub path: &'a std::path::Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::profile_sample_use_file_does_not_exist)]
+#[diag(session_profile_sample_use_file_does_not_exist)]
 pub struct ProfileSampleUseFileDoesNotExist<'a> {
     pub path: &'a std::path::Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::target_requires_unwind_tables)]
+#[diag(session_target_requires_unwind_tables)]
 pub struct TargetRequiresUnwindTables;
 
 #[derive(Diagnostic)]
-#[diag(session::sanitizer_not_supported)]
+#[diag(session_sanitizer_not_supported)]
 pub struct SanitizerNotSupported {
     pub us: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::sanitizers_not_supported)]
+#[diag(session_sanitizers_not_supported)]
 pub struct SanitizersNotSupported {
     pub us: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::cannot_mix_and_match_sanitizers)]
+#[diag(session_cannot_mix_and_match_sanitizers)]
 pub struct CannotMixAndMatchSanitizers {
     pub first: String,
     pub second: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::cannot_enable_crt_static_linux)]
+#[diag(session_cannot_enable_crt_static_linux)]
 pub struct CannotEnableCrtStaticLinux;
 
 #[derive(Diagnostic)]
-#[diag(session::sanitizer_cfi_enabled)]
+#[diag(session_sanitizer_cfi_enabled)]
 pub struct SanitizerCfiEnabled;
 
 #[derive(Diagnostic)]
-#[diag(session::unstable_virtual_function_elimination)]
+#[diag(session_unstable_virtual_function_elimination)]
 pub struct UnstableVirtualFunctionElimination;
 
 #[derive(Diagnostic)]
-#[diag(session::unsupported_dwarf_version)]
+#[diag(session_unsupported_dwarf_version)]
 pub struct UnsupportedDwarfVersion {
     pub dwarf_version: u32,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::target_stack_protector_not_supported)]
+#[diag(session_target_stack_protector_not_supported)]
 pub struct StackProtectorNotSupportedForTarget<'a> {
     pub stack_protector: StackProtector,
     pub target_triple: &'a TargetTriple,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::split_debuginfo_unstable_platform)]
+#[diag(session_split_debuginfo_unstable_platform)]
 pub struct SplitDebugInfoUnstablePlatform {
     pub debuginfo: SplitDebuginfo,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::file_is_not_writeable)]
+#[diag(session_file_is_not_writeable)]
 pub struct FileIsNotWriteable<'a> {
     pub file: &'a std::path::Path,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::crate_name_does_not_match)]
+#[diag(session_crate_name_does_not_match)]
 pub struct CrateNameDoesNotMatch<'a> {
     #[primary_span]
     pub span: Span,
@@ -136,38 +134,29 @@ pub struct CrateNameDoesNotMatch<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(session::crate_name_invalid)]
+#[diag(session_crate_name_invalid)]
 pub struct CrateNameInvalid<'a> {
     pub s: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(session::crate_name_empty)]
+#[diag(session_crate_name_empty)]
 pub struct CrateNameEmpty {
     #[primary_span]
     pub span: Option<Span>,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_invalid_character_in_create_name)]
 pub struct InvalidCharacterInCrateName<'a> {
+    #[primary_span]
     pub span: Option<Span>,
     pub character: char,
     pub crate_name: &'a str,
 }
 
-impl IntoDiagnostic<'_> for InvalidCharacterInCrateName<'_> {
-    fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name);
-        if let Some(sp) = self.span {
-            diag.set_span(sp);
-        }
-        diag.set_arg("character", self.character);
-        diag.set_arg("crate_name", self.crate_name);
-        diag
-    }
-}
-
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(session::expr_parentheses_needed, applicability = "machine-applicable")]
+#[multipart_suggestion(session_expr_parentheses_needed, applicability = "machine-applicable")]
 pub struct ExprParenthesesNeeded {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -180,3 +169,25 @@ impl ExprParenthesesNeeded {
         ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() }
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(session_skipping_const_checks)]
+pub struct SkippingConstChecks {
+    #[subdiagnostic(eager)]
+    pub unleashed_features: Vec<UnleashedFeatureHelp>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnleashedFeatureHelp {
+    #[help(session_unleashed_feature_help_named)]
+    Named {
+        #[primary_span]
+        span: Span,
+        gate: Symbol,
+    },
+    #[help(session_unleashed_feature_help_unnamed)]
+    Unnamed {
+        #[primary_span]
+        span: Span,
+    },
+}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index a8be318dea8..3f234a47a3d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1295,6 +1295,8 @@ options! {
         an additional `.html` file showing the computed coverage spans."),
     dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
+    dylib_lto: bool = (false, parse_bool, [UNTRACKED],
+        "enables LTO for dylib crate type"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index beb22ab3eb9..100c66f6364 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -5,9 +5,10 @@ use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, S
 use crate::errors::{
     CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported,
     NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist,
-    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
+    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks,
     SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
-    TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion,
+    TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination,
+    UnsupportedDwarfVersion,
 };
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
@@ -44,7 +45,6 @@ use rustc_target::spec::{
 use std::cell::{self, RefCell};
 use std::env;
 use std::fmt;
-use std::io::Write;
 use std::ops::{Div, Mul};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -233,21 +233,19 @@ impl Session {
         if !unleashed_features.is_empty() {
             let mut must_err = false;
             // Create a diagnostic pointing at where things got unleashed.
-            // FIXME(#100717): needs eager translation/lists
-            #[allow(rustc::untranslatable_diagnostic)]
-            #[allow(rustc::diagnostic_outside_of_impl)]
-            let mut diag = self.struct_warn("skipping const checks");
-            for &(span, feature_gate) in unleashed_features.iter() {
-                // FIXME: `span_label` doesn't do anything, so we use "help" as a hack.
-                if let Some(gate) = feature_gate {
-                    diag.span_help(span, &format!("skipping check for `{gate}` feature"));
-                    // The unleash flag must *not* be used to just "hack around" feature gates.
-                    must_err = true;
-                } else {
-                    diag.span_help(span, "skipping check that does not even have a feature gate");
-                }
-            }
-            diag.emit();
+            self.emit_warning(SkippingConstChecks {
+                unleashed_features: unleashed_features
+                    .iter()
+                    .map(|(span, gate)| {
+                        gate.map(|gate| {
+                            must_err = true;
+                            UnleashedFeatureHelp::Named { span: *span, gate }
+                        })
+                        .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span })
+                    })
+                    .collect(),
+            });
+
             // If we should err, make sure we did.
             if must_err && self.has_errors().is_none() {
                 // We have skipped a feature gate, and not run into other errors... reject.
@@ -1213,11 +1211,10 @@ fn default_emitter(
     source_map: Lrc<SourceMap>,
     bundle: Option<Lrc<FluentBundle>>,
     fallback_bundle: LazyFallbackBundle,
-    emitter_dest: Option<Box<dyn Write + Send>>,
 ) -> Box<dyn Emitter + sync::Send> {
     let macro_backtrace = sopts.unstable_opts.macro_backtrace;
-    match (sopts.error_format, emitter_dest) {
-        (config::ErrorOutputType::HumanReadable(kind), dst) => {
+    match sopts.error_format {
+        config::ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
 
             if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
@@ -1230,33 +1227,20 @@ fn default_emitter(
                 );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             } else {
-                let emitter = match dst {
-                    None => EmitterWriter::stderr(
-                        color_config,
-                        Some(source_map),
-                        bundle,
-                        fallback_bundle,
-                        short,
-                        sopts.unstable_opts.teach,
-                        sopts.diagnostic_width,
-                        macro_backtrace,
-                    ),
-                    Some(dst) => EmitterWriter::new(
-                        dst,
-                        Some(source_map),
-                        bundle,
-                        fallback_bundle,
-                        short,
-                        false, // no teach messages when writing to a buffer
-                        false, // no colors when writing to a buffer
-                        None,  // no diagnostic width
-                        macro_backtrace,
-                    ),
-                };
+                let emitter = EmitterWriter::stderr(
+                    color_config,
+                    Some(source_map),
+                    bundle,
+                    fallback_bundle,
+                    short,
+                    sopts.unstable_opts.teach,
+                    sopts.diagnostic_width,
+                    macro_backtrace,
+                );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
         }
-        (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
+        config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(
             JsonEmitter::stderr(
                 Some(registry),
                 source_map,
@@ -1269,28 +1253,9 @@ fn default_emitter(
             )
             .ui_testing(sopts.unstable_opts.ui_testing),
         ),
-        (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
-            JsonEmitter::new(
-                dst,
-                Some(registry),
-                source_map,
-                bundle,
-                fallback_bundle,
-                pretty,
-                json_rendered,
-                sopts.diagnostic_width,
-                macro_backtrace,
-            )
-            .ui_testing(sopts.unstable_opts.ui_testing),
-        ),
     }
 }
 
-pub enum DiagnosticOutput {
-    Default,
-    Raw(Box<dyn Write + Send>),
-}
-
 // JUSTIFICATION: literally session construction
 #[allow(rustc::bad_opt_access)]
 pub fn build_session(
@@ -1298,7 +1263,6 @@ pub fn build_session(
     local_crate_source_file: Option<PathBuf>,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
-    diagnostics_output: DiagnosticOutput,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     target_override: Option<Target>,
@@ -1314,11 +1278,6 @@ pub fn build_session(
     let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
     let can_emit_warnings = !(warnings_allow || cap_lints_allow);
 
-    let write_dest = match diagnostics_output {
-        DiagnosticOutput::Default => None,
-        DiagnosticOutput::Raw(write) => Some(write),
-    };
-
     let sysroot = match &sopts.maybe_sysroot {
         Some(sysroot) => sysroot.clone(),
         None => filesearch::get_or_default_sysroot(),
@@ -1351,8 +1310,7 @@ pub fn build_session(
         rustc_errors::DEFAULT_LOCALE_RESOURCES,
         sopts.unstable_opts.translate_directionality_markers,
     );
-    let emitter =
-        default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);
+    let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
 
     let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
         emitter,
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 9a4f6f9f9ef..e65b6891e32 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -53,6 +53,17 @@ impl NativeLibKind {
             NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false,
         }
     }
+
+    pub fn is_statically_included(&self) -> bool {
+        matches!(self, NativeLibKind::Static { .. })
+    }
+
+    pub fn is_dllimport(&self) -> bool {
+        matches!(
+            self,
+            NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified
+        )
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 91eef647713..842aa98bc9e 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1631,10 +1631,7 @@ impl SourceFile {
     /// number. If the source_file is empty or the position is located before the
     /// first line, `None` is returned.
     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
-        self.lines(|lines| match lines.partition_point(|x| x <= &pos) {
-            0 => None,
-            i => Some(i - 1),
-        })
+        self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
     }
 
     pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 4d94c92d3f2..f9566eeee94 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -853,28 +853,56 @@ impl SourceMap {
     }
 
     /// Returns a new span representing the next character after the end-point of this span.
+    /// Special cases:
+    /// - if span is a dummy one, returns the same span
+    /// - if next_point reached the end of source, return span with lo = hi
+    /// - respect multi-byte characters
     pub fn next_point(&self, sp: Span) -> Span {
         if sp.is_dummy() {
             return sp;
         }
         let start_of_next_point = sp.hi().0;
 
-        let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true);
-        // If the width is 1, then the next span should point to the same `lo` and `hi`. However,
-        // in the case of a multibyte character, where the width != 1, the next span should
+        let width = self.find_width_of_character_at_span(sp, true);
+        if width == 0 {
+            return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None);
+        }
+        // If the width is 1, then the next span should only contain the next char besides current ending.
+        // However, in the case of a multibyte character, where the width != 1, the next span should
         // span multiple bytes to include the whole character.
         let end_of_next_point =
-            start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point);
+            start_of_next_point.checked_add(width).unwrap_or(start_of_next_point);
 
-        let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point));
+        let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point));
         Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None)
     }
 
+    /// Returns a new span to check next none-whitespace character or some specified expected character
+    /// If `expect` is none, the first span of non-whitespace character is returned.
+    /// If `expect` presented, the first span of the character `expect` is returned
+    /// Otherwise, the span reached to limit is returned.
+    pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
+        let mut sp = span;
+        for _ in 0..limit.unwrap_or(100 as usize) {
+            sp = self.next_point(sp);
+            if let Ok(ref snippet) = self.span_to_snippet(sp) {
+                if expect.map_or(false, |es| snippet == es) {
+                    break;
+                }
+                if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) {
+                    break;
+                }
+            }
+        }
+        sp
+    }
+
     /// Finds the width of the character, either before or after the end of provided span,
     /// depending on the `forwards` parameter.
     fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         let sp = sp.data();
-        if sp.lo == sp.hi {
+
+        if sp.lo == sp.hi && !forwards {
             debug!("find_width_of_character_at_span: early return empty span");
             return 1;
         }
@@ -908,9 +936,9 @@ impl SourceMap {
         let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
         debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
         // Ensure indexes are also not malformed.
-        if start_index > end_index || end_index > source_len {
+        if start_index > end_index || end_index > source_len - 1 {
             debug!("find_width_of_character_at_span: source indexes are malformed");
-            return 1;
+            return 0;
         }
 
         let src = local_begin.sf.external_src.borrow();
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 3058ec45a64..1fd81018fa0 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -479,3 +479,48 @@ fn path_prefix_remapping_expand_to_absolute() {
         RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }
     );
 }
+
+#[test]
+fn test_next_point() {
+    let sm = SourceMap::new(FilePathMapping::empty());
+    sm.new_source_file(PathBuf::from("example.rs").into(), "a…b".to_string());
+
+    // Dummy spans don't advance.
+    let span = DUMMY_SP;
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 0);
+    assert_eq!(span.hi().0, 0);
+
+    // Span advance respect multi-byte character
+    let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
+    assert_eq!(sm.span_to_snippet(span), Ok("a".to_string()));
+    let span = sm.next_point(span);
+    assert_eq!(sm.span_to_snippet(span), Ok("…".to_string()));
+    assert_eq!(span.lo().0, 1);
+    assert_eq!(span.hi().0, 4);
+
+    // An empty span pointing just before a multi-byte character should
+    // advance to contain the multi-byte character.
+    let span = Span::with_root_ctxt(BytePos(1), BytePos(1));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 1);
+    assert_eq!(span.hi().0, 4);
+
+    let span = Span::with_root_ctxt(BytePos(1), BytePos(4));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 4);
+    assert_eq!(span.hi().0, 5);
+
+    // A non-empty span at the last byte should advance to create an empty
+    // span pointing at the end of the file.
+    let span = Span::with_root_ctxt(BytePos(4), BytePos(5));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 5);
+    assert_eq!(span.hi().0, 5);
+
+    // Empty span pointing just past the last byte.
+    let span = Span::with_root_ctxt(BytePos(5), BytePos(5));
+    let span = sm.next_point(span);
+    assert_eq!(span.lo().0, 5);
+    assert_eq!(span.hi().0, 5);
+}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c6711b603b6..3fe79370c37 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -451,6 +451,7 @@ symbols! {
         call_once,
         caller_location,
         capture_disjoint_fields,
+        cause,
         cdylib,
         ceilf32,
         ceilf64,
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
index eb487a03c93..f4d0751f753 100644
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ b/compiler/rustc_symbol_mangling/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_macros::Diagnostic;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(symbol_mangling::test_output)]
+#[diag(symbol_mangling_test_output)]
 pub struct TestOutput {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index c915124434b..ce45fa13970 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -109,175 +109,125 @@ pub enum AbiDisabled {
     Unrecognized,
 }
 
-fn gate_feature_post(
+pub fn is_enabled(
     features: &rustc_feature::Features,
-    feature: Symbol,
     span: Span,
-    explain: &'static str,
+    name: &str,
 ) -> Result<(), AbiDisabled> {
-    if !features.enabled(feature) && !span.allows_unstable(feature) {
-        Err(AbiDisabled::Unstable { feature, explain })
-    } else {
-        Ok(())
+    let s = is_stable(name);
+    if let Err(AbiDisabled::Unstable { feature, .. }) = s {
+        if features.enabled(feature) || span.allows_unstable(feature) {
+            return Ok(());
+        }
     }
+    s
 }
 
-pub fn is_enabled(
-    features: &rustc_feature::Features,
-    span: Span,
-    name: &str,
-) -> Result<(), AbiDisabled> {
+pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
     match name {
         // Stable
         "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
         | "system" => Ok(()),
-        "rust-intrinsic" => {
-            gate_feature_post(features, sym::intrinsics, span, "intrinsics are subject to change")
-        }
-        "platform-intrinsic" => gate_feature_post(
-            features,
-            sym::platform_intrinsics,
-            span,
-            "platform intrinsics are experimental and possibly buggy",
-        ),
-        "vectorcall" => gate_feature_post(
-            features,
-            sym::abi_vectorcall,
-            span,
-            "vectorcall is experimental and subject to change",
-        ),
-        "thiscall" => gate_feature_post(
-            features,
-            sym::abi_thiscall,
-            span,
-            "thiscall is experimental and subject to change",
-        ),
-        "rust-call" => gate_feature_post(
-            features,
-            sym::unboxed_closures,
-            span,
-            "rust-call ABI is subject to change",
-        ),
-        "rust-cold" => gate_feature_post(
-            features,
-            sym::rust_cold_cc,
-            span,
-            "rust-cold is experimental and subject to change",
-        ),
-        "ptx-kernel" => gate_feature_post(
-            features,
-            sym::abi_ptx,
-            span,
-            "PTX ABIs are experimental and subject to change",
-        ),
-        "unadjusted" => gate_feature_post(
-            features,
-            sym::abi_unadjusted,
-            span,
-            "unadjusted ABI is an implementation detail and perma-unstable",
-        ),
-        "msp430-interrupt" => gate_feature_post(
-            features,
-            sym::abi_msp430_interrupt,
-            span,
-            "msp430-interrupt ABI is experimental and subject to change",
-        ),
-        "x86-interrupt" => gate_feature_post(
-            features,
-            sym::abi_x86_interrupt,
-            span,
-            "x86-interrupt ABI is experimental and subject to change",
-        ),
-        "amdgpu-kernel" => gate_feature_post(
-            features,
-            sym::abi_amdgpu_kernel,
-            span,
-            "amdgpu-kernel ABI is experimental and subject to change",
-        ),
-        "avr-interrupt" | "avr-non-blocking-interrupt" => gate_feature_post(
-            features,
-            sym::abi_avr_interrupt,
-            span,
-            "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
-        ),
-        "efiapi" => gate_feature_post(
-            features,
-            sym::abi_efiapi,
-            span,
-            "efiapi ABI is experimental and subject to change",
-        ),
-        "C-cmse-nonsecure-call" => gate_feature_post(
-            features,
-            sym::abi_c_cmse_nonsecure_call,
-            span,
-            "C-cmse-nonsecure-call ABI is experimental and subject to change",
-        ),
-        "C-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "C-unwind ABI is experimental and subject to change",
-        ),
-        "stdcall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "stdcall-unwind ABI is experimental and subject to change",
-        ),
-        "system-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "system-unwind ABI is experimental and subject to change",
-        ),
-        "thiscall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "thiscall-unwind ABI is experimental and subject to change",
-        ),
-        "cdecl-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "cdecl-unwind ABI is experimental and subject to change",
-        ),
-        "fastcall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "fastcall-unwind ABI is experimental and subject to change",
-        ),
-        "vectorcall-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "vectorcall-unwind ABI is experimental and subject to change",
-        ),
-        "aapcs-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "aapcs-unwind ABI is experimental and subject to change",
-        ),
-        "win64-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "win64-unwind ABI is experimental and subject to change",
-        ),
-        "sysv64-unwind" => gate_feature_post(
-            features,
-            sym::c_unwind,
-            span,
-            "sysv64-unwind ABI is experimental and subject to change",
-        ),
-        "wasm" => gate_feature_post(
-            features,
-            sym::wasm_abi,
-            span,
-            "wasm ABI is experimental and subject to change",
-        ),
+        "rust-intrinsic" => Err(AbiDisabled::Unstable {
+            feature: sym::intrinsics,
+            explain: "intrinsics are subject to change",
+        }),
+        "platform-intrinsic" => Err(AbiDisabled::Unstable {
+            feature: sym::platform_intrinsics,
+            explain: "platform intrinsics are experimental and possibly buggy",
+        }),
+        "vectorcall" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_vectorcall,
+            explain: "vectorcall is experimental and subject to change",
+        }),
+        "thiscall" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_thiscall,
+            explain: "thiscall is experimental and subject to change",
+        }),
+        "rust-call" => Err(AbiDisabled::Unstable {
+            feature: sym::unboxed_closures,
+            explain: "rust-call ABI is subject to change",
+        }),
+        "rust-cold" => Err(AbiDisabled::Unstable {
+            feature: sym::rust_cold_cc,
+            explain: "rust-cold is experimental and subject to change",
+        }),
+        "ptx-kernel" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_ptx,
+            explain: "PTX ABIs are experimental and subject to change",
+        }),
+        "unadjusted" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_unadjusted,
+            explain: "unadjusted ABI is an implementation detail and perma-unstable",
+        }),
+        "msp430-interrupt" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_msp430_interrupt,
+            explain: "msp430-interrupt ABI is experimental and subject to change",
+        }),
+        "x86-interrupt" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_x86_interrupt,
+            explain: "x86-interrupt ABI is experimental and subject to change",
+        }),
+        "amdgpu-kernel" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_amdgpu_kernel,
+            explain: "amdgpu-kernel ABI is experimental and subject to change",
+        }),
+        "avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_avr_interrupt,
+            explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
+        }),
+        "efiapi" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_efiapi,
+            explain: "efiapi ABI is experimental and subject to change",
+        }),
+        "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
+            feature: sym::abi_c_cmse_nonsecure_call,
+            explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
+        }),
+        "C-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "C-unwind ABI is experimental and subject to change",
+        }),
+        "stdcall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "stdcall-unwind ABI is experimental and subject to change",
+        }),
+        "system-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "system-unwind ABI is experimental and subject to change",
+        }),
+        "thiscall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "thiscall-unwind ABI is experimental and subject to change",
+        }),
+        "cdecl-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "cdecl-unwind ABI is experimental and subject to change",
+        }),
+        "fastcall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "fastcall-unwind ABI is experimental and subject to change",
+        }),
+        "vectorcall-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "vectorcall-unwind ABI is experimental and subject to change",
+        }),
+        "aapcs-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "aapcs-unwind ABI is experimental and subject to change",
+        }),
+        "win64-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "win64-unwind ABI is experimental and subject to change",
+        }),
+        "sysv64-unwind" => Err(AbiDisabled::Unstable {
+            feature: sym::c_unwind,
+            explain: "sysv64-unwind ABI is experimental and subject to change",
+        }),
+        "wasm" => Err(AbiDisabled::Unstable {
+            feature: sym::wasm_abi,
+            explain: "wasm ABI is experimental and subject to change",
+        }),
         _ => Err(AbiDisabled::Unrecognized),
     }
 }
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 61793468594..7f870582444 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::dump_vtable_entries)]
+#[diag(trait_selection_dump_vtable_entries)]
 pub struct DumpVTableEntries<'a> {
     #[primary_span]
     pub span: Span,
@@ -14,7 +14,7 @@ pub struct DumpVTableEntries<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::unable_to_construct_constant_value)]
+#[diag(trait_selection_unable_to_construct_constant_value)]
 pub struct UnableToConstructConstantValue<'a> {
     #[primary_span]
     pub span: Span,
@@ -23,7 +23,7 @@ pub struct UnableToConstructConstantValue<'a> {
 
 #[derive(Diagnostic)]
 #[help]
-#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")]
+#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")]
 pub struct AutoDerefReachedRecursionLimit<'a> {
     #[primary_span]
     #[label]
@@ -34,7 +34,7 @@ pub struct AutoDerefReachedRecursionLimit<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
 pub struct EmptyOnClauseInOnUnimplemented {
     #[primary_span]
     #[label]
@@ -42,7 +42,7 @@ pub struct EmptyOnClauseInOnUnimplemented {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
 pub struct InvalidOnClauseInOnUnimplemented {
     #[primary_span]
     #[label]
@@ -50,7 +50,7 @@ pub struct InvalidOnClauseInOnUnimplemented {
 }
 
 #[derive(Diagnostic)]
-#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")]
+#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")]
 #[note]
 pub struct NoValueInOnUnimplemented {
     #[primary_span]
@@ -71,7 +71,7 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
         self,
         handler: &Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict);
+        let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict);
         diag.set_arg("trait_desc", self.trait_desc);
         diag.set_arg(
             "self_desc",
@@ -81,19 +81,19 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
         diag.code(rustc_errors::error_code!(E0751));
         match self.negative_impl_span {
             Ok(span) => {
-                diag.span_label(span, fluent::trait_selection::negative_implementation_here);
+                diag.span_label(span, fluent::negative_implementation_here);
             }
             Err(cname) => {
-                diag.note(fluent::trait_selection::negative_implementation_in_crate);
+                diag.note(fluent::negative_implementation_in_crate);
                 diag.set_arg("negative_impl_cname", cname.to_string());
             }
         }
         match self.positive_impl_span {
             Ok(span) => {
-                diag.span_label(span, fluent::trait_selection::positive_implementation_here);
+                diag.span_label(span, fluent::positive_implementation_here);
             }
             Err(cname) => {
-                diag.note(fluent::trait_selection::positive_implementation_in_crate);
+                diag.note(fluent::positive_implementation_in_crate);
                 diag.set_arg("positive_impl_cname", cname.to_string());
             }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 77158747431..8aab75490a8 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -60,23 +60,17 @@ pub fn add_placeholder_note(err: &mut Diagnostic) {
     );
 }
 
-/// If there are types that satisfy both impls, invokes `on_overlap`
+/// If there are types that satisfy both impls, returns `Some`
 /// with a suitably-freshened `ImplHeader` with those types
-/// substituted. Otherwise, invokes `no_overlap`.
-#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
-pub fn overlapping_impls<F1, F2, R>(
+/// substituted. Otherwise, returns `None`.
+#[instrument(skip(tcx, skip_leak_check), level = "debug")]
+pub fn overlapping_impls(
     tcx: TyCtxt<'_>,
     impl1_def_id: DefId,
     impl2_def_id: DefId,
     skip_leak_check: SkipLeakCheck,
     overlap_mode: OverlapMode,
-    on_overlap: F1,
-    no_overlap: F2,
-) -> R
-where
-    F1: FnOnce(OverlapResult<'_>) -> R,
-    F2: FnOnce() -> R,
-{
+) -> Option<OverlapResult<'_>> {
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
@@ -97,7 +91,7 @@ where
     if !may_overlap {
         // Some types involved are definitely different, so the impls couldn't possibly overlap.
         debug!("overlapping_impls: fast_reject early-exit");
-        return no_overlap();
+        return None;
     }
 
     let infcx = tcx.infer_ctxt().build();
@@ -105,7 +99,7 @@ where
     let overlaps =
         overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
     if !overlaps {
-        return no_overlap();
+        return None;
     }
 
     // In the case where we detect an error, run the check again, but
@@ -114,7 +108,7 @@ where
     let infcx = tcx.infer_ctxt().build();
     let selcx = &mut SelectionContext::intercrate(&infcx);
     selcx.enable_tracking_intercrate_ambiguity_causes();
-    on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
+    Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
 }
 
 fn with_fresh_ty_vars<'cx, 'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index b06f24ddf2e..84038625fb2 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -9,14 +9,12 @@
 //! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def::DefKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::{
     walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable,
 };
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
-use rustc_session::lint;
 use rustc_span::Span;
 
 use std::iter;
@@ -161,11 +159,20 @@ pub fn try_unify_abstract_consts<'tcx>(
 #[instrument(skip(infcx), level = "debug")]
 pub fn is_const_evaluatable<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    uv: ty::UnevaluatedConst<'tcx>,
+    ct: ty::Const<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     span: Span,
 ) -> Result<(), NotConstEvaluatable> {
     let tcx = infcx.tcx;
+    let uv = match ct.kind() {
+        ty::ConstKind::Unevaluated(uv) => uv,
+        ty::ConstKind::Param(_)
+        | ty::ConstKind::Bound(_, _)
+        | ty::ConstKind::Placeholder(_)
+        | ty::ConstKind::Value(_)
+        | ty::ConstKind::Error(_) => return Ok(()),
+        ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
+    };
 
     if tcx.features().generic_const_exprs {
         if let Some(ct) = AbstractConst::new(tcx, uv)? {
@@ -253,25 +260,7 @@ pub fn is_const_evaluatable<'tcx>(
                 Err(NotConstEvaluatable::Error(reported))
             }
             Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
-            Ok(_) => {
-                if uv.substs.has_non_region_param() {
-                    assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
-                    let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
-
-                    if mir_body.is_polymorphic {
-                        let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
-                        tcx.struct_span_lint_hir(
-                            lint::builtin::CONST_EVALUATABLE_UNCHECKED,
-                            tcx.hir().local_def_id_to_hir_id(local_def_id),
-                            span,
-                            "cannot use constants which depend on generic parameters in types",
-                            |err| err
-                        )
-                    }
-                }
-
-                Ok(())
-            },
+            Ok(_) => Ok(()),
         }
     }
 }
@@ -285,7 +274,7 @@ fn satisfied_from_param_env<'tcx>(
     for pred in param_env.caller_bounds() {
         match pred.kind().skip_binder() {
             ty::PredicateKind::ConstEvaluatable(uv) => {
-                if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+                if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? {
                     let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
 
                     // Try to unify with each subtree in the AbstractConst to allow for
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 4e8baa2dfab..1217d264a9c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2,10 +2,10 @@ pub mod on_unimplemented;
 pub mod suggestions;
 
 use super::{
-    EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
-    MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
-    OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
-    PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
+    FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
+    Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
+    OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
+    SelectionContext, SelectionError, TraitNotObjectSafe,
 };
 
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -764,6 +764,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
                         }
 
+                        let mut unsatisfied_const = false;
                         if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
                             let non_const_predicate = trait_ref.without_const();
                             let non_const_obligation = Obligation {
@@ -773,6 +774,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 recursion_depth: obligation.recursion_depth,
                             };
                             if self.predicate_may_hold(&non_const_obligation) {
+                                unsatisfied_const = true;
                                 err.span_note(
                                     span,
                                     &format!(
@@ -924,7 +926,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 }
                             }
                         } else if !trait_ref.has_non_region_infer()
-                            && self.predicate_can_apply(obligation.param_env, trait_ref)
+                            && self.predicate_can_apply(obligation.param_env, trait_predicate)
                         {
                             // If a where-clause may be useful, remind the
                             // user that they can add it.
@@ -939,7 +941,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 None,
                                 obligation.cause.body_id,
                             );
-                        } else if !suggested {
+                        } else if !suggested && !unsatisfied_const {
                             // Can't show anything else useful, try to find similar impls.
                             let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
                             if !self.report_similar_impl_candidates(
@@ -1304,7 +1306,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
 
                 match obligation.predicate.kind().skip_binder() {
-                    ty::PredicateKind::ConstEvaluatable(uv) => {
+                    ty::PredicateKind::ConstEvaluatable(ct) => {
+                        let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+                            bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+                        };
                         let mut err =
                             self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
                         let const_span = self.tcx.def_span(uv.def.did);
@@ -1433,7 +1438,7 @@ trait InferCtxtPrivExt<'tcx> {
     fn predicate_can_apply(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        pred: ty::PolyTraitRef<'tcx>,
+        pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool;
 
     fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
@@ -2368,7 +2373,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if predicate.references_error() || self.is_tainted_by_errors() {
                     return;
                 }
-                let subst = data.substs.iter().find(|g| g.has_non_region_infer());
+                let subst = data.walk().find(|g| g.is_non_region_infer());
                 if let Some(subst) = subst {
                     let err = self.emit_inference_failure_err(
                         body_id,
@@ -2508,7 +2513,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn predicate_can_apply(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        pred: ty::PolyTraitRef<'tcx>,
+        pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         struct ParamToVarFolder<'a, 'tcx> {
             infcx: &'a InferCtxt<'tcx>,
@@ -2552,7 +2557,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             let obligation = Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
-                cleaned_pred.without_const().to_predicate(selcx.tcx()),
+                cleaned_pred.to_predicate(selcx.tcx()),
             );
 
             self.predicate_may_hold(&obligation)
@@ -2796,3 +2801,8 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
         }
     }
 }
+
+pub enum DefIdOrName {
+    DefId(DefId),
+    Name(&'static str),
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 0f20e02d6ec..5eef54c6330 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -164,6 +164,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
         }
 
+        if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+            flags.push((sym::cause, Some("MainFunctionType".to_string())));
+        }
+
         // Add all types without trimmed paths.
         ty::print::with_no_trimmed_paths!({
             let generics = self.tcx.generics_of(def_id);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 4431cf9f443..8c41d9d240c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1,5 +1,5 @@
 use super::{
-    EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
     SelectionContext,
 };
 
@@ -7,6 +7,7 @@ use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::normalize_to;
 
+use hir::def::CtorOf;
 use hir::HirId;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -22,6 +23,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
@@ -29,7 +31,7 @@ use rustc_middle::ty::{
     ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
@@ -812,74 +814,136 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        // Skipping binder here, remapping below
-        let self_ty = trait_pred.self_ty().skip_binder();
-
-        let (def_id, output_ty, callable) = match *self_ty.kind() {
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
-            ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
-            _ => return false,
-        };
-        let msg = format!("use parentheses to call the {}", callable);
+        if let ty::PredicateKind::Trait(trait_pred) = obligation.predicate.kind().skip_binder()
+            && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
+        {
+            // Don't suggest calling to turn an unsized type into a sized type
+            return false;
+        }
 
-        // "We should really create a single list of bound vars from the combined vars
-        // from the predicate and function, but instead we just liberate the function bound vars"
-        let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+        // This is duplicated from `extract_callable_info` in typeck, which
+        // relies on autoderef, so we can't use it here.
+        let found = trait_pred.self_ty().skip_binder().peel_refs();
+        let Some((def_id_or_name, output, inputs)) = (match *found.kind()
+        {
+            ty::FnPtr(fn_sig) => {
+                Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.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, substs) => {
+                let fn_sig = substs.as_closure().sig();
+                Some((
+                    DefIdOrName::DefId(def_id),
+                    fn_sig.output(),
+                    fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
+                ))
+            }
+            ty::Opaque(def_id, substs) => {
+                self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    // args tuple will always be substs[1]
+                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                    {
+                        Some((
+                            DefIdOrName::DefId(def_id),
+                            pred.kind().rebind(proj.term.ty().unwrap()),
+                            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()
+                    && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    // for existential projection, substs are shifted over by 1
+                    && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+                    {
+                        Some((
+                            DefIdOrName::Name("trait object"),
+                            pred.rebind(proj.term.ty().unwrap()),
+                            pred.rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
+                    }
+                })
+            }
+            ty::Param(_) => {
+                obligation.param_env.caller_bounds().iter().find_map(|pred| {
+                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    && proj.projection_ty.self_ty() == found
+                    // args tuple will always be substs[1]
+                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                    {
+                        Some((
+                            DefIdOrName::Name("type parameter"),
+                            pred.kind().rebind(proj.term.ty().unwrap()),
+                            pred.kind().rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
+                    }
+                })
+            }
+            _ => None,
+        }) else { return false; };
+        let output = self.replace_bound_vars_with_fresh_vars(
+            obligation.cause.span,
+            LateBoundRegionConversionTime::FnCall,
+            output,
+        );
+        let inputs = inputs.skip_binder().iter().map(|ty| {
+            self.replace_bound_vars_with_fresh_vars(
+                obligation.cause.span,
+                LateBoundRegionConversionTime::FnCall,
+                inputs.rebind(*ty),
+            )
+        });
 
         // Remapping bound vars here
-        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
+        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
 
         let new_obligation =
             self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
-
-        match self.evaluate_obligation(&new_obligation) {
-            Ok(
-                EvaluationResult::EvaluatedToOk
-                | EvaluationResult::EvaluatedToOkModuloRegions
-                | EvaluationResult::EvaluatedToOkModuloOpaqueTypes
-                | EvaluationResult::EvaluatedToAmbig,
-            ) => {}
-            _ => return false,
+        if !self.predicate_must_hold_modulo_regions(&new_obligation) {
+            return false;
         }
-        let hir = self.tcx.hir();
+
         // Get the name of the callable and the arguments to be used in the suggestion.
-        let (snippet, sugg) = match hir.get_if_local(def_id) {
-            Some(hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
-                ..
-            })) => {
-                err.span_label(*fn_decl_span, "consider calling this closure");
-                let Some(name) = self.get_closure_name(def_id, err, &msg) else {
-                    return false;
-                };
-                let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                let sugg = format!("({})", args);
-                (format!("{}{}", name, sugg), sugg)
-            }
-            Some(hir::Node::Item(hir::Item {
-                ident,
-                kind: hir::ItemKind::Fn(.., body_id),
-                ..
-            })) => {
-                err.span_label(ident.span, "consider calling this function");
-                let body = hir.body(*body_id);
-                let args = body
-                    .params
-                    .iter()
-                    .map(|arg| match &arg.pat.kind {
-                        hir::PatKind::Binding(_, _, ident, None)
-                        // FIXME: provide a better suggestion when encountering `SelfLower`, it
-                        // should suggest a method call.
-                        if ident.name != kw::SelfLower => ident.to_string(),
-                        _ => "_".to_string(),
-                    })
-                    .collect::<Vec<_>>()
-                    .join(", ");
-                let sugg = format!("({})", args);
-                (format!("{}{}", ident, sugg), sugg)
-            }
-            _ => return false,
+        let hir = self.tcx.hir();
+
+        let msg = match def_id_or_name {
+            DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
+                DefKind::Ctor(CtorOf::Struct, _) => {
+                    "use parentheses to construct this tuple struct".to_string()
+                }
+                DefKind::Ctor(CtorOf::Variant, _) => {
+                    "use parentheses to construct this tuple variant".to_string()
+                }
+                kind => format!("use parentheses to call this {}", kind.descr(def_id)),
+            },
+            DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
         };
+
+        let args = inputs
+            .map(|ty| {
+                if ty.is_suggestable(self.tcx, false) {
+                    format!("/* {ty} */")
+                } else {
+                    "/* value */".to_string()
+                }
+            })
+            .collect::<Vec<_>>()
+            .join(", ");
+
         if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
             && obligation.cause.span.can_be_used_for_suggestions()
         {
@@ -890,11 +954,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             err.span_suggestion_verbose(
                 obligation.cause.span.shrink_to_hi(),
                 &msg,
-                sugg,
+                format!("({args})"),
                 Applicability::HasPlaceholders,
             );
-        } else {
-            err.help(&format!("{}: `{}`", msg, snippet));
+        } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
+            let name = match hir.get_if_local(def_id) {
+                Some(hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
+                    ..
+                })) => {
+                    err.span_label(*fn_decl_span, "consider calling this closure");
+                    let Some(name) = self.get_closure_name(def_id, err, &msg) else {
+                        return false;
+                    };
+                    name.to_string()
+                }
+                Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => {
+                    err.span_label(ident.span, "consider calling this function");
+                    ident.to_string()
+                }
+                Some(hir::Node::Ctor(..)) => {
+                    let name = self.tcx.def_path_str(def_id);
+                    err.span_label(
+                        self.tcx.def_span(def_id),
+                        format!("consider calling the constructor for `{}`", name),
+                    );
+                    name
+                }
+                _ => return false,
+            };
+            err.help(&format!("{msg}: `{name}({args})`"));
         }
         true
     }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 6eb02395685..a417e1440b9 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -355,7 +355,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::RegionOutlives(data) => {
-                    if infcx.considering_regions || data.has_placeholders() {
+                    if infcx.considering_regions {
                         infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
                     }
 
@@ -476,9 +476,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         Err(NotConstEvaluatable::MentionsInfer) => {
                             pending_obligation.stalled_on.clear();
                             pending_obligation.stalled_on.extend(
-                                uv.substs
-                                    .iter()
-                                    .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+                                uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
                             );
                             ProcessResult::Unchanged
                         }
@@ -492,19 +490,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
+                    assert!(
+                        self.selcx.tcx().features().generic_const_exprs,
+                        "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+                    );
                     debug!(?c1, ?c2, "equating consts");
-                    let tcx = self.selcx.tcx();
-                    if tcx.features().generic_const_exprs {
-                        // FIXME: we probably should only try to unify abstract constants
-                        // if the constants depend on generic parameters.
-                        //
-                        // Let's just see where this breaks :shrug:
-                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.kind(), c2.kind())
-                        {
-                            if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
-                                return ProcessResult::Changed(vec![]);
-                            }
+                    // FIXME: we probably should only try to unify abstract constants
+                    // if the constants depend on generic parameters.
+                    //
+                    // Let's just see where this breaks :shrug:
+                    if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                        (c1.kind(), c2.kind())
+                    {
+                        if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+                            return ProcessResult::Changed(vec![]);
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 274a366873c..0bf54c096cd 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -764,12 +764,9 @@ fn dump_vtable_entries<'tcx>(
     });
 }
 
-fn own_existential_vtable_entries<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
-) -> &'tcx [DefId] {
+fn own_existential_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> &'tcx [DefId] {
     let trait_methods = tcx
-        .associated_items(trait_ref.def_id())
+        .associated_items(trait_def_id)
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Fn);
     // Now list each method's DefId (for within its trait).
@@ -778,7 +775,7 @@ fn own_existential_vtable_entries<'tcx>(
         let def_id = trait_method.def_id;
 
         // Some methods cannot be called on an object; skip those.
-        if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+        if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) {
             debug!("own_existential_vtable_entry: not vtable safe");
             return None;
         }
@@ -810,7 +807,7 @@ fn vtable_entries<'tcx>(
 
                 // Lookup the shape of vtable for the trait.
                 let own_existential_entries =
-                    tcx.own_existential_vtable_entries(existential_trait_ref);
+                    tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
 
                 let own_entries = own_existential_entries.iter().copied().map(|def_id| {
                     debug!("vtable_entries: trait_method={:?}", def_id);
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 545524f63a7..0bb25a74dc8 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -837,24 +837,14 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
             }
         }
 
-        fn visit_ty_unevaluated(
-            &mut self,
-            uv: ty::UnevaluatedConst<'tcx>,
-        ) -> ControlFlow<Self::BreakTy> {
+        fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             // Constants can only influence object safety if they reference `Self`.
             // This is only possible for unevaluated constants, so we walk these here.
             //
-            // If `AbstractConst::new` returned an error we already failed compilation
+            // If `AbstractConst::from_const` returned an error we already failed compilation
             // so we don't have to emit an additional error here.
-            //
-            // We currently recurse into abstract consts here but do not recurse in
-            // `is_const_evaluatable`. This means that the object safety check is more
-            // liberal than the const eval check.
-            //
-            // This shouldn't really matter though as we can't really use any
-            // constants which are not considered const evaluatable.
             use rustc_middle::ty::abstract_const::Node;
-            if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv) {
+            if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
                 walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) {
                     Node::Leaf(leaf) => self.visit_const(leaf),
                     Node::Cast(_, _, ty) => self.visit_ty(ty),
@@ -863,7 +853,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
                     }
                 })
             } else {
-                ControlFlow::CONTINUE
+                ct.super_visit_with(self)
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 1ca9a1c1994..c8276854016 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -264,7 +264,7 @@ fn project_and_unify_type<'cx, 'tcx>(
     };
     debug!(?normalized, ?obligations, "project_and_unify_type result");
     let actual = obligation.predicate.term;
-    // For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs
+    // For an example where this is necessary see src/test/ui/impl-trait/nested-return-type2.rs
     // This allows users to omit re-mentioning all bounds on an associated type and just use an
     // `impl Trait` for the assoc type to add more bounds.
     let InferOk { value: actual, obligations: new } =
@@ -2254,7 +2254,10 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     }
 
     let impl_fn_def_id = leaf_def.item.def_id;
-    let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
+    // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
+    // since `data.substs` are the impl substs.
+    let impl_fn_substs =
+        obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
 
     let cause = ObligationCause::new(
         obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index af102952172..715f5be8e2f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -11,10 +11,10 @@ use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
-use rustc_middle::mir;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_span::DUMMY_SP;
 
 use std::ops::ControlFlow;
 
@@ -254,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let result = tcx.normalize_projection_ty(c_data)?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
-                    bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+                    // Rustdoc normalizes possibly not well-formed types, so only
+                    // treat this as a bug if we're not in rustdoc.
+                    if !tcx.sess.opts.actually_rustdoc {
+                        tcx.sess.delay_span_bug(
+                            DUMMY_SP,
+                            format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+                        );
+                    }
+                    return Err(NoSolution);
                 }
                 let InferOk { value: result, obligations } =
                     self.infcx.instantiate_query_response_and_region_obligations(
@@ -297,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let result = tcx.normalize_projection_ty(c_data)?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
-                    bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+                    // Rustdoc normalizes possibly not well-formed types, so only
+                    // treat this as a bug if we're not in rustdoc.
+                    if !tcx.sess.opts.actually_rustdoc {
+                        tcx.sess.delay_span_bug(
+                            DUMMY_SP,
+                            format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+                        );
+                    }
+                    return Err(NoSolution);
                 }
                 let InferOk { value: result, obligations } =
                     self.infcx.instantiate_query_response_and_region_obligations(
@@ -347,13 +363,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         ))
     }
 
-    fn try_fold_mir_const(
-        &mut self,
-        constant: mir::ConstantKind<'tcx>,
-    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        constant.try_super_fold_with(self)
-    }
-
     #[inline]
     fn try_fold_predicate(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index ddabea700d3..9ebff489201 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -676,19 +676,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
+                    assert!(
+                        self.tcx().features().generic_const_exprs,
+                        "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+                    );
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
-                    if self.tcx().features().generic_const_exprs {
-                        // FIXME: we probably should only try to unify abstract constants
-                        // if the constants depend on generic parameters.
-                        //
-                        // Let's just see where this breaks :shrug:
-                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.kind(), c2.kind())
-                        {
-                            if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
-                                return Ok(EvaluatedToOk);
-                            }
+                    // FIXME: we probably should only try to unify abstract constants
+                    // if the constants depend on generic parameters.
+                    //
+                    // Let's just see where this breaks :shrug:
+                    if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                        (c1.kind(), c2.kind())
+                    {
+                        if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+                            return Ok(EvaluatedToOk);
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index fcb73b43fa8..63f89a33e8a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -137,9 +137,8 @@ impl ChildrenExt<'_> for Children {
                     impl_def_id,
                     traits::SkipLeakCheck::default(),
                     overlap_mode,
-                    |_| true,
-                    || false,
-                );
+                )
+                .is_some();
 
                 let error = create_overlap_error(overlap);
 
@@ -162,34 +161,29 @@ impl ChildrenExt<'_> for Children {
                 impl_def_id,
                 traits::SkipLeakCheck::Yes,
                 overlap_mode,
-                |overlap| {
-                    if let Some(overlap_kind) =
-                        tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
-                    {
-                        match overlap_kind {
-                            ty::ImplOverlapKind::Permitted { marker: _ } => {}
-                            ty::ImplOverlapKind::Issue33140 => {
-                                *last_lint_mut = Some(FutureCompatOverlapError {
-                                    error: create_overlap_error(overlap),
-                                    kind: FutureCompatOverlapErrorKind::Issue33140,
-                                });
-                            }
+            )
+            .map_or(Ok((false, false)), |overlap| {
+                if let Some(overlap_kind) =
+                    tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
+                {
+                    match overlap_kind {
+                        ty::ImplOverlapKind::Permitted { marker: _ } => {}
+                        ty::ImplOverlapKind::Issue33140 => {
+                            *last_lint_mut = Some(FutureCompatOverlapError {
+                                error: create_overlap_error(overlap),
+                                kind: FutureCompatOverlapErrorKind::Issue33140,
+                            });
                         }
-
-                        return Ok((false, false));
                     }
 
-                    let le = tcx.specializes((impl_def_id, possible_sibling));
-                    let ge = tcx.specializes((possible_sibling, impl_def_id));
+                    return Ok((false, false));
+                }
 
-                    if le == ge {
-                        report_overlap_error(overlap, last_lint_mut)
-                    } else {
-                        Ok((le, ge))
-                    }
-                },
-                || Ok((false, false)),
-            )?;
+                let le = tcx.specializes((impl_def_id, possible_sibling));
+                let ge = tcx.specializes((possible_sibling, impl_def_id));
+
+                if le == ge { report_overlap_error(overlap, last_lint_mut) } else { Ok((le, ge)) }
+            })?;
 
             if le && !ge {
                 debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 5206e9f649b..ed47d2f83df 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -268,10 +268,7 @@ pub fn count_own_vtable_entries<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> usize {
-    let existential_trait_ref =
-        trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
-    let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
-    tcx.own_existential_vtable_entries(existential_trait_ref).len()
+    tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
 }
 
 /// Given an upcast trait object described by `object`, returns the
@@ -282,15 +279,10 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
     object: &super::ImplSourceObjectData<'tcx, N>,
     method_def_id: DefId,
 ) -> Option<usize> {
-    let existential_trait_ref = object
-        .upcast_trait_ref
-        .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
-    let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
-
     // Count number of methods preceding the one we are selecting and
     // add them to the total offset.
     if let Some(index) = tcx
-        .own_existential_vtable_entries(existential_trait_ref)
+        .own_existential_vtable_entries(object.upcast_trait_ref.def_id())
         .iter()
         .copied()
         .position(|def_id| def_id == method_def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 635cdde0e8e..0870833cc35 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -148,13 +148,8 @@ pub fn predicate_obligations<'tcx>(
             wf.compute(a.into());
             wf.compute(b.into());
         }
-        ty::PredicateKind::ConstEvaluatable(uv) => {
-            let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
-            wf.out.extend(obligations);
-
-            for arg in uv.substs.iter() {
-                wf.compute(arg);
-            }
+        ty::PredicateKind::ConstEvaluatable(ct) => {
+            wf.compute(ct.into());
         }
         ty::PredicateKind::ConstEquate(c1, c2) => {
             wf.compute(c1.into());
@@ -476,14 +471,14 @@ impl<'tcx> WfPredicates<'tcx> {
                 // obligations are handled by the parent (e.g. `ty::Ref`).
                 GenericArgKind::Lifetime(_) => continue,
 
-                GenericArgKind::Const(constant) => {
-                    match constant.kind() {
+                GenericArgKind::Const(ct) => {
+                    match ct.kind() {
                         ty::ConstKind::Unevaluated(uv) => {
                             let obligations = self.nominal_obligations(uv.def.did, uv.substs);
                             self.out.extend(obligations);
 
                             let predicate =
-                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
                                     .to_predicate(self.tcx());
                             let cause = self.cause(traits::WellFormed(None));
                             self.out.push(traits::Obligation::with_depth(
@@ -500,7 +495,7 @@ impl<'tcx> WfPredicates<'tcx> {
                                 cause,
                                 self.recursion_depth,
                                 self.param_env,
-                                ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
+                                ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into()))
                                     .to_predicate(self.tcx()),
                             ));
                         }
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 58b718ed127..2da64d73d34 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -18,9 +18,6 @@ pub(crate) fn provide(p: &mut Providers) {
 
             try_normalize_after_erasing_regions(tcx, goal)
         },
-        try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
-            try_normalize_after_erasing_regions(tcx, goal)
-        },
         ..*p
     };
 }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 6e34ee21082..73c7eb6992f 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -4,6 +4,7 @@ use rustc_middle::ty::layout::{
     fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::call::{
     ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
@@ -384,7 +385,7 @@ fn fn_abi_new_uncached<'tcx>(
         conv,
         can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi),
     };
-    fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi)?;
+    fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?;
     debug!("fn_abi_new_uncached = {:?}", fn_abi);
     Ok(cx.tcx.arena.alloc(fn_abi))
 }
@@ -394,6 +395,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
     abi: SpecAbi,
+    fn_def_id: Option<DefId>,
 ) -> Result<(), FnAbiError<'tcx>> {
     if abi == SpecAbi::Unadjusted {
         return Ok(());
@@ -404,7 +406,18 @@ fn fn_abi_adjust_for_abi<'tcx>(
         || abi == SpecAbi::RustIntrinsic
         || abi == SpecAbi::PlatformIntrinsic
     {
-        let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| {
+        // Look up the deduced parameter attributes for this function, if we have its def ID and
+        // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
+        // as appropriate.
+        let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No
+            && cx.tcx.sess.opts.incremental.is_none()
+        {
+            fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
+        } else {
+            &[]
+        };
+
+        let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
             if arg.is_ignore() {
                 return;
             }
@@ -451,10 +464,30 @@ fn fn_abi_adjust_for_abi<'tcx>(
                 // so we pick an appropriately sized integer type instead.
                 arg.cast_to(Reg { kind: RegKind::Integer, size });
             }
+
+            // If we deduced that this parameter was read-only, add that to the attribute list now.
+            //
+            // The `readonly` parameter only applies to pointers, so we can only do this if the
+            // argument was passed indirectly. (If the argument is passed directly, it's an SSA
+            // value, so it's implicitly immutable.)
+            if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) =
+                (arg_idx, &mut arg.mode)
+            {
+                // The `deduced_param_attrs` list could be empty if this is a type of function
+                // we can't deduce any parameters for, so make sure the argument index is in
+                // bounds.
+                if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx) {
+                    if deduced_param_attrs.read_only {
+                        attrs.regular.insert(ArgAttribute::ReadOnly);
+                        debug!("added deduced read-only attribute");
+                    }
+                }
+            }
         };
-        fixup(&mut fn_abi.ret);
-        for arg in fn_abi.args.iter_mut() {
-            fixup(arg);
+
+        fixup(&mut fn_abi.ret, None);
+        for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
+            fixup(arg, Some(arg_idx));
         }
     } else {
         fn_abi.adjust_for_foreign_abi(cx, abi)?;
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 753c474a34b..c05eeb353a8 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -5,18 +5,18 @@ use rustc_middle::ty::Ty;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(ty_utils::needs_drop_overflow)]
+#[diag(ty_utils_needs_drop_overflow)]
 pub struct NeedsDropOverflow<'tcx> {
     pub query_ty: Ty<'tcx>,
 }
 
 #[derive(Diagnostic)]
-#[diag(ty_utils::generic_constant_too_complex)]
+#[diag(ty_utils_generic_constant_too_complex)]
 #[help]
 pub struct GenericConstantTooComplex {
     #[primary_span]
     pub span: Span,
-    #[note(ty_utils::maybe_supported)]
+    #[note(maybe_supported)]
     pub maybe_supported: Option<()>,
     #[subdiagnostic]
     pub sub: GenericConstantTooComplexSub,
@@ -24,46 +24,46 @@ pub struct GenericConstantTooComplex {
 
 #[derive(Subdiagnostic)]
 pub enum GenericConstantTooComplexSub {
-    #[label(ty_utils::borrow_not_supported)]
+    #[label(ty_utils_borrow_not_supported)]
     BorrowNotSupported(#[primary_span] Span),
-    #[label(ty_utils::address_and_deref_not_supported)]
+    #[label(ty_utils_address_and_deref_not_supported)]
     AddressAndDerefNotSupported(#[primary_span] Span),
-    #[label(ty_utils::array_not_supported)]
+    #[label(ty_utils_array_not_supported)]
     ArrayNotSupported(#[primary_span] Span),
-    #[label(ty_utils::block_not_supported)]
+    #[label(ty_utils_block_not_supported)]
     BlockNotSupported(#[primary_span] Span),
-    #[label(ty_utils::never_to_any_not_supported)]
+    #[label(ty_utils_never_to_any_not_supported)]
     NeverToAnyNotSupported(#[primary_span] Span),
-    #[label(ty_utils::tuple_not_supported)]
+    #[label(ty_utils_tuple_not_supported)]
     TupleNotSupported(#[primary_span] Span),
-    #[label(ty_utils::index_not_supported)]
+    #[label(ty_utils_index_not_supported)]
     IndexNotSupported(#[primary_span] Span),
-    #[label(ty_utils::field_not_supported)]
+    #[label(ty_utils_field_not_supported)]
     FieldNotSupported(#[primary_span] Span),
-    #[label(ty_utils::const_block_not_supported)]
+    #[label(ty_utils_const_block_not_supported)]
     ConstBlockNotSupported(#[primary_span] Span),
-    #[label(ty_utils::adt_not_supported)]
+    #[label(ty_utils_adt_not_supported)]
     AdtNotSupported(#[primary_span] Span),
-    #[label(ty_utils::pointer_not_supported)]
+    #[label(ty_utils_pointer_not_supported)]
     PointerNotSupported(#[primary_span] Span),
-    #[label(ty_utils::yield_not_supported)]
+    #[label(ty_utils_yield_not_supported)]
     YieldNotSupported(#[primary_span] Span),
-    #[label(ty_utils::loop_not_supported)]
+    #[label(ty_utils_loop_not_supported)]
     LoopNotSupported(#[primary_span] Span),
-    #[label(ty_utils::box_not_supported)]
+    #[label(ty_utils_box_not_supported)]
     BoxNotSupported(#[primary_span] Span),
-    #[label(ty_utils::binary_not_supported)]
+    #[label(ty_utils_binary_not_supported)]
     BinaryNotSupported(#[primary_span] Span),
-    #[label(ty_utils::logical_op_not_supported)]
+    #[label(ty_utils_logical_op_not_supported)]
     LogicalOpNotSupported(#[primary_span] Span),
-    #[label(ty_utils::assign_not_supported)]
+    #[label(ty_utils_assign_not_supported)]
     AssignNotSupported(#[primary_span] Span),
-    #[label(ty_utils::closure_and_return_not_supported)]
+    #[label(ty_utils_closure_and_return_not_supported)]
     ClosureAndReturnNotSupported(#[primary_span] Span),
-    #[label(ty_utils::control_flow_not_supported)]
+    #[label(ty_utils_control_flow_not_supported)]
     ControlFlowNotSupported(#[primary_span] Span),
-    #[label(ty_utils::inline_asm_not_supported)]
+    #[label(ty_utils_inline_asm_not_supported)]
     InlineAsmNotSupported(#[primary_span] Span),
-    #[label(ty_utils::operation_not_supported)]
+    #[label(ty_utils_operation_not_supported)]
     OperationNotSupported(#[primary_span] Span),
 }
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index da30344ef7e..7fbe78aa523 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -675,9 +675,9 @@ impl<CTX> HashStable<CTX> for InferTy {
         use InferTy::*;
         discriminant(self).hash_stable(ctx, hasher);
         match self {
-            TyVar(v) => v.as_u32().hash_stable(ctx, hasher),
-            IntVar(v) => v.index.hash_stable(ctx, hasher),
-            FloatVar(v) => v.index.hash_stable(ctx, hasher),
+            TyVar(_) | IntVar(_) | FloatVar(_) => {
+                panic!("type variables should not be hashed: {self:?}")
+            }
             FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
         }
     }
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 6d54924e515..a4fb1480fa4 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -1332,8 +1332,8 @@ where
             RePlaceholder(p) => {
                 p.hash_stable(hcx, hasher);
             }
-            ReVar(reg) => {
-                reg.hash_stable(hcx, hasher);
+            ReVar(_) => {
+                panic!("region variables should not be hashed: {self:?}")
             }
         }
     }
diff --git a/config.toml.example b/config.toml.example
index 1f5747456e9..a46813e4d7a 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -638,6 +638,11 @@ changelog-seen = 2
 # If an explicit setting is given, it will be used for all parts of the codebase.
 #new-symbol-mangling = true|false (see comment)
 
+# Select LTO mode that will be used for compiling rustc. By default, thin local LTO
+# (LTO within a single crate) is used (like for any Rust crate). You can also select
+# "thin" or "fat" to apply Thin/Fat LTO to the `rustc_driver` dylib.
+#lto = "thin-local"
+
 # =============================================================================
 # Options for specific targets
 #
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index 904a53bb4ac..83a1385599b 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -21,7 +21,6 @@ use Cow::*;
 impl<'a, B: ?Sized> Borrow<B> for Cow<'a, B>
 where
     B: ToOwned,
-    <B as ToOwned>::Owned: 'a,
 {
     fn borrow(&self) -> &B {
         &**self
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f651cb02176..b7e7d5a38a5 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1620,6 +1620,22 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
     }
 }
 
+/// Casts a boxed slice to a boxed array.
+///
+/// # Safety
+///
+/// `boxed_slice.len()` must be exactly `N`.
+unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
+    boxed_slice: Box<[T], A>,
+) -> Box<[T; N], A> {
+    debug_assert_eq!(boxed_slice.len(), N);
+
+    let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
+    // SAFETY: Pointer and allocator came from an existing box,
+    // and our safety condition requires that the length is exactly `N`
+    unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
+}
+
 #[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
 impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
     type Error = Box<[T]>;
@@ -1635,13 +1651,46 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
     /// `boxed_slice.len()` does not equal `N`.
     fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
         if boxed_slice.len() == N {
-            Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })
+            Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
         } else {
             Err(boxed_slice)
         }
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_array_try_from_vec", since = "CURRENT_RUSTC_VERSION")]
+impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
+    type Error = Vec<T>;
+
+    /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
+    ///
+    /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
+    /// but will require a reallocation otherwise.
+    ///
+    /// # Errors
+    ///
+    /// Returns the original `Vec<T>` in the `Err` variant if
+    /// `boxed_slice.len()` does not equal `N`.
+    ///
+    /// # Examples
+    ///
+    /// This can be used with [`vec!`] to create an array on the heap:
+    ///
+    /// ```
+    /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
+    /// assert_eq!(state.len(), 100);
+    /// ```
+    fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
+        if vec.len() == N {
+            let boxed_slice = vec.into_boxed_slice();
+            Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
+        } else {
+            Err(vec)
+        }
+    }
+}
+
 impl<A: Allocator> Box<dyn Any, A> {
     /// Attempt to downcast the box to a concrete type.
     ///
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 73bc1c21d55..c4c75e46a2a 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1093,6 +1093,9 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
 
     /// Moves all elements from `other` into `self`, leaving `other` empty.
     ///
+    /// If a key from `other` is already present in `self`, the respective
+    /// value from `self` will be overwritten with the respective value from `other`.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1101,10 +1104,10 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// let mut a = BTreeMap::new();
     /// a.insert(1, "a");
     /// a.insert(2, "b");
-    /// a.insert(3, "c");
+    /// a.insert(3, "c"); // Note: Key (3) also present in b.
     ///
     /// let mut b = BTreeMap::new();
-    /// b.insert(3, "d");
+    /// b.insert(3, "d"); // Note: Key (3) also present in a.
     /// b.insert(4, "e");
     /// b.insert(5, "f");
     ///
@@ -1115,7 +1118,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     ///
     /// assert_eq!(a[&1], "a");
     /// assert_eq!(a[&2], "b");
-    /// assert_eq!(a[&3], "d");
+    /// assert_eq!(a[&3], "d"); // Note: "c" has been overwritten.
     /// assert_eq!(a[&4], "e");
     /// assert_eq!(a[&5], "f");
     /// ```
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 7fde8f670a2..ce36b116f13 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -125,9 +125,9 @@
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
 #![feature(layout_for_ptr)]
-#![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
+#![feature(maybe_uninit_uninit_array_transpose)]
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(pattern)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 6d247681c66..9c229665c7e 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1386,7 +1386,7 @@ impl<T: ?Sized> Rc<T> {
             Self::allocate_for_layout(
                 Layout::for_value(&*ptr),
                 |layout| Global.allocate(layout),
-                |mem| mem.with_metadata_of(ptr as *mut RcBox<T>),
+                |mem| mem.with_metadata_of(ptr as *const RcBox<T>),
             )
         }
     }
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 983376a282b..c436adf7006 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -67,7 +67,7 @@ use core::str::Utf8Chunks;
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::collections::TryReserveError;
-use crate::str::{self, Chars, Utf8Error};
+use crate::str::{self, from_utf8_unchecked_mut, Chars, Utf8Error};
 #[cfg(not(no_global_oom_handling))]
 use crate::str::{from_boxed_utf8_unchecked, FromStr};
 use crate::vec::Vec;
@@ -1849,6 +1849,35 @@ impl String {
         let slice = self.vec.into_boxed_slice();
         unsafe { from_boxed_utf8_unchecked(slice) }
     }
+
+    /// Consumes and leaks the `String`, returning a mutable reference to the contents,
+    /// `&'static mut str`.
+    ///
+    /// This is mainly useful for data that lives for the remainder of
+    /// the program's life. Dropping the returned reference will cause a memory
+    /// leak.
+    ///
+    /// It does not reallocate or shrink the `String`,
+    /// so the leaked allocation may include unused capacity that is not part
+    /// of the returned slice.
+    ///
+    /// # Examples
+    ///
+    /// Simple usage:
+    ///
+    /// ```
+    /// #![feature(string_leak)]
+    ///
+    /// let x = String::from("bucket");
+    /// let static_ref: &'static mut str = x.leak();
+    /// assert_eq!(static_ref, "bucket");
+    /// ```
+    #[unstable(feature = "string_leak", issue = "102929")]
+    #[inline]
+    pub fn leak(self) -> &'static mut str {
+        let slice = self.vec.leak();
+        unsafe { from_utf8_unchecked_mut(slice) }
+    }
 }
 
 impl FromUtf8Error {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index df315dad893..e8d9de4fb3c 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1204,7 +1204,7 @@ impl<T: ?Sized> Arc<T> {
             Self::allocate_for_layout(
                 Layout::for_value(&*ptr),
                 |layout| Global.allocate(layout),
-                |mem| mem.with_metadata_of(ptr as *mut ArcInner<T>),
+                |mem| mem.with_metadata_of(ptr as *const ArcInner<T>),
             )
         }
     }
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 73d7c90cf78..02cc7691a82 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -223,7 +223,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
 
             self.ptr = self.ptr.wrapping_byte_add(N);
             // Safety: ditto
-            return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
+            return Ok(unsafe { raw_ary.transpose().assume_init() });
         }
 
         if len < N {
@@ -241,7 +241,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         return unsafe {
             ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N);
             self.ptr = self.ptr.add(N);
-            Ok(MaybeUninit::array_assume_init(raw_ary))
+            Ok(raw_ary.transpose().assume_init())
         };
     }
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index b2bb7a5b2e6..6a71f08330c 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1999,9 +1999,7 @@ impl<T, A: Allocator> Vec<T, A> {
         unsafe {
             // set self.vec length's to start, to be safe in case Drain is leaked
             self.set_len(start);
-            // Use the borrow in the IterMut to indicate borrowing behavior of the
-            // whole Drain iterator (like &mut T).
-            let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start);
+            let range_slice = slice::from_raw_parts(self.as_ptr().add(start), end - start);
             Drain {
                 tail_start: end,
                 tail_len: len - end,
@@ -2193,7 +2191,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// static_ref[0] += 1;
     /// assert_eq!(static_ref, &[2, 2, 3]);
     /// ```
-    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_leak", since = "1.47.0")]
     #[inline]
     pub fn leak<'a>(self) -> &'a mut [T]
diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs
index 4b40485d207..38887f29af1 100644
--- a/library/core/benches/iter.rs
+++ b/library/core/benches/iter.rs
@@ -1,4 +1,6 @@
 use core::iter::*;
+use core::mem;
+use core::num::Wrapping;
 use test::{black_box, Bencher};
 
 #[bench]
@@ -398,3 +400,21 @@ fn bench_trusted_random_access_adapters(b: &mut Bencher) {
         acc
     })
 }
+
+/// Exercises the iter::Copied specialization for slice::Iter
+#[bench]
+fn bench_copied_array_chunks(b: &mut Bencher) {
+    let v = vec![1u8; 1024];
+
+    b.iter(|| {
+        black_box(&v)
+            .iter()
+            .copied()
+            .array_chunks::<{ mem::size_of::<u64>() }>()
+            .map(|ary| {
+                let d = u64::from_ne_bytes(ary);
+                Wrapping(d.rotate_left(7).wrapping_add(1))
+            })
+            .sum::<Wrapping<u64>>()
+    })
+}
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index a6c174d2fca..1e462e3fc3f 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -4,6 +4,7 @@
 #![feature(int_log)]
 #![feature(test)]
 #![feature(trusted_random_access)]
+#![feature(iter_array_chunks)]
 
 extern crate test;
 
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index b3b26040067..b91c630183d 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -104,8 +104,7 @@ impl<T, const N: usize> IntoIter<T, N> {
     ///
     /// ```
     /// #![feature(array_into_iter_constructors)]
-    ///
-    /// #![feature(maybe_uninit_array_assume_init)]
+    /// #![feature(maybe_uninit_uninit_array_transpose)]
     /// #![feature(maybe_uninit_uninit_array)]
     /// use std::array::IntoIter;
     /// use std::mem::MaybeUninit;
@@ -134,7 +133,7 @@ impl<T, const N: usize> IntoIter<T, N> {
     ///     }
     ///
     ///     // SAFETY: We've initialized all N items
-    ///     unsafe { Ok(MaybeUninit::array_assume_init(buffer)) }
+    ///     unsafe { Ok(buffer.transpose().assume_init()) }
     /// }
     ///
     /// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index b82bbf2267a..eae0e1c7618 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -32,6 +32,10 @@ pub use iter::IntoIter;
 /// # Example
 ///
 /// ```rust
+/// // type inference is helping us here, the way `from_fn` knows how many
+/// // elements to produce is the length of array down there: only arrays of
+/// // equal lengths can be compared, so the const generic parameter `N` is
+/// // inferred to be 5, thus creating array of 5 elements.
 /// let array = core::array::from_fn(|i| i);
 /// assert_eq!(array, [0, 1, 2, 3, 4]);
 /// ```
@@ -912,7 +916,7 @@ where
 
     mem::forget(guard);
     // SAFETY: All elements of the array were populated in the loop above.
-    let output = unsafe { MaybeUninit::array_assume_init(array) };
+    let output = unsafe { array.transpose().assume_init() };
     Ok(Try::from_output(output))
 }
 
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 4474b673a95..3451a25504e 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1816,6 +1816,50 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 ///
 /// [`.get_mut()`]: `UnsafeCell::get_mut`
 ///
+/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T`. A consequence
+/// of this guarantee is that it is possible to convert between `T` and `UnsafeCell<T>`.
+/// Special care has to be taken when converting a nested `T` inside of an `Outer<T>` type
+/// to an `Outer<UnsafeCell<T>>` type: this is not sound when the `Outer<T>` type enables [niche]
+/// optimizations. For example, the type `Option<NonNull<u8>>` is typically 8 bytes large on
+/// 64-bit platforms, but the type `Option<UnsafeCell<NonNull<u8>>>` takes up 16 bytes of space.
+/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
+/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
+/// order to avoid its interior mutability property from spreading from `T` into the `Outer` type,
+/// thus this can cause distortions in the type size in these cases. Furthermore, it is only valid
+/// to obtain a `*mut T` pointer to the contents of a _shared_ `UnsafeCell<T>` through [`.get()`]
+/// or [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer or
+/// by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell<T>`, e.g.:
+///
+/// ```rust
+/// use std::cell::UnsafeCell;
+///
+/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
+/// let shared: &UnsafeCell<u32> = &x;
+/// // using `.get()` is okay:
+/// unsafe {
+///     // SAFETY: there exist no other references to the contents of `x`
+///     let exclusive: &mut u32 = &mut *shared.get();
+/// };
+/// // using `.raw_get()` is also okay:
+/// unsafe {
+///     // SAFETY: there exist no other references to the contents of `x` in this scope
+///     let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _);
+/// };
+/// // using `.get_mut()` is always safe:
+/// let exclusive: &mut u32 = x.get_mut();
+///
+/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`:
+/// unsafe {
+///     // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell<u32>`
+///     let shared: &UnsafeCell<u32> = &*(exclusive as *mut _ as *const UnsafeCell<u32>);
+///     // SAFETY: there exist no other *active* references to the contents of `x` in this scope
+///     let exclusive: &mut u32 = &mut *shared.get();
+/// }
+/// ```
+///
+/// [niche]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#niche
+/// [`.raw_get()`]: `UnsafeCell::raw_get`
+///
 /// # Examples
 ///
 /// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 224bc9effe6..bb83599369c 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -597,9 +597,14 @@ impl char {
     /// Returns the number of 16-bit code units this `char` would need if
     /// encoded in UTF-16.
     ///
+    /// That number of code units is always either 1 or 2, for unicode scalar values in
+    /// the [basic multilingual plane] or [supplementary planes] respectively.
+    ///
     /// See the documentation for [`len_utf8()`] for more explanation of this
     /// concept. This function is a mirror, but for UTF-16 instead of UTF-8.
     ///
+    /// [basic multilingual plane]: http://www.unicode.org/glossary/#basic_multilingual_plane
+    /// [supplementary planes]: http://www.unicode.org/glossary/#supplementary_planes
     /// [`len_utf8()`]: #method.len_utf8
     ///
     /// # Examples
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 2399262c05b..1589fee46be 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -994,14 +994,14 @@ extern "rust-intrinsic" {
     /// `transmute` is semantically equivalent to a bitwise move of one type
     /// into another. It copies the bits from the source value into the
     /// destination value, then forgets the original. Note that source and destination
-    /// are passed by-value, which means if `T` or `U` contain padding, that padding
+    /// are passed by-value, which means if `Src` or `Dst` contain padding, that padding
     /// is *not* guaranteed to be preserved by `transmute`.
     ///
     /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at
     /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler
     /// will generate code *assuming that you, the programmer, ensure that there will never be
     /// undefined behavior*. It is therefore your responsibility to guarantee that every value
-    /// passed to `transmute` is valid at both types `T` and `U`. Failing to uphold this condition
+    /// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition
     /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
     /// unsafe**. `transmute` should be the absolute last resort.
     ///
@@ -1012,7 +1012,7 @@ extern "rust-intrinsic" {
     ///
     /// Because `transmute` is a by-value operation, alignment of the *transmuted values
     /// themselves* is not a concern. As with any other function, the compiler already ensures
-    /// both `T` and `U` are properly aligned. However, when transmuting values that *point
+    /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point
     /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper
     /// alignment of the pointed-to values.
     ///
@@ -1248,7 +1248,7 @@ extern "rust-intrinsic" {
     #[rustc_allowed_through_unstable_modules]
     #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
     #[rustc_diagnostic_item = "transmute"]
-    pub fn transmute<T, U>(e: T) -> U;
+    pub fn transmute<Src, Dst>(src: Src) -> Dst;
 
     /// Returns `true` if the actual type given as `T` requires drop
     /// glue; returns `false` if the actual type provided for `T`
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index f9bfd77d7fb..62d3afb8160 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -2,7 +2,10 @@ use crate::iter::adapters::{
     zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
 };
 use crate::iter::{FusedIterator, TrustedLen};
+use crate::mem::MaybeUninit;
+use crate::mem::SizedTypeProperties;
 use crate::ops::Try;
+use crate::{array, ptr};
 
 /// An iterator that copies the elements of an underlying iterator.
 ///
@@ -44,6 +47,15 @@ where
         self.it.next().copied()
     }
 
+    fn next_chunk<const N: usize>(
+        &mut self,
+    ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
+    where
+        Self: Sized,
+    {
+        <I as SpecNextChunk<'_, N, T>>::spec_next_chunk(&mut self.it)
+    }
+
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.it.size_hint()
     }
@@ -166,3 +178,65 @@ where
     T: Copy,
 {
 }
+
+trait SpecNextChunk<'a, const N: usize, T: 'a>: Iterator<Item = &'a T>
+where
+    T: Copy,
+{
+    fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>>;
+}
+
+impl<'a, const N: usize, I, T: 'a> SpecNextChunk<'a, N, T> for I
+where
+    I: Iterator<Item = &'a T>,
+    T: Copy,
+{
+    default fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
+        array::iter_next_chunk(&mut self.map(|e| *e))
+    }
+}
+
+impl<'a, const N: usize, T: 'a> SpecNextChunk<'a, N, T> for crate::slice::Iter<'a, T>
+where
+    T: Copy,
+{
+    fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
+        let mut raw_array = MaybeUninit::uninit_array();
+
+        let len = self.len();
+
+        if T::IS_ZST {
+            if len < N {
+                let _ = self.advance_by(len);
+                // SAFETY: ZSTs can be conjured ex nihilo; only the amount has to be correct
+                return Err(unsafe { array::IntoIter::new_unchecked(raw_array, 0..len) });
+            }
+
+            let _ = self.advance_by(N);
+            // SAFETY: ditto
+            return Ok(unsafe { MaybeUninit::array_assume_init(raw_array) });
+        }
+
+        if len < N {
+            // SAFETY: `len` indicates that this many elements are available and we just checked that
+            // it fits into the array.
+            unsafe {
+                ptr::copy_nonoverlapping(
+                    self.as_ref().as_ptr(),
+                    raw_array.as_mut_ptr() as *mut T,
+                    len,
+                );
+                let _ = self.advance_by(len);
+                return Err(array::IntoIter::new_unchecked(raw_array, 0..len));
+            }
+        }
+
+        // SAFETY: `len` is larger than the array size. Copy a fixed amount here to fully initialize
+        // the array.
+        unsafe {
+            ptr::copy_nonoverlapping(self.as_ref().as_ptr(), raw_array.as_mut_ptr() as *mut T, N);
+            let _ = self.advance_by(N);
+            Ok(MaybeUninit::array_assume_init(raw_array))
+        }
+    }
+}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index da84763836e..9cbfbbb9f39 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -174,6 +174,7 @@
 #![feature(allow_internal_unstable)]
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
+#![feature(c_unwind)]
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
@@ -217,6 +218,7 @@
 #![feature(unboxed_closures)]
 #![feature(unsized_fn_params)]
 #![feature(asm_const)]
+#![feature(const_transmute_copy)]
 //
 // Target features:
 #![feature(arm_target_feature)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index d5ed52124e2..c43c4fff6ae 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -483,64 +483,6 @@ impl<T: ?Sized> !Sync for *const T {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> !Sync for *mut T {}
 
-macro_rules! impls {
-    ($t: ident) => {
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> Hash for $t<T> {
-            #[inline]
-            fn hash<H: Hasher>(&self, _: &mut H) {}
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> cmp::PartialEq for $t<T> {
-            fn eq(&self, _other: &$t<T>) -> bool {
-                true
-            }
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> cmp::Eq for $t<T> {}
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> cmp::PartialOrd for $t<T> {
-            fn partial_cmp(&self, _other: &$t<T>) -> Option<cmp::Ordering> {
-                Option::Some(cmp::Ordering::Equal)
-            }
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> cmp::Ord for $t<T> {
-            fn cmp(&self, _other: &$t<T>) -> cmp::Ordering {
-                cmp::Ordering::Equal
-            }
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> Copy for $t<T> {}
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized> Clone for $t<T> {
-            fn clone(&self) -> Self {
-                Self
-            }
-        }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
-        impl<T: ?Sized> const Default for $t<T> {
-            fn default() -> Self {
-                Self
-            }
-        }
-
-        #[unstable(feature = "structural_match", issue = "31434")]
-        impl<T: ?Sized> StructuralPartialEq for $t<T> {}
-
-        #[unstable(feature = "structural_match", issue = "31434")]
-        impl<T: ?Sized> StructuralEq for $t<T> {}
-    };
-}
-
 /// Zero-sized type used to mark things that "act like" they own a `T`.
 ///
 /// Adding a `PhantomData<T>` field to your type tells the compiler that your
@@ -678,7 +620,59 @@ macro_rules! impls {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct PhantomData<T: ?Sized>;
 
-impls! { PhantomData }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Hash for PhantomData<T> {
+    #[inline]
+    fn hash<H: Hasher>(&self, _: &mut H) {}
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::PartialEq for PhantomData<T> {
+    fn eq(&self, _other: &PhantomData<T>) -> bool {
+        true
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::Eq for PhantomData<T> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::PartialOrd for PhantomData<T> {
+    fn partial_cmp(&self, _other: &PhantomData<T>) -> Option<cmp::Ordering> {
+        Option::Some(cmp::Ordering::Equal)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::Ord for PhantomData<T> {
+    fn cmp(&self, _other: &PhantomData<T>) -> cmp::Ordering {
+        cmp::Ordering::Equal
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Copy for PhantomData<T> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Clone for PhantomData<T> {
+    fn clone(&self) -> Self {
+        Self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+impl<T: ?Sized> const Default for PhantomData<T> {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[unstable(feature = "structural_match", issue = "31434")]
+impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
+
+#[unstable(feature = "structural_match", issue = "31434")]
+impl<T: ?Sized> StructuralEq for PhantomData<T> {}
 
 mod impls {
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index e2ae39fbab3..7757c95de9d 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -146,7 +146,6 @@ use crate::slice;
 ///
 /// ```
 /// use std::mem::MaybeUninit;
-/// use std::ptr;
 ///
 /// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
 /// // safe because the type we are claiming to have initialized here is a
@@ -162,7 +161,7 @@ use crate::slice;
 ///
 /// // For each item in the array, drop if we allocated it.
 /// for elem in &mut data[0..data_len] {
-///     unsafe { ptr::drop_in_place(elem.as_mut_ptr()); }
+///     unsafe { elem.assume_init_drop(); }
 /// }
 /// ```
 ///
@@ -1284,3 +1283,42 @@ impl<T> MaybeUninit<T> {
         }
     }
 }
+
+impl<T, const N: usize> MaybeUninit<[T; N]> {
+    /// Transposes a `MaybeUninit<[T; N]>` into a `[MaybeUninit<T>; N]`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_uninit_array_transpose)]
+    /// # use std::mem::MaybeUninit;
+    ///
+    /// let data: [MaybeUninit<u8>; 1000] = MaybeUninit::uninit().transpose();
+    /// ```
+    #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")]
+    #[inline]
+    pub const fn transpose(self) -> [MaybeUninit<T>; N] {
+        // SAFETY: T and MaybeUninit<T> have the same layout
+        unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+    }
+}
+
+impl<T, const N: usize> [MaybeUninit<T>; N] {
+    /// Transposes a `[MaybeUninit<T>; N]` into a `MaybeUninit<[T; N]>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_uninit_array_transpose)]
+    /// # use std::mem::MaybeUninit;
+    ///
+    /// let data = [MaybeUninit::<u8>::uninit(); 1000];
+    /// let data: MaybeUninit<[u8; 1000]> = data.transpose();
+    /// ```
+    #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")]
+    #[inline]
+    pub const fn transpose(self) -> MaybeUninit<[T; N]> {
+        // SAFETY: T and MaybeUninit<T> have the same layout
+        unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+    }
+}
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 1a78efaf4ff..9195da5a44f 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1008,18 +1008,18 @@ pub fn copy<T: Copy>(x: &T) -> T {
     *x
 }
 
-/// Interprets `src` as having type `&U`, and then reads `src` without moving
+/// Interprets `src` as having type `&Dst`, and then reads `src` without moving
 /// the contained value.
 ///
-/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of]
-/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way
-/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also
-/// unsafely create a copy of the contained value instead of moving out of `src`.
+/// This function will unsafely assume the pointer `src` is valid for [`size_of::<Dst>`][size_of]
+/// bytes by transmuting `&Src` to `&Dst` and then reading the `&Dst` (except that this is done
+/// in a way that is correct even when `&Dst` has stricter alignment requirements than `&Src`).
+/// It will also unsafely create a copy of the contained value instead of moving out of `src`.
 ///
-/// It is not a compile-time error if `T` and `U` have different sizes, but it
-/// is highly encouraged to only invoke this function where `T` and `U` have the
-/// same size. This function triggers [undefined behavior][ub] if `U` is larger than
-/// `T`.
+/// It is not a compile-time error if `Src` and `Dst` have different sizes, but it
+/// is highly encouraged to only invoke this function where `Src` and `Dst` have the
+/// same size. This function triggers [undefined behavior][ub] if `Dst` is larger than
+/// `Src`.
 ///
 /// [ub]: ../../reference/behavior-considered-undefined.html
 ///
@@ -1052,19 +1052,22 @@ pub fn copy<T: Copy>(x: &T) -> T {
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
-pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
-    assert!(size_of::<T>() >= size_of::<U>(), "cannot transmute_copy if U is larger than T");
+pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst {
+    assert!(
+        size_of::<Src>() >= size_of::<Dst>(),
+        "cannot transmute_copy if Dst is larger than Src"
+    );
 
-    // If U has a higher alignment requirement, src might not be suitably aligned.
-    if align_of::<U>() > align_of::<T>() {
+    // If Dst has a higher alignment requirement, src might not be suitably aligned.
+    if align_of::<Dst>() > align_of::<Src>() {
         // SAFETY: `src` is a reference which is guaranteed to be valid for reads.
         // The caller must guarantee that the actual transmutation is safe.
-        unsafe { ptr::read_unaligned(src as *const T as *const U) }
+        unsafe { ptr::read_unaligned(src as *const Src as *const Dst) }
     } else {
         // SAFETY: `src` is a reference which is guaranteed to be valid for reads.
-        // We just checked that `src as *const U` was properly aligned.
+        // We just checked that `src as *const Dst` was properly aligned.
         // The caller must guarantee that the actual transmutation is safe.
-        unsafe { ptr::read(src as *const T as *const U) }
+        unsafe { ptr::read(src as *const Src as *const Dst) }
     }
 }
 
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index b413a85fee3..81f050cb283 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -869,7 +869,7 @@ macro_rules! int_impl {
             // Deal with the final bit of the exponent separately, since
             // squaring the base afterwards is not necessary and may cause a
             // needless overflow.
-            Some(try_opt!(acc.checked_mul(base)))
+            acc.checked_mul(base)
         }
 
         /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index b177e5e3900..93f65c5c7aa 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -990,7 +990,7 @@ macro_rules! uint_impl {
             // squaring the base afterwards is not necessary and may cause a
             // needless overflow.
 
-            Some(try_opt!(acc.checked_mul(base)))
+            acc.checked_mul(base)
         }
 
         /// Saturating integer addition. Computes `self + rhs`, saturating at
@@ -1469,37 +1469,42 @@ macro_rules! uint_impl {
             (a as Self, b)
         }
 
-        /// Calculates `self + rhs + carry` without the ability to overflow.
+        /// Calculates `self` + `rhs` + `carry` and returns a tuple containing
+        /// the sum and the output carry.
         ///
-        /// Performs "ternary addition" which takes in an extra bit to add, and may return an
-        /// additional bit of overflow. This allows for chaining together multiple additions
-        /// to create "big integers" which represent larger values.
+        /// Performs "ternary addition" of two integer operands and a carry-in
+        /// bit, and returns an output integer and a carry-out bit. This allows
+        /// chaining together multiple additions to create a wider addition, and
+        /// can be useful for bignum addition.
         ///
         #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")]
         ///
-        /// # Examples
+        /// If the input carry is false, this method is equivalent to
+        /// [`overflowing_add`](Self::overflowing_add), and the output carry is
+        /// equal to the overflow flag. Note that although carry and overflow
+        /// flags are similar for unsigned integers, they are different for
+        /// signed integers.
         ///
-        /// Basic usage
+        /// # Examples
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (0, true));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
-        #[doc = concat!("assert_eq!(",
-            stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
-            "(", stringify!($SelfT), "::MAX, true));"
-        )]
-        /// ```
         ///
-        /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+        #[doc = concat!("//    3  MAX    (a = 3 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
+        #[doc = concat!("// +  5    7    (b = 5 × 2^", stringify!($BITS), " + 7)")]
+        /// // ---------
+        #[doc = concat!("//    9    6    (sum = 9 × 2^", stringify!($BITS), " + 6)")]
         ///
-        /// ```
-        /// #![feature(bigint_helper_methods)]
-        #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
+        #[doc = concat!("let (a1, a0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (3, ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("let (b1, b0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (5, 7);")]
+        /// let carry0 = false;
+        ///
+        /// let (sum0, carry1) = a0.carrying_add(b0, carry0);
+        /// assert_eq!(carry1, true);
+        /// let (sum1, carry2) = a1.carrying_add(b1, carry1);
+        /// assert_eq!(carry2, false);
+        ///
+        /// assert_eq!((sum1, sum0), (9, 6));
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
@@ -1563,22 +1568,35 @@ macro_rules! uint_impl {
             (a as Self, b)
         }
 
-        /// Calculates `self - rhs - borrow` without the ability to overflow.
+        /// Calculates `self` &minus; `rhs` &minus; `borrow` and returns a tuple
+        /// containing the difference and the output borrow.
         ///
-        /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return
-        /// an additional bit of overflow. This allows for chaining together multiple subtractions
-        /// to create "big integers" which represent larger values.
+        /// Performs "ternary subtraction" by subtracting both an integer
+        /// operand and a borrow-in bit from `self`, and returns an output
+        /// integer and a borrow-out bit. This allows chaining together multiple
+        /// subtractions to create a wider subtraction, and can be useful for
+        /// bignum subtraction.
         ///
         /// # Examples
         ///
-        /// Basic usage
-        ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, true));")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
+        ///
+        #[doc = concat!("//    9    6    (a = 9 × 2^", stringify!($BITS), " + 6)")]
+        #[doc = concat!("// -  5    7    (b = 5 × 2^", stringify!($BITS), " + 7)")]
+        /// // ---------
+        #[doc = concat!("//    3  MAX    (diff = 3 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
+        ///
+        #[doc = concat!("let (a1, a0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (9, 6);")]
+        #[doc = concat!("let (b1, b0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (5, 7);")]
+        /// let borrow0 = false;
+        ///
+        /// let (diff0, borrow1) = a0.borrowing_sub(b0, borrow0);
+        /// assert_eq!(borrow1, true);
+        /// let (diff1, borrow2) = a1.borrowing_sub(b1, borrow1);
+        /// assert_eq!(borrow2, false);
+        ///
+        #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")]
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index 56c5e6cb724..846efbc4ebf 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -83,7 +83,7 @@ impl Alignment {
         unsafe { mem::transmute::<usize, Alignment>(align) }
     }
 
-    /// Returns the alignment as a [`NonZeroUsize`]
+    /// Returns the alignment as a [`usize`]
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
     #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
     #[inline]
@@ -91,7 +91,7 @@ impl Alignment {
         self.0 as usize
     }
 
-    /// Returns the alignment as a [`usize`]
+    /// Returns the alignment as a [`NonZeroUsize`]
     #[unstable(feature = "ptr_alignment_type", issue = "102070")]
     #[inline]
     pub const fn as_nonzero(self) -> NonZeroUsize {
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 8865c834c88..caa10f1818b 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -135,16 +135,16 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
 }
 
 #[repr(C)]
-pub(crate) union PtrRepr<T: ?Sized> {
-    pub(crate) const_ptr: *const T,
-    pub(crate) mut_ptr: *mut T,
-    pub(crate) components: PtrComponents<T>,
+union PtrRepr<T: ?Sized> {
+    const_ptr: *const T,
+    mut_ptr: *mut T,
+    components: PtrComponents<T>,
 }
 
 #[repr(C)]
-pub(crate) struct PtrComponents<T: ?Sized> {
-    pub(crate) data_address: *const (),
-    pub(crate) metadata: <T as Pointee>::Metadata,
+struct PtrComponents<T: ?Sized> {
+    data_address: *const (),
+    metadata: <T as Pointee>::Metadata,
 }
 
 // Manual impl needed to avoid `T: Copy` bound.
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 1f7cf6e5d05..cfffe351a87 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -394,7 +394,6 @@ pub use crate::intrinsics::copy;
 pub use crate::intrinsics::write_bytes;
 
 mod metadata;
-pub(crate) use metadata::PtrRepr;
 #[unstable(feature = "ptr_metadata", issue = "81513")]
 pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
 
@@ -1862,9 +1861,16 @@ macro_rules! maybe_fnptr_doc {
 // Impls for function pointers
 macro_rules! fnptr_impls_safety_abi {
     ($FnTy: ty, $($Arg: ident),*) => {
+        fnptr_impls_safety_abi! { #[stable(feature = "fnptr_impls", since = "1.4.0")] $FnTy, $($Arg),* }
+    };
+    (@c_unwind $FnTy: ty, $($Arg: ident),*) => {
+        #[cfg(not(bootstrap))]
+        fnptr_impls_safety_abi! { #[unstable(feature = "c_unwind", issue = "74990")] $FnTy, $($Arg),* }
+    };
+    (#[$meta:meta] $FnTy: ty, $($Arg: ident),*) => {
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> PartialEq for $FnTy {
                 #[inline]
                 fn eq(&self, other: &Self) -> bool {
@@ -1875,13 +1881,13 @@ macro_rules! fnptr_impls_safety_abi {
 
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> Eq for $FnTy {}
         }
 
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> PartialOrd for $FnTy {
                 #[inline]
                 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -1892,7 +1898,7 @@ macro_rules! fnptr_impls_safety_abi {
 
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> Ord for $FnTy {
                 #[inline]
                 fn cmp(&self, other: &Self) -> Ordering {
@@ -1903,7 +1909,7 @@ macro_rules! fnptr_impls_safety_abi {
 
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> hash::Hash for $FnTy {
                 fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
                     state.write_usize(*self as usize)
@@ -1913,7 +1919,7 @@ macro_rules! fnptr_impls_safety_abi {
 
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     fmt::pointer_fmt_inner(*self as usize, f)
@@ -1923,7 +1929,7 @@ macro_rules! fnptr_impls_safety_abi {
 
         maybe_fnptr_doc! {
             $($Arg)* @
-            #[stable(feature = "fnptr_impls", since = "1.4.0")]
+            #[$meta]
             impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     fmt::pointer_fmt_inner(*self as usize, f)
@@ -1938,16 +1944,22 @@ macro_rules! fnptr_impls_args {
         fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
         fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
         fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
         fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
         fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
         fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
     };
     () => {
         // No variadic functions with 0 parameters
         fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
         fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
+        fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn() -> Ret, }
         fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
         fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, }
+        fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn() -> Ret, }
     };
 }
 
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index bbcc7c699e0..0bb2566fd4c 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -80,10 +80,14 @@ impl<T: ?Sized> *mut T {
     #[unstable(feature = "set_ptr_value", issue = "75091")]
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[inline]
-    pub fn with_metadata_of<U>(self, mut val: *mut U) -> *mut U
+    pub fn with_metadata_of<U>(self, val: *const U) -> *mut U
     where
         U: ?Sized,
     {
+        // Prepare in the type system that we will replace the pointer value with a mutable
+        // pointer, taking the mutable provenance from the `self` pointer.
+        let mut val = val as *mut U;
+        // Pointer to the pointer value within the value.
         let target = &mut val as *mut *mut U as *mut *mut u8;
         // SAFETY: In case of a thin pointer, this operations is identical
         // to a simple assignment. In case of a fat pointer, with the current
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index f3ef094cbcc..7264d57ba6a 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -2,6 +2,7 @@ use crate::cmp::Ordering;
 use crate::convert::From;
 use crate::fmt;
 use crate::hash;
+use crate::intrinsics::assert_unsafe_precondition;
 use crate::marker::Unsize;
 use crate::mem::{self, MaybeUninit};
 use crate::num::NonZeroUsize;
@@ -195,7 +196,10 @@ impl<T: ?Sized> NonNull<T> {
     #[inline]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
         // SAFETY: the caller must guarantee that `ptr` is non-null.
-        unsafe { NonNull { pointer: ptr as _ } }
+        unsafe {
+            assert_unsafe_precondition!([T: ?Sized](ptr: *mut T) => !ptr.is_null());
+            NonNull { pointer: ptr as _ }
+        }
     }
 
     /// Creates a new `NonNull` if `ptr` is non-null.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 56133f346ae..94ab13ed2e0 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -123,18 +123,11 @@ impl<T> [T] {
     #[lang = "slice_len_fn"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")]
+    #[rustc_allow_const_fn_unstable(ptr_metadata)]
     #[inline]
     #[must_use]
-    // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
     pub const fn len(&self) -> usize {
-        // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
-        // As of this writing this causes a "Const-stable functions can only call other
-        // const-stable functions" error.
-
-        // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
-        // and PtrComponents<T> have the same memory layouts. Only std can make this
-        // guarantee.
-        unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
+        ptr::metadata(self)
     }
 
     /// Returns `true` if the slice has a length of 0.
@@ -2359,6 +2352,28 @@ impl<T> [T] {
     /// assert!(match r { Ok(1..=4) => true, _ => false, });
     /// ```
     ///
+    /// If you want to find that whole *range* of matching items, rather than
+    /// an arbitrary matching one, that can be done using [`partition_point`]:
+    /// ```
+    /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+    ///
+    /// let low = s.partition_point(|x| x < &1);
+    /// assert_eq!(low, 1);
+    /// let high = s.partition_point(|x| x <= &1);
+    /// assert_eq!(high, 5);
+    /// let r = s.binary_search(&1);
+    /// assert!((low..high).contains(&r.unwrap()));
+    ///
+    /// assert!(s[..low].iter().all(|&x| x < 1));
+    /// assert!(s[low..high].iter().all(|&x| x == 1));
+    /// assert!(s[high..].iter().all(|&x| x > 1));
+    ///
+    /// // For something not found, the "range" of equal items is empty
+    /// assert_eq!(s.partition_point(|x| x < &11), 9);
+    /// assert_eq!(s.partition_point(|x| x <= &11), 9);
+    /// assert_eq!(s.binary_search(&11), Err(9));
+    /// ```
+    ///
     /// If you want to insert an item to a sorted vector, while maintaining
     /// sort order, consider using [`partition_point`]:
     ///
@@ -3787,6 +3802,16 @@ impl<T> [T] {
     /// assert!(v[i..].iter().all(|&x| !(x < 5)));
     /// ```
     ///
+    /// If all elements of the slice match the predicate, including if the slice
+    /// is empty, then the length of the slice will be returned:
+    ///
+    /// ```
+    /// let a = [2, 4, 8];
+    /// assert_eq!(a.partition_point(|x| x < &100), a.len());
+    /// let a: [i32; 0] = [];
+    /// assert_eq!(a.partition_point(|x| x < &100), 0);
+    /// ```
+    ///
     /// If you want to insert an item to a sorted vector, while maintaining
     /// sort order:
     ///
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index 031fb8e8b21..ec2cb429e67 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -267,7 +267,7 @@ pub unsafe trait Searcher<'a> {
 /// The index ranges returned by this trait are not required
 /// to exactly match those of the forward search in reverse.
 ///
-/// For the reason why this trait is marked unsafe, see them
+/// For the reason why this trait is marked unsafe, see the
 /// parent trait [`Searcher`].
 pub unsafe trait ReverseSearcher<'a>: Searcher<'a> {
     /// Performs the next search step starting from the back.
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index cdc47e17938..edc68d6fae5 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -294,7 +294,7 @@ impl AtomicBool {
     /// ```
     /// use std::sync::atomic::AtomicBool;
     ///
-    /// let atomic_true  = AtomicBool::new(true);
+    /// let atomic_true = AtomicBool::new(true);
     /// let atomic_false = AtomicBool::new(false);
     /// ```
     #[inline]
@@ -1179,7 +1179,7 @@ impl<T> AtomicPtr<T> {
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
     /// let ptr = &mut 5;
-    /// let some_ptr  = AtomicPtr::new(ptr);
+    /// let some_ptr = AtomicPtr::new(ptr);
     ///
     /// let value = some_ptr.load(Ordering::Relaxed);
     /// ```
@@ -1206,7 +1206,7 @@ impl<T> AtomicPtr<T> {
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
     /// let ptr = &mut 5;
-    /// let some_ptr  = AtomicPtr::new(ptr);
+    /// let some_ptr = AtomicPtr::new(ptr);
     ///
     /// let other_ptr = &mut 10;
     ///
@@ -1238,7 +1238,7 @@ impl<T> AtomicPtr<T> {
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
     /// let ptr = &mut 5;
-    /// let some_ptr  = AtomicPtr::new(ptr);
+    /// let some_ptr = AtomicPtr::new(ptr);
     ///
     /// let other_ptr = &mut 10;
     ///
@@ -1290,9 +1290,9 @@ impl<T> AtomicPtr<T> {
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
     /// let ptr = &mut 5;
-    /// let some_ptr  = AtomicPtr::new(ptr);
+    /// let some_ptr = AtomicPtr::new(ptr);
     ///
-    /// let other_ptr   = &mut 10;
+    /// let other_ptr = &mut 10;
     ///
     /// let value = some_ptr.compare_and_swap(ptr, other_ptr, Ordering::Relaxed);
     /// ```
@@ -1333,9 +1333,9 @@ impl<T> AtomicPtr<T> {
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
     /// let ptr = &mut 5;
-    /// let some_ptr  = AtomicPtr::new(ptr);
+    /// let some_ptr = AtomicPtr::new(ptr);
     ///
-    /// let other_ptr   = &mut 10;
+    /// let other_ptr = &mut 10;
     ///
     /// let value = some_ptr.compare_exchange(ptr, other_ptr,
     ///                                       Ordering::SeqCst, Ordering::Relaxed);
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index a698e6e99e1..3012a78b9c9 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -49,8 +49,8 @@
 #![feature(slice_from_ptr_range)]
 #![feature(split_as_slice)]
 #![feature(maybe_uninit_uninit_array)]
-#![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_write_slice)]
+#![feature(maybe_uninit_uninit_array_transpose)]
 #![feature(min_specialization)]
 #![feature(numfmt)]
 #![feature(step_trait)]
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index 6856d1a1f51..0362e1c8afb 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -130,7 +130,11 @@ fn test_transmute_copy_grow_panics() {
             payload
                 .downcast::<&'static str>()
                 .and_then(|s| {
-                    if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) }
+                    if *s == "cannot transmute_copy if Dst is larger than Src" {
+                        Ok(s)
+                    } else {
+                        Err(s)
+                    }
                 })
                 .unwrap_or_else(|p| panic::resume_unwind(p));
         }
@@ -163,18 +167,18 @@ fn assume_init_good() {
 
 #[test]
 fn uninit_array_assume_init() {
-    let mut array: [MaybeUninit<i16>; 5] = MaybeUninit::uninit_array();
+    let mut array = [MaybeUninit::<i16>::uninit(); 5];
     array[0].write(3);
     array[1].write(1);
     array[2].write(4);
     array[3].write(1);
     array[4].write(5);
 
-    let array = unsafe { MaybeUninit::array_assume_init(array) };
+    let array = unsafe { array.transpose().assume_init() };
 
     assert_eq!(array, [3, 1, 4, 1, 5]);
 
-    let [] = unsafe { MaybeUninit::<!>::array_assume_init([]) };
+    let [] = unsafe { [MaybeUninit::<!>::uninit(); 0].transpose().assume_init() };
 }
 
 #[test]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index f9c7d3e172c..8001fcff648 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -546,7 +546,7 @@ impl Span {
     /// Note: The observable result of a macro should only rely on the tokens and
     /// not on this source text. The result of this function is a best effort to
     /// be used for diagnostics only.
-    #[unstable(feature = "proc_macro_span", issue = "54725")]
+    #[stable(feature = "proc_macro_source_text", since = "CURRENT_RUSTC_VERSION")]
     pub fn source_text(&self) -> Option<String> {
         self.0.source_text()
     }
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 34b57c37635..9cb74f951dd 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -325,8 +325,7 @@ impl Backtrace {
     // Capture a backtrace which start just before the function addressed by
     // `ip`
     fn create(ip: usize) -> Backtrace {
-        // SAFETY: We don't attempt to lock this reentrantly.
-        let _lock = unsafe { lock() };
+        let _lock = lock();
         let mut frames = Vec::new();
         let mut actual_start = None;
         unsafe {
@@ -469,8 +468,7 @@ impl Capture {
         // Use the global backtrace lock to synchronize this as it's a
         // requirement of the `backtrace` crate, and then actually resolve
         // everything.
-        // SAFETY: We don't attempt to lock this reentrantly.
-        let _lock = unsafe { lock() };
+        let _lock = lock();
         for frame in self.frames.iter_mut() {
             let symbols = &mut frame.symbols;
             let frame = match &frame.frame {
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index c6c78dc3939..188ff00e1f8 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1365,6 +1365,34 @@ impl FileTimes {
 impl Permissions {
     /// Returns `true` if these permissions describe a readonly (unwritable) file.
     ///
+    /// # Note
+    ///
+    /// This function does not take Access Control Lists (ACLs) or Unix group
+    /// membership into account.
+    ///
+    /// # Windows
+    ///
+    /// On Windows this returns [`FILE_ATTRIBUTE_READONLY`](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants).
+    /// If `FILE_ATTRIBUTE_READONLY` is set then writes to the file will fail
+    /// but the user may still have permission to change this flag. If
+    /// `FILE_ATTRIBUTE_READONLY` is *not* set then writes may still fail due
+    /// to lack of write permission.
+    /// The behavior of this attribute for directories depends on the Windows
+    /// version.
+    ///
+    /// # Unix (including macOS)
+    ///
+    /// On Unix-based platforms this checks if *any* of the owner, group or others
+    /// write permission bits are set. It does not check if the current
+    /// user is in the file's assigned group. It also does not check ACLs.
+    /// Therefore even if this returns true you may not be able to write to the
+    /// file, and vice versa. The [`PermissionsExt`] trait gives direct access
+    /// to the permission bits but also does not read ACLs. If you need to
+    /// accurately know whether or not a file is writable use the `access()`
+    /// function from libc.
+    ///
+    /// [`PermissionsExt`]: crate::os::unix::fs::PermissionsExt
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -1390,8 +1418,40 @@ impl Permissions {
     /// using the resulting `Permission` will update file permissions to allow
     /// writing.
     ///
-    /// This operation does **not** modify the filesystem. To modify the
-    /// filesystem use the [`set_permissions`] function.
+    /// This operation does **not** modify the files attributes. This only
+    /// changes the in-memory value of these attributes for this `Permissions`
+    /// instance. To modify the files attributes use the [`set_permissions`]
+    /// function which commits these attribute changes to the file.
+    ///
+    /// # Note
+    ///
+    /// `set_readonly(false)` makes the file *world-writable* on Unix.
+    /// You can use the [`PermissionsExt`] trait on Unix to avoid this issue.
+    ///
+    /// It also does not take Access Control Lists (ACLs) or Unix group
+    /// membership into account.
+    ///
+    /// # Windows
+    ///
+    /// On Windows this sets or clears [`FILE_ATTRIBUTE_READONLY`](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants).
+    /// If `FILE_ATTRIBUTE_READONLY` is set then writes to the file will fail
+    /// but the user may still have permission to change this flag. If
+    /// `FILE_ATTRIBUTE_READONLY` is *not* set then the write may still fail if
+    /// the user does not have permission to write to the file.
+    ///
+    /// In Windows 7 and earlier this attribute prevents deleting empty
+    /// directories. It does not prevent modifying the directory contents.
+    /// On later versions of Windows this attribute is ignored for directories.
+    ///
+    /// # Unix (including macOS)
+    ///
+    /// On Unix-based platforms this sets or clears the write access bit for
+    /// the owner, group *and* others, equivalent to `chmod a+w <file>`
+    /// or `chmod a-w <file>` respectively. The latter will grant write access
+    /// to all users! You can use the [`PermissionsExt`] trait on Unix
+    /// to avoid this issue.
+    ///
+    /// [`PermissionsExt`]: crate::os::unix::fs::PermissionsExt
     ///
     /// # Examples
     ///
@@ -1405,7 +1465,8 @@ impl Permissions {
     ///
     ///     permissions.set_readonly(true);
     ///
-    ///     // filesystem doesn't change
+    ///     // filesystem doesn't change, only the in memory state of the
+    ///     // readonly permission
     ///     assert_eq!(false, metadata.permissions().readonly());
     ///
     ///     // just this particular `permissions`.
diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs
index d528590d75b..57bd842a50c 100644
--- a/library/std/src/os/wasi/io/mod.rs
+++ b/library/std/src/os/wasi/io/mod.rs
@@ -1,6 +1,6 @@
 //! WASI-specific extensions to general I/O primitives.
 
-#![unstable(feature = "wasi_ext", issue = "71213")]
+#![stable(feature = "io_safety", since = "1.63.0")]
 
-#[unstable(feature = "wasi_ext", issue = "71213")]
+#[stable(feature = "io_safety", since = "1.63.0")]
 pub use crate::os::fd::*;
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index b8249a027ad..400d25beb26 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -2154,8 +2154,16 @@ pub fn id() -> u32 {
 #[cfg_attr(not(test), lang = "termination")]
 #[stable(feature = "termination_trait_lib", since = "1.61.0")]
 #[rustc_on_unimplemented(
-    message = "`main` has invalid return type `{Self}`",
-    label = "`main` can only return types that implement `{Termination}`"
+    on(
+        all(not(bootstrap), cause = "MainFunctionType"),
+        message = "`main` has invalid return type `{Self}`",
+        label = "`main` can only return types that implement `{Termination}`"
+    ),
+    on(
+        bootstrap,
+        message = "`main` has invalid return type `{Self}`",
+        label = "`main` can only return types that implement `{Termination}`"
+    )
 )]
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index b8bcdbece0a..9c2f0c1dd3e 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -89,7 +89,7 @@ macro_rules! rtunwrap {
 // `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe`
 // has a value, but its value is ignored.
 //
-// Even though it is an `u8`, it only ever has 3 values. These are documented in
+// Even though it is an `u8`, it only ever has 4 values. These are documented in
 // `compiler/rustc_session/src/config/sigpipe.rs`.
 #[cfg_attr(test, allow(dead_code))]
 unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs
index 1c7e1dd8d57..afcae6c90ee 100644
--- a/library/std/src/sys/hermit/args.rs
+++ b/library/std/src/sys/hermit/args.rs
@@ -1,20 +1,37 @@
-use crate::ffi::OsString;
+use crate::ffi::{c_char, CStr, OsString};
 use crate::fmt;
+use crate::os::unix::ffi::OsStringExt;
+use crate::ptr;
+use crate::sync::atomic::{
+    AtomicIsize, AtomicPtr,
+    Ordering::{Acquire, Relaxed, Release},
+};
 use crate::vec;
 
+static ARGC: AtomicIsize = AtomicIsize::new(0);
+static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
+
 /// One-time global initialization.
 pub unsafe fn init(argc: isize, argv: *const *const u8) {
-    imp::init(argc, argv)
-}
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() {
-    imp::cleanup()
+    ARGC.store(argc, Relaxed);
+    // Use release ordering here to broadcast writes by the OS.
+    ARGV.store(argv as *mut *const u8, Release);
 }
 
 /// Returns the command line arguments
 pub fn args() -> Args {
-    imp::args()
+    // Synchronize with the store above.
+    let argv = ARGV.load(Acquire);
+    // If argv has not been initialized yet, do not return any arguments.
+    let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) };
+    let args: Vec<OsString> = (0..argc)
+        .map(|i| unsafe {
+            let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char);
+            OsStringExt::from_vec(cstr.to_bytes().to_vec())
+        })
+        .collect();
+
+    Args { iter: args.into_iter() }
 }
 
 pub struct Args {
@@ -51,44 +68,3 @@ impl DoubleEndedIterator for Args {
         self.iter.next_back()
     }
 }
-
-mod imp {
-    use super::Args;
-    use crate::ffi::{CStr, OsString};
-    use crate::os::unix::ffi::OsStringExt;
-    use crate::ptr;
-
-    use crate::sys_common::mutex::StaticMutex;
-
-    static mut ARGC: isize = 0;
-    static mut ARGV: *const *const u8 = ptr::null();
-    static LOCK: StaticMutex = StaticMutex::new();
-
-    pub unsafe fn init(argc: isize, argv: *const *const u8) {
-        let _guard = LOCK.lock();
-        ARGC = argc;
-        ARGV = argv;
-    }
-
-    pub unsafe fn cleanup() {
-        let _guard = LOCK.lock();
-        ARGC = 0;
-        ARGV = ptr::null();
-    }
-
-    pub fn args() -> Args {
-        Args { iter: clone().into_iter() }
-    }
-
-    fn clone() -> Vec<OsString> {
-        unsafe {
-            let _guard = LOCK.lock();
-            (0..ARGC)
-                .map(|i| {
-                    let cstr = CStr::from_ptr(*ARGV.offset(i) as *const i8);
-                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
-                })
-                .collect()
-        }
-    }
-}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 827d82900ea..e6534df8938 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -106,9 +106,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
 
 // SAFETY: must be called only once during runtime cleanup.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
-pub unsafe fn cleanup() {
-    args::cleanup();
-}
+pub unsafe fn cleanup() {}
 
 #[cfg(not(test))]
 #[no_mangle]
diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs
index 9692222534e..6c66b93a3e1 100644
--- a/library/std/src/sys/solid/fs.rs
+++ b/library/std/src/sys/solid/fs.rs
@@ -175,15 +175,19 @@ impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
 
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        unsafe {
-            let mut out_dirent = MaybeUninit::uninit();
-            error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir(
+        let entry = unsafe {
+            let mut out_entry = MaybeUninit::uninit();
+            match error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir(
                 self.inner.dirp,
-                out_dirent.as_mut_ptr(),
-            ))
-            .ok()?;
-            Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) }))
-        }
+                out_entry.as_mut_ptr(),
+            )) {
+                Ok(_) => out_entry.assume_init(),
+                Err(e) if e.as_raw() == abi::SOLID_ERR_NOTFOUND => return None,
+                Err(e) => return Some(Err(e.as_io_error())),
+            }
+        };
+
+        (entry.d_name[0] != 0).then(|| Ok(DirEntry { entry, inner: Arc::clone(&self.inner) }))
     }
 }
 
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 3ac01e6a27d..e22b2f3340a 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -4,6 +4,15 @@ use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "fuchsia",
+    target_os = "redox",
+    target_os = "illumos"
+))]
+use crate::mem::MaybeUninit;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
@@ -584,33 +593,69 @@ impl Iterator for ReadDir {
                     };
                 }
 
-                // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
-                // whole thing (#93384).  Instead, copy everything except the name.
-                let mut copy: dirent64 = mem::zeroed();
-                // Can't dereference entry_ptr, so use the local entry to get
-                // offsetof(struct dirent, d_name)
-                let copy_bytes = &mut copy as *mut _ as *mut u8;
-                let copy_name = &mut copy.d_name as *mut _ as *mut u8;
-                let name_offset = copy_name.offset_from(copy_bytes) as usize;
-                let entry_bytes = entry_ptr as *const u8;
-                let entry_name = entry_bytes.add(name_offset);
-                ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset);
+                // The dirent64 struct is a weird imaginary thing that isn't ever supposed
+                // to be worked with by value. Its trailing d_name field is declared
+                // variously as [c_char; 256] or [c_char; 1] on different systems but
+                // either way that size is meaningless; only the offset of d_name is
+                // meaningful. The dirent64 pointers that libc returns from readdir64 are
+                // allowed to point to allocations smaller _or_ LARGER than implied by the
+                // definition of the struct.
+                //
+                // As such, we need to be even more careful with dirent64 than if its
+                // contents were "simply" partially initialized data.
+                //
+                // Like for uninitialized contents, converting entry_ptr to `&dirent64`
+                // would not be legal. However, unique to dirent64 is that we don't even
+                // get to use `addr_of!((*entry_ptr).d_name)` because that operation
+                // requires the full extent of *entry_ptr to be in bounds of the same
+                // allocation, which is not necessarily the case here.
+                //
+                // Absent any other way to obtain a pointer to `(*entry_ptr).d_name`
+                // legally in Rust analogously to how it would be done in C, we instead
+                // need to make our own non-libc allocation that conforms to the weird
+                // imaginary definition of dirent64, and use that for a field offset
+                // computation.
+                macro_rules! offset_ptr {
+                    ($entry_ptr:expr, $field:ident) => {{
+                        const OFFSET: isize = {
+                            let delusion = MaybeUninit::<dirent64>::uninit();
+                            let entry_ptr = delusion.as_ptr();
+                            unsafe {
+                                ptr::addr_of!((*entry_ptr).$field)
+                                    .cast::<u8>()
+                                    .offset_from(entry_ptr.cast::<u8>())
+                            }
+                        };
+                        if true {
+                            // Cast to the same type determined by the else branch.
+                            $entry_ptr.byte_offset(OFFSET).cast::<_>()
+                        } else {
+                            #[allow(deref_nullptr)]
+                            {
+                                ptr::addr_of!((*ptr::null::<dirent64>()).$field)
+                            }
+                        }
+                    }};
+                }
+
+                // d_name is guaranteed to be null-terminated.
+                let name = CStr::from_ptr(offset_ptr!(entry_ptr, d_name).cast());
+                let name_bytes = name.to_bytes();
+                if name_bytes == b"." || name_bytes == b".." {
+                    continue;
+                }
 
                 let entry = dirent64_min {
-                    d_ino: copy.d_ino as u64,
+                    d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
                     #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
-                    d_type: copy.d_type as u8,
+                    d_type: *offset_ptr!(entry_ptr, d_type) as u8,
                 };
 
-                let ret = DirEntry {
+                return Some(Ok(DirEntry {
                     entry,
-                    // d_name is guaranteed to be null-terminated.
-                    name: CStr::from_ptr(entry_name as *const _).to_owned(),
+                    name: name.to_owned(),
                     dir: Arc::clone(&self.inner),
-                };
-                if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
-                    return Some(Ok(ret));
-                }
+                }));
             }
         }
     }
@@ -674,7 +719,10 @@ impl DirEntry {
         self.file_name_os_str().to_os_string()
     }
 
-    #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+    #[cfg(all(
+        any(target_os = "linux", target_os = "emscripten", target_os = "android"),
+        not(miri)
+    ))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
         let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
         let name = self.name_cstr().as_ptr();
@@ -695,7 +743,10 @@ impl DirEntry {
         Ok(FileAttr::from_stat64(stat))
     }
 
-    #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))]
+    #[cfg(any(
+        not(any(target_os = "linux", target_os = "emscripten", target_os = "android")),
+        miri
+    ))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
         lstat(&self.path())
     }
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index c84e292eac1..4a9f356b63c 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -163,17 +163,27 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
             // See the other file for docs. NOTE: Make sure to keep them in
             // sync!
             mod sigpipe {
+                pub const DEFAULT: u8 = 0;
                 pub const INHERIT: u8 = 1;
                 pub const SIG_IGN: u8 = 2;
                 pub const SIG_DFL: u8 = 3;
             }
 
-            let handler = match sigpipe {
-                sigpipe::INHERIT => None,
-                sigpipe::SIG_IGN => Some(libc::SIG_IGN),
-                sigpipe::SIG_DFL => Some(libc::SIG_DFL),
+            let (sigpipe_attr_specified, handler) = match sigpipe {
+                sigpipe::DEFAULT => (false, Some(libc::SIG_IGN)),
+                sigpipe::INHERIT => (true, None),
+                sigpipe::SIG_IGN => (true, Some(libc::SIG_IGN)),
+                sigpipe::SIG_DFL => (true, Some(libc::SIG_DFL)),
                 _ => unreachable!(),
             };
+            // The bootstrap compiler doesn't know about sigpipe::DEFAULT, and always passes in
+            // SIG_IGN. This causes some tests to fail because they expect SIGPIPE to be reset to
+            // default on process spawning (which doesn't happen if #[unix_sigpipe] is specified).
+            // Since we can't differentiate between the cases here, treat SIG_IGN as DEFAULT
+            // unconditionally.
+            if sigpipe_attr_specified && !(cfg!(bootstrap) && sigpipe == sigpipe::SIG_IGN) {
+                UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
+            }
             if let Some(handler) = handler {
                 rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
             }
@@ -181,6 +191,26 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     }
 }
 
+// This is set (up to once) in reset_sigpipe.
+#[cfg(not(any(
+    target_os = "espidf",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_os = "horizon"
+)))]
+static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
+    crate::sync::atomic::AtomicBool::new(false);
+
+#[cfg(not(any(
+    target_os = "espidf",
+    target_os = "emscripten",
+    target_os = "fuchsia",
+    target_os = "horizon"
+)))]
+pub(crate) fn unix_sigpipe_attr_specified() -> bool {
+    UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed)
+}
+
 // SAFETY: must be called only once during runtime cleanup.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
 pub unsafe fn cleanup() {
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 2834ee0ace8..848adca78c0 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -39,10 +39,12 @@ cfg_if::cfg_if! {
 // https://github.com/aosp-mirror/platform_bionic/blob/ad8dcd6023294b646e5a8288c0ed431b0845da49/libc/include/android/legacy_signal_inlines.h
 cfg_if::cfg_if! {
     if #[cfg(target_os = "android")] {
+        #[allow(dead_code)]
         pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
             set.write_bytes(0u8, 1);
             return 0;
         }
+
         #[allow(dead_code)]
         pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
             use crate::{
diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs
index d176b3401c0..03631e4e33b 100644
--- a/library/std/src/sys/unix/process/process_common/tests.rs
+++ b/library/std/src/sys/unix/process/process_common/tests.rs
@@ -31,41 +31,54 @@ macro_rules! t {
     ignore
 )]
 fn test_process_mask() {
-    unsafe {
-        // Test to make sure that a signal mask does not get inherited.
-        let mut cmd = Command::new(OsStr::new("cat"));
-
-        let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
-        let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
-        t!(cvt(sigemptyset(set.as_mut_ptr())));
-        t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
-        t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
-
-        cmd.stdin(Stdio::MakePipe);
-        cmd.stdout(Stdio::MakePipe);
-
-        let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
-        let stdin_write = pipes.stdin.take().unwrap();
-        let stdout_read = pipes.stdout.take().unwrap();
-
-        t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
-
-        t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
-        // We need to wait until SIGINT is definitely delivered. The
-        // easiest way is to write something to cat, and try to read it
-        // back: if SIGINT is unmasked, it'll get delivered when cat is
-        // next scheduled.
-        let _ = stdin_write.write(b"Hello");
-        drop(stdin_write);
-
-        // Either EOF or failure (EPIPE) is okay.
-        let mut buf = [0; 5];
-        if let Ok(ret) = stdout_read.read(&mut buf) {
-            assert_eq!(ret, 0);
+    // Test to make sure that a signal mask *does* get inherited.
+    fn test_inner(mut cmd: Command) {
+        unsafe {
+            let mut set = mem::MaybeUninit::<libc::sigset_t>::uninit();
+            let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
+            t!(cvt(sigemptyset(set.as_mut_ptr())));
+            t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
+            t!(cvt_nz(libc::pthread_sigmask(
+                libc::SIG_SETMASK,
+                set.as_ptr(),
+                old_set.as_mut_ptr()
+            )));
+
+            cmd.stdin(Stdio::MakePipe);
+            cmd.stdout(Stdio::MakePipe);
+
+            let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
+            let stdin_write = pipes.stdin.take().unwrap();
+            let stdout_read = pipes.stdout.take().unwrap();
+
+            t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
+
+            t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
+            // We need to wait until SIGINT is definitely delivered. The
+            // easiest way is to write something to cat, and try to read it
+            // back: if SIGINT is unmasked, it'll get delivered when cat is
+            // next scheduled.
+            let _ = stdin_write.write(b"Hello");
+            drop(stdin_write);
+
+            // Exactly 5 bytes should be read.
+            let mut buf = [0; 5];
+            let ret = t!(stdout_read.read(&mut buf));
+            assert_eq!(ret, 5);
+            assert_eq!(&buf, b"Hello");
+
+            t!(cat.wait());
         }
-
-        t!(cat.wait());
     }
+
+    // A plain `Command::new` uses the posix_spawn path on many platforms.
+    let cmd = Command::new(OsStr::new("cat"));
+    test_inner(cmd);
+
+    // Specifying `pre_exec` forces the fork/exec path.
+    let mut cmd = Command::new(OsStr::new("cat"));
+    unsafe { cmd.pre_exec(Box::new(|| Ok(()))) };
+    test_inner(cmd);
 }
 
 #[test]
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 2ff8e600f7c..56a805cef73 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -2,7 +2,6 @@ use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::mem;
 use crate::num::NonZeroI32;
-use crate::ptr;
 use crate::sys;
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
@@ -310,7 +309,7 @@ impl Command {
                 //FIXME: Redox kernel does not support setgroups yet
                 #[cfg(not(target_os = "redox"))]
                 if libc::getuid() == 0 && self.get_groups().is_none() {
-                    cvt(libc::setgroups(0, ptr::null()))?;
+                    cvt(libc::setgroups(0, crate::ptr::null()))?;
                 }
                 cvt(libc::setuid(u as uid_t))?;
             }
@@ -326,30 +325,26 @@ impl Command {
         // emscripten has no signal support.
         #[cfg(not(target_os = "emscripten"))]
         {
-            use crate::mem::MaybeUninit;
-            use crate::sys::cvt_nz;
-            // Reset signal handling so the child process starts in a
-            // standardized state. libstd ignores SIGPIPE, and signal-handling
-            // libraries often set a mask. Child processes inherit ignored
-            // signals and the signal mask from their parent, but most
-            // UNIX programs do not reset these things on their own, so we
-            // need to clean things up now to avoid confusing the program
-            // we're about to run.
-            let mut set = MaybeUninit::<libc::sigset_t>::uninit();
-            cvt(sigemptyset(set.as_mut_ptr()))?;
-            cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?;
-
-            #[cfg(target_os = "android")] // see issue #88585
-            {
-                let mut action: libc::sigaction = mem::zeroed();
-                action.sa_sigaction = libc::SIG_DFL;
-                cvt(libc::sigaction(libc::SIGPIPE, &action, ptr::null_mut()))?;
-            }
-            #[cfg(not(target_os = "android"))]
-            {
-                let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
-                if ret == libc::SIG_ERR {
-                    return Err(io::Error::last_os_error());
+            // Inherit the signal mask from the parent rather than resetting it (i.e. do not call
+            // pthread_sigmask).
+
+            // If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
+            // If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
+            //
+            // #[unix_sigpipe] is an opportunity to change the default here.
+            if !crate::sys::unix_sigpipe_attr_specified() {
+                #[cfg(target_os = "android")] // see issue #88585
+                {
+                    let mut action: libc::sigaction = mem::zeroed();
+                    action.sa_sigaction = libc::SIG_DFL;
+                    cvt(libc::sigaction(libc::SIGPIPE, &action, crate::ptr::null_mut()))?;
+                }
+                #[cfg(not(target_os = "android"))]
+                {
+                    let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL);
+                    if ret == libc::SIG_ERR {
+                        return Err(io::Error::last_os_error());
+                    }
                 }
             }
         }
@@ -411,7 +406,7 @@ impl Command {
         envp: Option<&CStringArray>,
     ) -> io::Result<Option<Process>> {
         use crate::mem::MaybeUninit;
-        use crate::sys::{self, cvt_nz};
+        use crate::sys::{self, cvt_nz, unix_sigpipe_attr_specified};
 
         if self.get_gid().is_some()
             || self.get_uid().is_some()
@@ -531,13 +526,24 @@ impl Command {
                 cvt_nz(libc::posix_spawnattr_setpgroup(attrs.0.as_mut_ptr(), pgroup))?;
             }
 
-            let mut set = MaybeUninit::<libc::sigset_t>::uninit();
-            cvt(sigemptyset(set.as_mut_ptr()))?;
-            cvt_nz(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?;
-            cvt(sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?;
-            cvt_nz(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?;
+            // Inherit the signal mask from this process rather than resetting it (i.e. do not call
+            // posix_spawnattr_setsigmask).
+
+            // If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
+            // If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
+            //
+            // #[unix_sigpipe] is an opportunity to change the default here.
+            if !unix_sigpipe_attr_specified() {
+                let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
+                cvt(sigemptyset(default_set.as_mut_ptr()))?;
+                cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
+                cvt_nz(libc::posix_spawnattr_setsigdefault(
+                    attrs.0.as_mut_ptr(),
+                    default_set.as_ptr(),
+                ))?;
+                flags |= libc::POSIX_SPAWN_SETSIGDEF;
+            }
 
-            flags |= libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK;
             cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 917fc8e4995..be6fc2ebb7a 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -129,6 +129,8 @@ pub const FIONBIO: c_ulong = 0x8004667e;
 
 pub const MAX_PATH: usize = 260;
 
+pub const FILE_TYPE_PIPE: u32 = 3;
+
 #[repr(C)]
 #[derive(Copy)]
 pub struct WIN32_FIND_DATAW {
@@ -1114,6 +1116,7 @@ extern "system" {
         lpFileInformation: LPVOID,
         dwBufferSize: DWORD,
     ) -> BOOL;
+    pub fn GetFileType(hfile: HANDLE) -> DWORD;
     pub fn SleepConditionVariableSRW(
         ConditionVariable: PCONDITION_VARIABLE,
         SRWLock: PSRWLOCK,
diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs
index 0879ef19933..2cc34c986b9 100644
--- a/library/std/src/sys/windows/io.rs
+++ b/library/std/src/sys/windows/io.rs
@@ -120,6 +120,11 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
 }
 
 unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
+    // Early return if the handle is not a pipe.
+    if c::GetFileType(handle) != c::FILE_TYPE_PIPE {
+        return false;
+    }
+
     const SIZE: usize = size_of::<c::FILE_NAME_INFO>() + c::MAX_PATH * size_of::<c::WCHAR>();
     let mut name_info_bytes = Align8([0u8; SIZE]);
     let res = c::GetFileInformationByHandleEx(
@@ -137,11 +142,13 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
     let name_ptr = name_info_bytes.0.as_ptr().offset(size_of::<c::DWORD>() as isize).cast::<u16>();
     let s = core::slice::from_raw_parts(name_ptr, name_len);
     let name = String::from_utf16_lossy(s);
+    // Get the file name only.
+    let name = name.rsplit('\\').next().unwrap_or(&name);
     // This checks whether 'pty' exists in the file name, which indicates that
     // a pseudo-terminal is attached. To mitigate against false positives
     // (e.g., an actual file name that contains 'pty'), we also require that
-    // either the strings 'msys-' or 'cygwin-' are in the file name as well.)
-    let is_msys = name.contains("msys-") || name.contains("cygwin-");
+    // the file name begins with either the strings 'msys-' or 'cygwin-'.)
+    let is_msys = name.starts_with("msys-") || name.starts_with("cygwin-");
     let is_pty = name.contains("-pty");
     is_msys && is_pty
 }
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 02d5af4719a..9cbb4ef19e9 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -16,6 +16,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
+use crate::sync::Mutex;
 use crate::sys::args::{self, Arg};
 use crate::sys::c;
 use crate::sys::c::NonZeroDWORD;
@@ -25,7 +26,6 @@ use crate::sys::handle::Handle;
 use crate::sys::path;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
-use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::sys_common::IntoInner;
 
@@ -301,9 +301,9 @@ impl Command {
         //
         // For more information, msdn also has an article about this race:
         // https://support.microsoft.com/kb/315939
-        static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
+        static CREATE_PROCESS_LOCK: Mutex<()> = Mutex::new(());
 
-        let _guard = unsafe { CREATE_PROCESS_LOCK.lock() };
+        let _guard = CREATE_PROCESS_LOCK.lock();
 
         let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
         let null = Stdio::Null;
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index 31164afdc7b..8807077cb49 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -7,15 +7,14 @@ use crate::fmt;
 use crate::io;
 use crate::io::prelude::*;
 use crate::path::{self, Path, PathBuf};
-use crate::sys_common::mutex::StaticMutex;
+use crate::sync::{Mutex, PoisonError};
 
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
-// SAFETY: Don't attempt to lock this reentrantly.
-pub unsafe fn lock() -> impl Drop {
-    static LOCK: StaticMutex = StaticMutex::new();
-    LOCK.lock()
+pub fn lock() -> impl Drop {
+    static LOCK: Mutex<()> = Mutex::new(());
+    LOCK.lock().unwrap_or_else(PoisonError::into_inner)
 }
 
 /// Prints the current backtrace.
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
index 7b9f7ef5487..98046f20f89 100644
--- a/library/std/src/sys_common/mutex.rs
+++ b/library/std/src/sys_common/mutex.rs
@@ -1,49 +1,5 @@
 use crate::sys::locks as imp;
 
-/// An OS-based mutual exclusion lock, meant for use in static variables.
-///
-/// This mutex has a const constructor ([`StaticMutex::new`]), does not
-/// implement `Drop` to cleanup resources, and causes UB when used reentrantly.
-///
-/// This mutex does not implement poisoning.
-///
-/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
-/// `destroy()`.
-pub struct StaticMutex(imp::Mutex);
-
-unsafe impl Sync for StaticMutex {}
-
-impl StaticMutex {
-    /// Creates a new mutex for use.
-    #[inline]
-    pub const fn new() -> Self {
-        Self(imp::Mutex::new())
-    }
-
-    /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
-    /// will be unlocked.
-    ///
-    /// It is undefined behaviour to call this function while locked by the
-    /// same thread.
-    #[inline]
-    pub unsafe fn lock(&'static self) -> StaticMutexGuard {
-        self.0.lock();
-        StaticMutexGuard(&self.0)
-    }
-}
-
-#[must_use]
-pub struct StaticMutexGuard(&'static imp::Mutex);
-
-impl Drop for StaticMutexGuard {
-    #[inline]
-    fn drop(&mut self) {
-        unsafe {
-            self.0.unlock();
-        }
-    }
-}
-
 /// An OS-based mutual exclusion lock.
 ///
 /// This mutex cleans up its resources in its `Drop` implementation, may safely
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 5d4a236bd2c..05023df1bb2 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1128,24 +1128,21 @@ impl ThreadId {
                     }
                 }
             } else {
-                use crate::sys_common::mutex::StaticMutex;
+                use crate::sync::{Mutex, PoisonError};
 
-                // It is UB to attempt to acquire this mutex reentrantly!
-                static GUARD: StaticMutex = StaticMutex::new();
-                static mut COUNTER: u64 = 0;
+                static COUNTER: Mutex<u64> = Mutex::new(0);
 
-                unsafe {
-                    let guard = GUARD.lock();
+                let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
+                let Some(id) = counter.checked_add(1) else {
+                    // in case the panic handler ends up calling `ThreadId::new()`,
+                    // avoid reentrant lock acquire.
+                    drop(counter);
+                    exhausted();
+                };
 
-                    let Some(id) = COUNTER.checked_add(1) else {
-                        drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
-                        exhausted();
-                    };
-
-                    COUNTER = id;
-                    drop(guard);
-                    ThreadId(NonZeroU64::new(id).unwrap())
-                }
+                *counter = id;
+                drop(counter);
+                ThreadId(NonZeroU64::new(id).unwrap())
             }
         }
     }
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index c7c413da060..34e18b5fa87 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -356,7 +356,7 @@ impl Instant {
     ///
     /// # Panics
     ///
-    /// Previous rust versions panicked when self was earlier than the current time. Currently this
+    /// Previous rust versions panicked when the current time was earlier than self. Currently this
     /// method returns a Duration of zero in that case. Future versions may reintroduce the panic.
     /// See [Monotonicity].
     ///
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index e9dda98966d..b1270c27271 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -147,7 +147,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
     let mut ntest = 0;
     let mut nbench = 0;
 
-    for test in filter_tests(&opts, tests) {
+    for test in filter_tests(&opts, tests).into_iter() {
         use crate::TestFn::*;
 
         let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index b1e0bbfc591..4de69455798 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -247,7 +247,7 @@ where
     let event = TestEvent::TeFiltered(filtered_descs, shuffle_seed);
     notify_about_test_event(event)?;
 
-    let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
+    let (mut filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
         .into_iter()
         .enumerate()
         .map(|(i, e)| (TestId(i), e))
@@ -255,12 +255,12 @@ where
 
     let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
 
-    let mut remaining = filtered_tests;
     if let Some(shuffle_seed) = shuffle_seed {
-        shuffle_tests(shuffle_seed, &mut remaining);
-    } else {
-        remaining.reverse();
+        shuffle_tests(shuffle_seed, &mut filtered_tests);
     }
+    // Store the tests in a VecDeque so we can efficiently remove the first element to run the
+    // tests in the order they were passed (unless shuffled).
+    let mut remaining = VecDeque::from(filtered_tests);
     let mut pending = 0;
 
     let (tx, rx) = channel::<CompletedTest>();
@@ -300,7 +300,7 @@ where
 
     if concurrency == 1 {
         while !remaining.is_empty() {
-            let (id, test) = remaining.pop().unwrap();
+            let (id, test) = remaining.pop_front().unwrap();
             let event = TestEvent::TeWait(test.desc.clone());
             notify_about_test_event(event)?;
             let join_handle =
@@ -314,7 +314,7 @@ where
     } else {
         while pending > 0 || !remaining.is_empty() {
             while pending < concurrency && !remaining.is_empty() {
-                let (id, test) = remaining.pop().unwrap();
+                let (id, test) = remaining.pop_front().unwrap();
                 let timeout = time::get_default_test_timeout();
                 let desc = test.desc.clone();
 
@@ -426,9 +426,6 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescA
         RunIgnored::No => {}
     }
 
-    // Sort the tests alphabetically
-    filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice()));
-
     filtered
 }
 
diff --git a/library/test/src/term.rs b/library/test/src/term.rs
index b256ab7b8f8..a14b0d4f5a9 100644
--- a/library/test/src/term.rs
+++ b/library/test/src/term.rs
@@ -39,7 +39,7 @@ pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> {
 pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> {
     TerminfoTerminal::new(io::stdout())
         .map(|t| Box::new(t) as Box<StdoutTerminal>)
-        .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
+        .or_else(|| Some(Box::new(WinConsole::new(io::stdout())) as Box<StdoutTerminal>))
 }
 
 /// Terminal color definitions
diff --git a/library/test/src/term/win.rs b/library/test/src/term/win.rs
index 4bdbd6ee75f..55020141a82 100644
--- a/library/test/src/term/win.rs
+++ b/library/test/src/term/win.rs
@@ -113,8 +113,7 @@ impl<T: Write + Send + 'static> WinConsole<T> {
         }
     }
 
-    /// Returns `None` whenever the terminal cannot be created for some reason.
-    pub(crate) fn new(out: T) -> io::Result<WinConsole<T>> {
+    pub(crate) fn new(out: T) -> WinConsole<T> {
         use std::mem::MaybeUninit;
 
         let fg;
@@ -132,13 +131,13 @@ impl<T: Write + Send + 'static> WinConsole<T> {
                 bg = color::BLACK;
             }
         }
-        Ok(WinConsole {
+        WinConsole {
             buf: out,
             def_foreground: fg,
             def_background: bg,
             foreground: fg,
             background: bg,
-        })
+        }
     }
 }
 
diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs
index 278cfb15bb1..b54be64efcf 100644
--- a/library/test/src/tests.rs
+++ b/library/test/src/tests.rs
@@ -611,33 +611,6 @@ fn sample_tests() -> Vec<TestDescAndFn> {
 }
 
 #[test]
-pub fn sort_tests() {
-    let mut opts = TestOpts::new();
-    opts.run_tests = true;
-
-    let tests = sample_tests();
-    let filtered = filter_tests(&opts, tests);
-
-    let expected = vec![
-        "isize::test_pow".to_string(),
-        "isize::test_to_str".to_string(),
-        "sha1::test".to_string(),
-        "test::do_not_run_ignored_tests".to_string(),
-        "test::filter_for_ignored_option".to_string(),
-        "test::first_free_arg_should_be_a_filter".to_string(),
-        "test::ignored_tests_result_in_ignored".to_string(),
-        "test::parse_ignored_flag".to_string(),
-        "test::parse_include_ignored_flag".to_string(),
-        "test::run_include_ignored_option".to_string(),
-        "test::sort_tests".to_string(),
-    ];
-
-    for (a, b) in expected.iter().zip(filtered) {
-        assert_eq!(*a, b.desc.name.to_string());
-    }
-}
-
-#[test]
 pub fn shuffle_tests() {
     let mut opts = TestOpts::new();
     opts.shuffle = true;
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 4ccdabe4bb6..e02a10b8164 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -21,7 +21,7 @@ use serde::Deserialize;
 use crate::builder::Cargo;
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
-use crate::config::{LlvmLibunwind, TargetSelection};
+use crate::config::{LlvmLibunwind, RustcLto, TargetSelection};
 use crate::dist;
 use crate::native;
 use crate::tool::SourceType;
@@ -701,6 +701,28 @@ impl Step for Rustc {
             ));
         }
 
+        // cfg(bootstrap): remove if condition once the bootstrap compiler supports dylib LTO
+        if compiler.stage != 0 {
+            match builder.config.rust_lto {
+                RustcLto::Thin | RustcLto::Fat => {
+                    // Since using LTO for optimizing dylibs is currently experimental,
+                    // we need to pass -Zdylib-lto.
+                    cargo.rustflag("-Zdylib-lto");
+                    // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when
+                    // compiling dylibs (and their dependencies), even when LTO is enabled for the
+                    // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here.
+                    let lto_type = match builder.config.rust_lto {
+                        RustcLto::Thin => "thin",
+                        RustcLto::Fat => "fat",
+                        _ => unreachable!(),
+                    };
+                    cargo.rustflag(&format!("-Clto={}", lto_type));
+                    cargo.rustflag("-Cembed-bitcode=yes");
+                }
+                RustcLto::ThinLocal => { /* Do nothing, this is the default */ }
+            }
+        }
+
         builder.info(&format!(
             "Building stage{} compiler artifacts ({} -> {})",
             compiler.stage, &compiler.host, target
@@ -1155,6 +1177,20 @@ impl Step for Sysroot {
                 );
             }
         }
+        // Same for the rustc-src component.
+        let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src");
+        t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc));
+        let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust");
+        if let Err(e) =
+            symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_rustcsrc_rust)
+        {
+            eprintln!(
+                "warning: creating symbolic link `{}` to `{}` failed with {}",
+                sysroot_lib_rustlib_rustcsrc_rust.display(),
+                builder.src.display(),
+                e,
+            );
+        }
 
         INTERNER.intern_path(sysroot)
     }
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 635823b958b..a8c403675d8 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -158,6 +158,7 @@ pub struct Config {
     pub rust_new_symbol_mangling: Option<bool>,
     pub rust_profile_use: Option<String>,
     pub rust_profile_generate: Option<String>,
+    pub rust_lto: RustcLto,
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
     pub llvm_libunwind_default: Option<LlvmLibunwind>,
@@ -319,6 +320,28 @@ impl SplitDebuginfo {
     }
 }
 
+/// LTO mode used for compiling rustc itself.
+#[derive(Default, Clone)]
+pub enum RustcLto {
+    #[default]
+    ThinLocal,
+    Thin,
+    Fat,
+}
+
+impl std::str::FromStr for RustcLto {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "thin-local" => Ok(RustcLto::ThinLocal),
+            "thin" => Ok(RustcLto::Thin),
+            "fat" => Ok(RustcLto::Fat),
+            _ => Err(format!("Invalid value for rustc LTO: {}", s)),
+        }
+    }
+}
+
 #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct TargetSelection {
     pub triple: Interned<String>,
@@ -726,6 +749,7 @@ define_config! {
         profile_use: Option<String> = "profile-use",
         // ignored; this is set from an env var set by bootstrap.py
         download_rustc: Option<StringOrBool> = "download-rustc",
+        lto: Option<String> = "lto",
     }
 }
 
@@ -1173,6 +1197,12 @@ impl Config {
             config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
             config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
             config.download_rustc_commit = download_ci_rustc_commit(&config, rust.download_rustc);
+
+            config.rust_lto = rust
+                .lto
+                .as_deref()
+                .map(|value| RustcLto::from_str(value).unwrap())
+                .unwrap_or_default();
         } else {
             config.rust_profile_use = flags.rust_profile_use;
             config.rust_profile_generate = flags.rust_profile_generate;
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index d6e7f787270..eec74b2675a 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -698,7 +698,7 @@ pub struct RustAnalyzer {
 impl Step for RustAnalyzer {
     type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
-    const ONLY_HOSTS: bool = false;
+    const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
@@ -742,7 +742,7 @@ pub struct RustAnalyzerProcMacroSrv {
 impl Step for RustAnalyzerProcMacroSrv {
     type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
-    const ONLY_HOSTS: bool = false;
+    const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 38629c4fae7..ea236bee563 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -250,6 +250,92 @@ For targets: `i586-unknown-linux-gnu`
 (\*) Compressed debug is enabled by default for gas (assembly) on Linux/x86 targets,
      but that makes our `compiler_builtins` incompatible with binutils < 2.32.
 
+### `mips-linux-gnu.config`
+
+For targets: `mips-unknown-linux-gnu`
+
+- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
+- Path and misc options > Patches origin = Bundled, then local
+- Path and misc options > Local patch directory = /tmp/patches
+- Target options > Target Architecture = mips
+- Target options > ABI = o32
+- Target options > Endianness = Big endian
+- Target options > Bitness = 32-bit
+- Target options > Architecture level = mips32r2
+- Operating System > Target OS = linux
+- Operating System > Linux kernel version = 4.4.174
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.23
+- C compiler > gcc version = 8.3.0
+- C compiler > gcc extra config = --with-fp-32=xx --with-odd-spreg-32=no
+- C compiler > C++ = ENABLE -- to cross compile LLVM
+
+### `mipsel-linux-gnu.config`
+
+For targets: `mipsel-unknown-linux-gnu`
+
+- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
+- Path and misc options > Patches origin = Bundled, then local
+- Path and misc options > Local patch directory = /tmp/patches
+- Target options > Target Architecture = mips
+- Target options > ABI = o32
+- Target options > Endianness = Little endian
+- Target options > Bitness = 32-bit
+- Target options > Architecture level = mips32r2
+- Operating System > Target OS = linux
+- Operating System > Linux kernel version = 4.4.174
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.23
+- C compiler > gcc version = 8.3.0
+- C compiler > gcc extra config = --with-fp-32=xx --with-odd-spreg-32=no
+- C compiler > C++ = ENABLE -- to cross compile LLVM
+
+### `mips64-linux-gnu.config`
+
+For targets: `mips64-unknown-linux-gnuabi64`
+
+- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
+- Path and misc options > Patches origin = Bundled, then local
+- Path and misc options > Local patch directory = /tmp/patches
+- Target options > Target Architecture = mips
+- Target options > ABI = n64
+- Target options > Endianness = Big endian
+- Target options > Bitness = 64-bit
+- Target options > Architecture level = mips64r2
+- Operating System > Target OS = linux
+- Operating System > Linux kernel version = 4.4.174
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.23
+- C compiler > gcc version = 8.3.0
+- C compiler > C++ = ENABLE -- to cross compile LLVM
+
+### `mips64el-linux-gnu.config`
+
+For targets: `mips64el-unknown-linux-gnuabi64`
+
+- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
+- Path and misc options > Patches origin = Bundled, then local
+- Path and misc options > Local patch directory = /tmp/patches
+- Target options > Target Architecture = mips
+- Target options > ABI = n64
+- Target options > Endianness = Little endian
+- Target options > Bitness = 64-bit
+- Target options > Architecture level = mips64r2
+- Operating System > Target OS = linux
+- Operating System > Linux kernel version = 4.4.174
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.23
+- C compiler > gcc version = 8.3.0
+- C compiler > C++ = ENABLE -- to cross compile LLVM
+
 ### `powerpc-linux-gnu.config`
 
 For targets: `powerpc-unknown-linux-gnu`
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
index 948fa40dd4b..eb511b32107 100644
--- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
@@ -1,31 +1,30 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils \
-  g++-mips-linux-gnu \
-  libssl-dev \
-  pkg-config
+FROM ubuntu:22.04
 
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+WORKDIR /tmp
+
+COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
+COPY host-x86_64/dist-mips-linux/mips-linux-gnu.config host-x86_64/dist-mips-linux/build-mips-toolchain.sh /tmp/
+RUN su rustbuild -c ./build-mips-toolchain.sh
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
+ENV PATH=$PATH:/x-tools/mips-unknown-linux-gnu/bin
+
+ENV \
+    CC_mips_unknown_linux_gnu=mips-unknown-linux-gnu-gcc \
+    AR_mips_unknown_linux_gnu=mips-unknown-linux-gnu-ar \
+    CXX_mips_unknown_linux_gnu=mips-unknown-linux-gnu-g++
 
 ENV HOSTS=mips-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/build-mips-toolchain.sh b/src/ci/docker/host-x86_64/dist-mips-linux/build-mips-toolchain.sh
new file mode 100755
index 00000000000..32612cf6852
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/build-mips-toolchain.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../mips-linux-gnu.config .config
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.config b/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.config
new file mode 100644
index 00000000000..575584ef0cf
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.config
@@ -0,0 +1,740 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
+CT_MODULES=y
+
+#
+# Paths and misc options
+#
+
+#
+# crosstool-NG behavior
+#
+# CT_OBSOLETE is not set
+# CT_EXPERIMENTAL is not set
+# CT_DEBUG_CT is not set
+
+#
+# Paths
+#
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
+CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_RM_RF_PREFIX_DIR=y
+CT_REMOVE_DOCS=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
+CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
+# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
+
+#
+# Downloading
+#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
+# CT_FORBID_DOWNLOAD is not set
+# CT_FORCE_DOWNLOAD is not set
+CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
+# CT_ONLY_DOWNLOAD is not set
+CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
+
+#
+# Extracting
+#
+# CT_FORCE_EXTRACT is not set
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
+# CT_ONLY_EXTRACT is not set
+# CT_PATCH_BUNDLED is not set
+CT_PATCH_BUNDLED_LOCAL=y
+CT_PATCH_ORDER="bundled,local"
+CT_PATCH_USE_LOCAL=y
+CT_LOCAL_PATCH_DIR="/tmp/patches"
+
+#
+# Build behavior
+#
+CT_PARALLEL_JOBS=0
+CT_LOAD=""
+CT_USE_PIPES=y
+CT_EXTRA_CFLAGS_FOR_BUILD=""
+CT_EXTRA_LDFLAGS_FOR_BUILD=""
+CT_EXTRA_CFLAGS_FOR_HOST=""
+CT_EXTRA_LDFLAGS_FOR_HOST=""
+# CT_CONFIG_SHELL_SH is not set
+# CT_CONFIG_SHELL_ASH is not set
+CT_CONFIG_SHELL_BASH=y
+# CT_CONFIG_SHELL_CUSTOM is not set
+CT_CONFIG_SHELL="${bash}"
+
+#
+# Logging
+#
+# CT_LOG_ERROR is not set
+# CT_LOG_WARN is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
+# CT_LOG_ALL is not set
+# CT_LOG_DEBUG is not set
+CT_LOG_LEVEL_MAX="EXTRA"
+# CT_LOG_SEE_TOOLS_WARN is not set
+CT_LOG_PROGRESS_BAR=y
+CT_LOG_TO_FILE=y
+CT_LOG_FILE_COMPRESS=y
+
+#
+# Target options
+#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+CT_ARCH_MIPS=y
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
+CT_ARCH="mips"
+CT_ARCH_CHOICE_KSYM="MIPS"
+CT_ARCH_TUNE=""
+CT_ARCH_MIPS_SHOW=y
+
+#
+# Options for mips
+#
+CT_ARCH_MIPS_PKG_KSYM=""
+CT_ARCH_mips_o32=y
+CT_ARCH_mips_ABI="32"
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
+CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
+
+#
+# Generic target options
+#
+# CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
+CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=32
+CT_ARCH_32=y
+# CT_ARCH_64 is not set
+
+#
+# Target optimisations
+#
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ARCH="mips32r2"
+CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
+CT_ARCH_FLOAT="auto"
+
+#
+# Toolchain options
+#
+
+#
+# General toolchain options
+#
+CT_FORCE_SYSROOT=y
+CT_USE_SYSROOT=y
+CT_SYSROOT_NAME="sysroot"
+CT_SYSROOT_DIR_PREFIX=""
+CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
+# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
+CT_TOOLCHAIN_PKGVERSION=""
+CT_TOOLCHAIN_BUGURL=""
+
+#
+# Tuple completion and aliasing
+#
+CT_TARGET_VENDOR="unknown"
+CT_TARGET_ALIAS_SED_EXPR=""
+CT_TARGET_ALIAS=""
+
+#
+# Toolchain type
+#
+CT_CROSS=y
+# CT_CANADIAN is not set
+CT_TOOLCHAIN_TYPE="cross"
+
+#
+# Build system
+#
+CT_BUILD=""
+CT_BUILD_PREFIX=""
+CT_BUILD_SUFFIX=""
+
+#
+# Misc options
+#
+# CT_TOOLCHAIN_ENABLE_NLS is not set
+
+#
+# Operating System
+#
+CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
+CT_KERNEL="linux"
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+CT_LINUX_V_4_4=y
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+# CT_LINUX_V_3_2 is not set
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.4.174"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
+CT_KERNEL_LINUX_VERBOSITY_0=y
+# CT_KERNEL_LINUX_VERBOSITY_1 is not set
+# CT_KERNEL_LINUX_VERBOSITY_2 is not set
+CT_KERNEL_LINUX_VERBOSE_LEVEL=0
+CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
+
+#
+# Binary utilities
+#
+CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
+CT_BINUTILS="binutils"
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
+
+#
+# GNU binutils
+#
+CT_BINUTILS_HAS_HASH_STYLE=y
+CT_BINUTILS_HAS_GOLD=y
+CT_BINUTILS_HAS_PLUGINS=y
+CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
+CT_BINUTILS_LINKER_LD=y
+CT_BINUTILS_LINKERS_LIST="ld"
+CT_BINUTILS_LINKER_DEFAULT="bfd"
+# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
+CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
+# CT_BINUTILS_FOR_TARGET is not set
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
+
+#
+# C-library
+#
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
+CT_LIBC="glibc"
+CT_LIBC_CHOICE_KSYM="GLIBC"
+CT_THREADS="nptl"
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+CT_GLIBC_V_2_23=y
+# CT_GLIBC_V_2_19 is not set
+# CT_GLIBC_V_2_17 is not set
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.23"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_later=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_later_than_2_20=y
+CT_GLIBC_2_20_or_later=y
+CT_GLIBC_later_than_2_17=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_NO_SPARC_V8=y
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.4.174"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
+CT_LIBC_SUPPORT_THREADS_ANY=y
+CT_LIBC_SUPPORT_THREADS_NATIVE=y
+
+#
+# Common C library options
+#
+CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
+CT_LIBC_XLDD=y
+
+#
+# C compiler
+#
+CT_CC_CORE_PASSES_NEEDED=y
+CT_CC_CORE_PASS_1_NEEDED=y
+CT_CC_CORE_PASS_2_NEEDED=y
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
+CT_CC_GCC_ENABLE_CXX_FLAGS=""
+CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-fp-32=xx --with-odd-spreg-32=no"
+CT_CC_GCC_STATIC_LIBSTDCXX=y
+# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
+
+#
+# Optimisation features
+#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
+
+#
+# Settings for libraries running on target
+#
+CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y
+# CT_CC_GCC_LIBMUDFLAP is not set
+# CT_CC_GCC_LIBGOMP is not set
+# CT_CC_GCC_LIBSSP is not set
+# CT_CC_GCC_LIBQUADMATH is not set
+# CT_CC_GCC_LIBSANITIZER is not set
+
+#
+# Misc. obscure options.
+#
+CT_CC_CXA_ATEXIT=y
+# CT_CC_GCC_DISABLE_PCH is not set
+CT_CC_GCC_SJLJ_EXCEPTIONS=m
+CT_CC_GCC_LDBL_128=m
+# CT_CC_GCC_BUILD_ID is not set
+CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y
+# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set
+# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set
+# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set
+CT_CC_GCC_LNK_HASH_STYLE=""
+CT_CC_GCC_DEC_FLOAT_AUTO=y
+# CT_CC_GCC_DEC_FLOAT_BID is not set
+# CT_CC_GCC_DEC_FLOAT_DPD is not set
+# CT_CC_GCC_DEC_FLOATS_NO is not set
+CT_CC_GCC_HAS_ARCH_OPTIONS=y
+
+#
+# archictecture-specific options
+#
+CT_CC_GCC_mips_llsc=m
+CT_CC_GCC_mips_synci=m
+# CT_CC_GCC_mips_plt is not set
+CT_ALL_CC_CHOICES="GCC"
+
+#
+# Additional supported languages:
+#
+CT_CC_LANG_CXX=y
+# CT_CC_LANG_FORTRAN is not set
+
+#
+# Debug facilities
+#
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
+
+#
+# Companion libraries
+#
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
+CT_LIBICONV_NEEDED=y
+CT_GETTEXT_NEEDED=y
+CT_GMP_NEEDED=y
+CT_MPFR_NEEDED=y
+CT_ISL_NEEDED=y
+CT_MPC_NEEDED=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
+CT_LIBICONV=y
+CT_GETTEXT=y
+CT_GMP=y
+CT_MPFR=y
+CT_ISL=y
+CT_MPC=y
+CT_NCURSES=y
+CT_ZLIB=y
+
+#
+# Companion tools
+#
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch
new file mode 100644
index 00000000000..393084df324
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch
@@ -0,0 +1,44 @@
+From 43c2948756bb6e144c7b871e827bba37d61ad3a3 Mon Sep 17 00:00:00 2001
+From: Aurelien Jarno <aurelien@aurel32.net>
+Date: Sat, 18 Jun 2016 19:11:23 +0200
+Subject: [PATCH 1/2] MIPS, SPARC: fix wrong vfork aliases in libpthread.so
+
+With recent binutils versions the GNU libc fails to build on at least
+MISP and SPARC, with this kind of error:
+
+  /home/aurel32/glibc/glibc-build/nptl/libpthread.so:(*IND*+0x0): multiple definition of `vfork@GLIBC_2.0'
+  /home/aurel32/glibc/glibc-build/nptl/libpthread.so::(.text+0xee50): first defined here
+
+It appears that on these architectures pt-vfork.S includes vfork.S
+(through the alpha version of pt-vfork.S) and that the __vfork aliases
+are not conditionalized on IS_IN (libc) like on other architectures.
+Therefore the aliases are also wrongly included in libpthread.so.
+
+Fix this by properly conditionalizing the aliases like on other
+architectures.
+
+Changelog:
+	* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize
+	hidden_def, weak_alias and strong_alias on [IS_IN (libc)].
+	* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
+---
+ sysdeps/unix/sysv/linux/mips/vfork.S | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
+index 8c6615143708..c0c0ce699159 100644
+--- a/sysdeps/unix/sysv/linux/mips/vfork.S
++++ b/sysdeps/unix/sysv/linux/mips/vfork.S
+@@ -106,6 +106,8 @@ L(error):
+ #endif
+ 	END(__vfork)
+ 
++#if IS_IN (libc)
+ libc_hidden_def(__vfork)
+ weak_alias (__vfork, vfork)
+ strong_alias (__vfork, __libc_vfork)
++#endif
+-- 
+2.37.3
+
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch
new file mode 100644
index 00000000000..e28c7ae99f0
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch
@@ -0,0 +1,63 @@
+From b87c1ec3fa398646f042a68f0ce0f7d09c1348c7 Mon Sep 17 00:00:00 2001
+From: Aurelien Jarno <aurelien@aurel32.net>
+Date: Tue, 21 Jun 2016 23:59:37 +0200
+Subject: [PATCH 2/2] MIPS, SPARC: more fixes to the vfork aliases in
+ libpthread.so
+
+Commit 43c29487 tried to fix the vfork aliases in libpthread.so on MIPS
+and SPARC, but failed to do it correctly, introducing an ABI change.
+
+This patch does the remaining changes needed to align the MIPS and SPARC
+vfork implementations with the other architectures. That way the the
+alpha version of pt-vfork.S works correctly for MIPS and SPARC. The
+changes for alpha were done in 82aab97c.
+
+Changelog:
+	* sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into
+	__libc_vfork.
+	(__vfork) [IS_IN (libc)]: Remove alias.
+	(__libc_vfork) [IS_IN (libc)]: Define as an alias.
+	* sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise.
+---
+ sysdeps/unix/sysv/linux/mips/vfork.S | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
+index c0c0ce699159..1867c8626ebe 100644
+--- a/sysdeps/unix/sysv/linux/mips/vfork.S
++++ b/sysdeps/unix/sysv/linux/mips/vfork.S
+@@ -31,13 +31,13 @@
+ LOCALSZ= 1
+ FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+ GPOFF= FRAMESZ-(1*SZREG)
+-NESTED(__vfork,FRAMESZ,sp)
++NESTED(__libc_vfork,FRAMESZ,sp)
+ #ifdef __PIC__
+ 	SETUP_GP
+ #endif
+ 	PTR_SUBU sp, FRAMESZ
+ 	cfi_adjust_cfa_offset (FRAMESZ)
+-	SETUP_GP64_REG (a5, __vfork)
++	SETUP_GP64_REG (a5, __libc_vfork)
+ #ifdef __PIC__
+ 	SAVE_GP (GPOFF)
+ #endif
+@@ -104,10 +104,10 @@ L(error):
+ 	RESTORE_GP64_REG
+ 	j		__syscall_error
+ #endif
+-	END(__vfork)
++	END(__libc_vfork)
+ 
+ #if IS_IN (libc)
+-libc_hidden_def(__vfork)
+-weak_alias (__vfork, vfork)
+-strong_alias (__vfork, __libc_vfork)
++weak_alias (__libc_vfork, vfork)
++strong_alias (__libc_vfork, __vfork)
++libc_hidden_def (__vfork)
+ #endif
+-- 
+2.37.3
+
diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
index fd15dbd22c6..de862e1df2d 100644
--- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
@@ -1,30 +1,30 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils \
-  g++-mips64-linux-gnuabi64 \
-  libssl-dev \
-  pkg-config
+FROM ubuntu:22.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+WORKDIR /tmp
+
+COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
+COPY host-x86_64/dist-mips64-linux/mips64-linux-gnu.config host-x86_64/dist-mips64-linux/build-mips64-toolchain.sh /tmp/
+RUN su rustbuild -c ./build-mips64-toolchain.sh
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
+ENV PATH=$PATH:/x-tools/mips64-unknown-linux-gnu/bin
+
+ENV \
+    CC_mips64_unknown_linux_gnuabi64=mips64-unknown-linux-gnu-gcc \
+    AR_mips64_unknown_linux_gnuabi64=mips64-unknown-linux-gnu-ar \
+    CXX_mips64_unknown_linux_gnuabi64=mips64-unknown-linux-gnu-g++
 
 ENV HOSTS=mips64-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/build-mips64-toolchain.sh b/src/ci/docker/host-x86_64/dist-mips64-linux/build-mips64-toolchain.sh
new file mode 100755
index 00000000000..f554a5f4754
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips64-linux/build-mips64-toolchain.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../mips64-linux-gnu.config .config
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.config b/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.config
new file mode 100644
index 00000000000..4b1efe24aed
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.config
@@ -0,0 +1,741 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
+CT_MODULES=y
+
+#
+# Paths and misc options
+#
+
+#
+# crosstool-NG behavior
+#
+# CT_OBSOLETE is not set
+# CT_EXPERIMENTAL is not set
+# CT_DEBUG_CT is not set
+
+#
+# Paths
+#
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
+CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_RM_RF_PREFIX_DIR=y
+CT_REMOVE_DOCS=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
+CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
+# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
+
+#
+# Downloading
+#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
+# CT_FORBID_DOWNLOAD is not set
+# CT_FORCE_DOWNLOAD is not set
+CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
+# CT_ONLY_DOWNLOAD is not set
+CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
+
+#
+# Extracting
+#
+# CT_FORCE_EXTRACT is not set
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
+# CT_ONLY_EXTRACT is not set
+# CT_PATCH_BUNDLED is not set
+CT_PATCH_BUNDLED_LOCAL=y
+CT_PATCH_ORDER="bundled,local"
+CT_PATCH_USE_LOCAL=y
+CT_LOCAL_PATCH_DIR="/tmp/patches"
+
+#
+# Build behavior
+#
+CT_PARALLEL_JOBS=0
+CT_LOAD=""
+CT_USE_PIPES=y
+CT_EXTRA_CFLAGS_FOR_BUILD=""
+CT_EXTRA_LDFLAGS_FOR_BUILD=""
+CT_EXTRA_CFLAGS_FOR_HOST=""
+CT_EXTRA_LDFLAGS_FOR_HOST=""
+# CT_CONFIG_SHELL_SH is not set
+# CT_CONFIG_SHELL_ASH is not set
+CT_CONFIG_SHELL_BASH=y
+# CT_CONFIG_SHELL_CUSTOM is not set
+CT_CONFIG_SHELL="${bash}"
+
+#
+# Logging
+#
+# CT_LOG_ERROR is not set
+# CT_LOG_WARN is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
+# CT_LOG_ALL is not set
+# CT_LOG_DEBUG is not set
+CT_LOG_LEVEL_MAX="EXTRA"
+# CT_LOG_SEE_TOOLS_WARN is not set
+CT_LOG_PROGRESS_BAR=y
+CT_LOG_TO_FILE=y
+CT_LOG_FILE_COMPRESS=y
+
+#
+# Target options
+#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+CT_ARCH_MIPS=y
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
+CT_ARCH="mips"
+CT_ARCH_CHOICE_KSYM="MIPS"
+CT_ARCH_TUNE=""
+CT_ARCH_MIPS_SHOW=y
+
+#
+# Options for mips
+#
+CT_ARCH_MIPS_PKG_KSYM=""
+# CT_ARCH_mips_n32 is not set
+CT_ARCH_mips_n64=y
+CT_ARCH_mips_ABI="64"
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
+CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
+
+#
+# Generic target options
+#
+# CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
+CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
+
+#
+# Target optimisations
+#
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ARCH="mips64r2"
+CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
+CT_ARCH_FLOAT="auto"
+
+#
+# Toolchain options
+#
+
+#
+# General toolchain options
+#
+CT_FORCE_SYSROOT=y
+CT_USE_SYSROOT=y
+CT_SYSROOT_NAME="sysroot"
+CT_SYSROOT_DIR_PREFIX=""
+CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
+# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
+CT_TOOLCHAIN_PKGVERSION=""
+CT_TOOLCHAIN_BUGURL=""
+
+#
+# Tuple completion and aliasing
+#
+CT_TARGET_VENDOR="unknown"
+CT_TARGET_ALIAS_SED_EXPR=""
+CT_TARGET_ALIAS=""
+
+#
+# Toolchain type
+#
+CT_CROSS=y
+# CT_CANADIAN is not set
+CT_TOOLCHAIN_TYPE="cross"
+
+#
+# Build system
+#
+CT_BUILD=""
+CT_BUILD_PREFIX=""
+CT_BUILD_SUFFIX=""
+
+#
+# Misc options
+#
+# CT_TOOLCHAIN_ENABLE_NLS is not set
+
+#
+# Operating System
+#
+CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
+CT_KERNEL="linux"
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+CT_LINUX_V_4_4=y
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+# CT_LINUX_V_3_2 is not set
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.4.174"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
+CT_KERNEL_LINUX_VERBOSITY_0=y
+# CT_KERNEL_LINUX_VERBOSITY_1 is not set
+# CT_KERNEL_LINUX_VERBOSITY_2 is not set
+CT_KERNEL_LINUX_VERBOSE_LEVEL=0
+CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
+
+#
+# Binary utilities
+#
+CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
+CT_BINUTILS="binutils"
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
+
+#
+# GNU binutils
+#
+CT_BINUTILS_HAS_HASH_STYLE=y
+CT_BINUTILS_HAS_GOLD=y
+CT_BINUTILS_HAS_PLUGINS=y
+CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
+CT_BINUTILS_LINKER_LD=y
+CT_BINUTILS_LINKERS_LIST="ld"
+CT_BINUTILS_LINKER_DEFAULT="bfd"
+# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
+CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
+# CT_BINUTILS_FOR_TARGET is not set
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
+
+#
+# C-library
+#
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
+CT_LIBC="glibc"
+CT_LIBC_CHOICE_KSYM="GLIBC"
+CT_THREADS="nptl"
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+CT_GLIBC_V_2_23=y
+# CT_GLIBC_V_2_19 is not set
+# CT_GLIBC_V_2_17 is not set
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.23"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_later=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_later_than_2_20=y
+CT_GLIBC_2_20_or_later=y
+CT_GLIBC_later_than_2_17=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_NO_SPARC_V8=y
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.4.174"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
+CT_LIBC_SUPPORT_THREADS_ANY=y
+CT_LIBC_SUPPORT_THREADS_NATIVE=y
+
+#
+# Common C library options
+#
+CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
+CT_LIBC_XLDD=y
+
+#
+# C compiler
+#
+CT_CC_CORE_PASSES_NEEDED=y
+CT_CC_CORE_PASS_1_NEEDED=y
+CT_CC_CORE_PASS_2_NEEDED=y
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
+CT_CC_GCC_ENABLE_CXX_FLAGS=""
+CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_STATIC_LIBSTDCXX=y
+# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
+
+#
+# Optimisation features
+#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
+
+#
+# Settings for libraries running on target
+#
+CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y
+# CT_CC_GCC_LIBMUDFLAP is not set
+# CT_CC_GCC_LIBGOMP is not set
+# CT_CC_GCC_LIBSSP is not set
+# CT_CC_GCC_LIBQUADMATH is not set
+# CT_CC_GCC_LIBSANITIZER is not set
+
+#
+# Misc. obscure options.
+#
+CT_CC_CXA_ATEXIT=y
+# CT_CC_GCC_DISABLE_PCH is not set
+CT_CC_GCC_SJLJ_EXCEPTIONS=m
+CT_CC_GCC_LDBL_128=m
+# CT_CC_GCC_BUILD_ID is not set
+CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y
+# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set
+# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set
+# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set
+CT_CC_GCC_LNK_HASH_STYLE=""
+CT_CC_GCC_DEC_FLOAT_AUTO=y
+# CT_CC_GCC_DEC_FLOAT_BID is not set
+# CT_CC_GCC_DEC_FLOAT_DPD is not set
+# CT_CC_GCC_DEC_FLOATS_NO is not set
+CT_CC_GCC_HAS_ARCH_OPTIONS=y
+
+#
+# archictecture-specific options
+#
+CT_CC_GCC_mips_llsc=m
+CT_CC_GCC_mips_synci=m
+# CT_CC_GCC_mips_plt is not set
+CT_ALL_CC_CHOICES="GCC"
+
+#
+# Additional supported languages:
+#
+CT_CC_LANG_CXX=y
+# CT_CC_LANG_FORTRAN is not set
+
+#
+# Debug facilities
+#
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
+
+#
+# Companion libraries
+#
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
+CT_LIBICONV_NEEDED=y
+CT_GETTEXT_NEEDED=y
+CT_GMP_NEEDED=y
+CT_MPFR_NEEDED=y
+CT_ISL_NEEDED=y
+CT_MPC_NEEDED=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
+CT_LIBICONV=y
+CT_GETTEXT=y
+CT_GMP=y
+CT_MPFR=y
+CT_ISL=y
+CT_MPC=y
+CT_NCURSES=y
+CT_ZLIB=y
+
+#
+# Companion tools
+#
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
index 376bdfb4a2f..b90950f7330 100644
--- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
@@ -1,31 +1,30 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils \
-  g++-mips64el-linux-gnuabi64 \
-  libssl-dev \
-  pkg-config
+FROM ubuntu:22.04
 
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+WORKDIR /tmp
+
+COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
+COPY host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.config host-x86_64/dist-mips64el-linux/build-mips64el-toolchain.sh /tmp/
+RUN su rustbuild -c ./build-mips64el-toolchain.sh
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
+ENV PATH=$PATH:/x-tools/mips64el-unknown-linux-gnu/bin
+
+ENV \
+    CC_mips64el_unknown_linux_gnuabi64=mips64el-unknown-linux-gnu-gcc \
+    AR_mips64el_unknown_linux_gnuabi64=mips64el-unknown-linux-gnu-ar \
+    CXX_mips64el_unknown_linux_gnuabi64=mips64el-unknown-linux-gnu-g++
 
 ENV HOSTS=mips64el-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/build-mips64el-toolchain.sh b/src/ci/docker/host-x86_64/dist-mips64el-linux/build-mips64el-toolchain.sh
new file mode 100755
index 00000000000..1ad406800b1
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/build-mips64el-toolchain.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../mips64el-linux-gnu.config .config
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.config b/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.config
new file mode 100644
index 00000000000..baff944cf97
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.config
@@ -0,0 +1,741 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
+CT_MODULES=y
+
+#
+# Paths and misc options
+#
+
+#
+# crosstool-NG behavior
+#
+# CT_OBSOLETE is not set
+# CT_EXPERIMENTAL is not set
+# CT_DEBUG_CT is not set
+
+#
+# Paths
+#
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
+CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_RM_RF_PREFIX_DIR=y
+CT_REMOVE_DOCS=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
+CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
+# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
+
+#
+# Downloading
+#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
+# CT_FORBID_DOWNLOAD is not set
+# CT_FORCE_DOWNLOAD is not set
+CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
+# CT_ONLY_DOWNLOAD is not set
+CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
+
+#
+# Extracting
+#
+# CT_FORCE_EXTRACT is not set
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
+# CT_ONLY_EXTRACT is not set
+# CT_PATCH_BUNDLED is not set
+CT_PATCH_BUNDLED_LOCAL=y
+CT_PATCH_ORDER="bundled,local"
+CT_PATCH_USE_LOCAL=y
+CT_LOCAL_PATCH_DIR="/tmp/patches"
+
+#
+# Build behavior
+#
+CT_PARALLEL_JOBS=0
+CT_LOAD=""
+CT_USE_PIPES=y
+CT_EXTRA_CFLAGS_FOR_BUILD=""
+CT_EXTRA_LDFLAGS_FOR_BUILD=""
+CT_EXTRA_CFLAGS_FOR_HOST=""
+CT_EXTRA_LDFLAGS_FOR_HOST=""
+# CT_CONFIG_SHELL_SH is not set
+# CT_CONFIG_SHELL_ASH is not set
+CT_CONFIG_SHELL_BASH=y
+# CT_CONFIG_SHELL_CUSTOM is not set
+CT_CONFIG_SHELL="${bash}"
+
+#
+# Logging
+#
+# CT_LOG_ERROR is not set
+# CT_LOG_WARN is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
+# CT_LOG_ALL is not set
+# CT_LOG_DEBUG is not set
+CT_LOG_LEVEL_MAX="EXTRA"
+# CT_LOG_SEE_TOOLS_WARN is not set
+CT_LOG_PROGRESS_BAR=y
+CT_LOG_TO_FILE=y
+CT_LOG_FILE_COMPRESS=y
+
+#
+# Target options
+#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+CT_ARCH_MIPS=y
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
+CT_ARCH="mips"
+CT_ARCH_CHOICE_KSYM="MIPS"
+CT_ARCH_TUNE=""
+CT_ARCH_MIPS_SHOW=y
+
+#
+# Options for mips
+#
+CT_ARCH_MIPS_PKG_KSYM=""
+# CT_ARCH_mips_n32 is not set
+CT_ARCH_mips_n64=y
+CT_ARCH_mips_ABI="64"
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
+CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
+
+#
+# Generic target options
+#
+# CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+# CT_ARCH_BE is not set
+CT_ARCH_LE=y
+CT_ARCH_ENDIAN="little"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
+
+#
+# Target optimisations
+#
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ARCH="mips64r2"
+CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
+CT_ARCH_FLOAT="auto"
+
+#
+# Toolchain options
+#
+
+#
+# General toolchain options
+#
+CT_FORCE_SYSROOT=y
+CT_USE_SYSROOT=y
+CT_SYSROOT_NAME="sysroot"
+CT_SYSROOT_DIR_PREFIX=""
+CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
+# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
+CT_TOOLCHAIN_PKGVERSION=""
+CT_TOOLCHAIN_BUGURL=""
+
+#
+# Tuple completion and aliasing
+#
+CT_TARGET_VENDOR="unknown"
+CT_TARGET_ALIAS_SED_EXPR=""
+CT_TARGET_ALIAS=""
+
+#
+# Toolchain type
+#
+CT_CROSS=y
+# CT_CANADIAN is not set
+CT_TOOLCHAIN_TYPE="cross"
+
+#
+# Build system
+#
+CT_BUILD=""
+CT_BUILD_PREFIX=""
+CT_BUILD_SUFFIX=""
+
+#
+# Misc options
+#
+# CT_TOOLCHAIN_ENABLE_NLS is not set
+
+#
+# Operating System
+#
+CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
+CT_KERNEL="linux"
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+CT_LINUX_V_4_4=y
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+# CT_LINUX_V_3_2 is not set
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.4.174"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
+CT_KERNEL_LINUX_VERBOSITY_0=y
+# CT_KERNEL_LINUX_VERBOSITY_1 is not set
+# CT_KERNEL_LINUX_VERBOSITY_2 is not set
+CT_KERNEL_LINUX_VERBOSE_LEVEL=0
+CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
+
+#
+# Binary utilities
+#
+CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
+CT_BINUTILS="binutils"
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
+
+#
+# GNU binutils
+#
+CT_BINUTILS_HAS_HASH_STYLE=y
+CT_BINUTILS_HAS_GOLD=y
+CT_BINUTILS_HAS_PLUGINS=y
+CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
+CT_BINUTILS_LINKER_LD=y
+CT_BINUTILS_LINKERS_LIST="ld"
+CT_BINUTILS_LINKER_DEFAULT="bfd"
+# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
+CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
+# CT_BINUTILS_FOR_TARGET is not set
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
+
+#
+# C-library
+#
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
+CT_LIBC="glibc"
+CT_LIBC_CHOICE_KSYM="GLIBC"
+CT_THREADS="nptl"
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+CT_GLIBC_V_2_23=y
+# CT_GLIBC_V_2_19 is not set
+# CT_GLIBC_V_2_17 is not set
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.23"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_later=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_later_than_2_20=y
+CT_GLIBC_2_20_or_later=y
+CT_GLIBC_later_than_2_17=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_NO_SPARC_V8=y
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.4.174"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
+CT_LIBC_SUPPORT_THREADS_ANY=y
+CT_LIBC_SUPPORT_THREADS_NATIVE=y
+
+#
+# Common C library options
+#
+CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
+CT_LIBC_XLDD=y
+
+#
+# C compiler
+#
+CT_CC_CORE_PASSES_NEEDED=y
+CT_CC_CORE_PASS_1_NEEDED=y
+CT_CC_CORE_PASS_2_NEEDED=y
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
+CT_CC_GCC_ENABLE_CXX_FLAGS=""
+CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_STATIC_LIBSTDCXX=y
+# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
+
+#
+# Optimisation features
+#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
+
+#
+# Settings for libraries running on target
+#
+CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y
+# CT_CC_GCC_LIBMUDFLAP is not set
+# CT_CC_GCC_LIBGOMP is not set
+# CT_CC_GCC_LIBSSP is not set
+# CT_CC_GCC_LIBQUADMATH is not set
+# CT_CC_GCC_LIBSANITIZER is not set
+
+#
+# Misc. obscure options.
+#
+CT_CC_CXA_ATEXIT=y
+# CT_CC_GCC_DISABLE_PCH is not set
+CT_CC_GCC_SJLJ_EXCEPTIONS=m
+CT_CC_GCC_LDBL_128=m
+# CT_CC_GCC_BUILD_ID is not set
+CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y
+# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set
+# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set
+# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set
+CT_CC_GCC_LNK_HASH_STYLE=""
+CT_CC_GCC_DEC_FLOAT_AUTO=y
+# CT_CC_GCC_DEC_FLOAT_BID is not set
+# CT_CC_GCC_DEC_FLOAT_DPD is not set
+# CT_CC_GCC_DEC_FLOATS_NO is not set
+CT_CC_GCC_HAS_ARCH_OPTIONS=y
+
+#
+# archictecture-specific options
+#
+CT_CC_GCC_mips_llsc=m
+CT_CC_GCC_mips_synci=m
+# CT_CC_GCC_mips_plt is not set
+CT_ALL_CC_CHOICES="GCC"
+
+#
+# Additional supported languages:
+#
+CT_CC_LANG_CXX=y
+# CT_CC_LANG_FORTRAN is not set
+
+#
+# Debug facilities
+#
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
+
+#
+# Companion libraries
+#
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
+CT_LIBICONV_NEEDED=y
+CT_GETTEXT_NEEDED=y
+CT_GMP_NEEDED=y
+CT_MPFR_NEEDED=y
+CT_ISL_NEEDED=y
+CT_MPC_NEEDED=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
+CT_LIBICONV=y
+CT_GETTEXT=y
+CT_GMP=y
+CT_MPFR=y
+CT_ISL=y
+CT_MPC=y
+CT_NCURSES=y
+CT_ZLIB=y
+
+#
+# Companion tools
+#
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
index 70c8b2a96c8..6cc2de5e47d 100644
--- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
@@ -1,30 +1,30 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils \
-  g++-mipsel-linux-gnu \
-  libssl-dev \
-  pkg-config
+FROM ubuntu:22.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+WORKDIR /tmp
+
+COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/
+COPY host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.config host-x86_64/dist-mipsel-linux/build-mipsel-toolchain.sh /tmp/
+RUN su rustbuild -c ./build-mipsel-toolchain.sh
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
+ENV PATH=$PATH:/x-tools/mipsel-unknown-linux-gnu/bin
+
+ENV \
+    CC_mipsel_unknown_linux_gnu=mipsel-unknown-linux-gnu-gcc \
+    AR_mipsel_unknown_linux_gnu=mipsel-unknown-linux-gnu-ar \
+    CXX_mipsel_unknown_linux_gnu=mipsel-unknown-linux-gnu-g++
 
 ENV HOSTS=mipsel-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/build-mipsel-toolchain.sh b/src/ci/docker/host-x86_64/dist-mipsel-linux/build-mipsel-toolchain.sh
new file mode 100755
index 00000000000..598e4893325
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/build-mipsel-toolchain.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  "$@" &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../mipsel-linux-gnu.config .config
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.config b/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.config
new file mode 100644
index 00000000000..adb2da7ddee
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.config
@@ -0,0 +1,740 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
+CT_MODULES=y
+
+#
+# Paths and misc options
+#
+
+#
+# crosstool-NG behavior
+#
+# CT_OBSOLETE is not set
+# CT_EXPERIMENTAL is not set
+# CT_DEBUG_CT is not set
+
+#
+# Paths
+#
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
+CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_RM_RF_PREFIX_DIR=y
+CT_REMOVE_DOCS=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
+CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
+# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
+
+#
+# Downloading
+#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
+# CT_FORBID_DOWNLOAD is not set
+# CT_FORCE_DOWNLOAD is not set
+CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
+# CT_ONLY_DOWNLOAD is not set
+CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
+
+#
+# Extracting
+#
+# CT_FORCE_EXTRACT is not set
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
+# CT_ONLY_EXTRACT is not set
+# CT_PATCH_BUNDLED is not set
+CT_PATCH_BUNDLED_LOCAL=y
+CT_PATCH_ORDER="bundled,local"
+CT_PATCH_USE_LOCAL=y
+CT_LOCAL_PATCH_DIR="/tmp/patches"
+
+#
+# Build behavior
+#
+CT_PARALLEL_JOBS=0
+CT_LOAD=""
+CT_USE_PIPES=y
+CT_EXTRA_CFLAGS_FOR_BUILD=""
+CT_EXTRA_LDFLAGS_FOR_BUILD=""
+CT_EXTRA_CFLAGS_FOR_HOST=""
+CT_EXTRA_LDFLAGS_FOR_HOST=""
+# CT_CONFIG_SHELL_SH is not set
+# CT_CONFIG_SHELL_ASH is not set
+CT_CONFIG_SHELL_BASH=y
+# CT_CONFIG_SHELL_CUSTOM is not set
+CT_CONFIG_SHELL="${bash}"
+
+#
+# Logging
+#
+# CT_LOG_ERROR is not set
+# CT_LOG_WARN is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
+# CT_LOG_ALL is not set
+# CT_LOG_DEBUG is not set
+CT_LOG_LEVEL_MAX="EXTRA"
+# CT_LOG_SEE_TOOLS_WARN is not set
+CT_LOG_PROGRESS_BAR=y
+CT_LOG_TO_FILE=y
+CT_LOG_FILE_COMPRESS=y
+
+#
+# Target options
+#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+CT_ARCH_MIPS=y
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
+CT_ARCH="mips"
+CT_ARCH_CHOICE_KSYM="MIPS"
+CT_ARCH_TUNE=""
+CT_ARCH_MIPS_SHOW=y
+
+#
+# Options for mips
+#
+CT_ARCH_MIPS_PKG_KSYM=""
+CT_ARCH_mips_o32=y
+CT_ARCH_mips_ABI="32"
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
+CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
+
+#
+# Generic target options
+#
+# CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+# CT_ARCH_BE is not set
+CT_ARCH_LE=y
+CT_ARCH_ENDIAN="little"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=32
+CT_ARCH_32=y
+# CT_ARCH_64 is not set
+
+#
+# Target optimisations
+#
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ARCH="mips32r2"
+CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
+CT_ARCH_FLOAT="auto"
+
+#
+# Toolchain options
+#
+
+#
+# General toolchain options
+#
+CT_FORCE_SYSROOT=y
+CT_USE_SYSROOT=y
+CT_SYSROOT_NAME="sysroot"
+CT_SYSROOT_DIR_PREFIX=""
+CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
+# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
+CT_TOOLCHAIN_PKGVERSION=""
+CT_TOOLCHAIN_BUGURL=""
+
+#
+# Tuple completion and aliasing
+#
+CT_TARGET_VENDOR="unknown"
+CT_TARGET_ALIAS_SED_EXPR=""
+CT_TARGET_ALIAS=""
+
+#
+# Toolchain type
+#
+CT_CROSS=y
+# CT_CANADIAN is not set
+CT_TOOLCHAIN_TYPE="cross"
+
+#
+# Build system
+#
+CT_BUILD=""
+CT_BUILD_PREFIX=""
+CT_BUILD_SUFFIX=""
+
+#
+# Misc options
+#
+# CT_TOOLCHAIN_ENABLE_NLS is not set
+
+#
+# Operating System
+#
+CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
+CT_KERNEL="linux"
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+CT_LINUX_V_4_4=y
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+# CT_LINUX_V_3_2 is not set
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.4.174"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
+CT_KERNEL_LINUX_VERBOSITY_0=y
+# CT_KERNEL_LINUX_VERBOSITY_1 is not set
+# CT_KERNEL_LINUX_VERBOSITY_2 is not set
+CT_KERNEL_LINUX_VERBOSE_LEVEL=0
+CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
+
+#
+# Binary utilities
+#
+CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
+CT_BINUTILS="binutils"
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
+
+#
+# GNU binutils
+#
+CT_BINUTILS_HAS_HASH_STYLE=y
+CT_BINUTILS_HAS_GOLD=y
+CT_BINUTILS_HAS_PLUGINS=y
+CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
+CT_BINUTILS_LINKER_LD=y
+CT_BINUTILS_LINKERS_LIST="ld"
+CT_BINUTILS_LINKER_DEFAULT="bfd"
+# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
+CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
+# CT_BINUTILS_FOR_TARGET is not set
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
+
+#
+# C-library
+#
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
+CT_LIBC="glibc"
+CT_LIBC_CHOICE_KSYM="GLIBC"
+CT_THREADS="nptl"
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+CT_GLIBC_V_2_23=y
+# CT_GLIBC_V_2_19 is not set
+# CT_GLIBC_V_2_17 is not set
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.23"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_later=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_later_than_2_20=y
+CT_GLIBC_2_20_or_later=y
+CT_GLIBC_later_than_2_17=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_NO_SPARC_V8=y
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.4.174"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
+CT_LIBC_SUPPORT_THREADS_ANY=y
+CT_LIBC_SUPPORT_THREADS_NATIVE=y
+
+#
+# Common C library options
+#
+CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
+CT_LIBC_XLDD=y
+
+#
+# C compiler
+#
+CT_CC_CORE_PASSES_NEEDED=y
+CT_CC_CORE_PASS_1_NEEDED=y
+CT_CC_CORE_PASS_2_NEEDED=y
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
+CT_CC_GCC_ENABLE_CXX_FLAGS=""
+CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-fp-32=xx --with-odd-spreg-32=no"
+CT_CC_GCC_STATIC_LIBSTDCXX=y
+# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
+
+#
+# Optimisation features
+#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
+
+#
+# Settings for libraries running on target
+#
+CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y
+# CT_CC_GCC_LIBMUDFLAP is not set
+# CT_CC_GCC_LIBGOMP is not set
+# CT_CC_GCC_LIBSSP is not set
+# CT_CC_GCC_LIBQUADMATH is not set
+# CT_CC_GCC_LIBSANITIZER is not set
+
+#
+# Misc. obscure options.
+#
+CT_CC_CXA_ATEXIT=y
+# CT_CC_GCC_DISABLE_PCH is not set
+CT_CC_GCC_SJLJ_EXCEPTIONS=m
+CT_CC_GCC_LDBL_128=m
+# CT_CC_GCC_BUILD_ID is not set
+CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y
+# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set
+# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set
+# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set
+CT_CC_GCC_LNK_HASH_STYLE=""
+CT_CC_GCC_DEC_FLOAT_AUTO=y
+# CT_CC_GCC_DEC_FLOAT_BID is not set
+# CT_CC_GCC_DEC_FLOAT_DPD is not set
+# CT_CC_GCC_DEC_FLOATS_NO is not set
+CT_CC_GCC_HAS_ARCH_OPTIONS=y
+
+#
+# archictecture-specific options
+#
+CT_CC_GCC_mips_llsc=m
+CT_CC_GCC_mips_synci=m
+# CT_CC_GCC_mips_plt is not set
+CT_ALL_CC_CHOICES="GCC"
+
+#
+# Additional supported languages:
+#
+CT_CC_LANG_CXX=y
+# CT_CC_LANG_FORTRAN is not set
+
+#
+# Debug facilities
+#
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
+
+#
+# Companion libraries
+#
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
+CT_LIBICONV_NEEDED=y
+CT_GETTEXT_NEEDED=y
+CT_GMP_NEEDED=y
+CT_MPFR_NEEDED=y
+CT_ISL_NEEDED=y
+CT_MPC_NEEDED=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
+CT_LIBICONV=y
+CT_GETTEXT=y
+CT_GMP=y
+CT_MPFR=y
+CT_ISL=y
+CT_MPC=y
+CT_NCURSES=y
+CT_ZLIB=y
+
+#
+# Companion tools
+#
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index b960239807a..423aba06cca 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -78,7 +78,8 @@ ENV RUST_CONFIGURE_ARGS \
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
       --set rust.jemalloc \
-      --set rust.use-lld=true
+      --set rust.use-lld=true \
+      --set rust.lto=thin
 ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 7fd0b1e8e6f..cc96715b285 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.12.4
\ No newline at end of file
+0.12.7
\ No newline at end of file
diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
index 507631cdc54..432e0cfc960 100644
--- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
@@ -1,7 +1,7 @@
 # armeb-unknown-linux-gnueabi
 **Tier: 3**
 
-Target for cross-compiling Linux user-mode applications targetting the ARM BE8 architecture.
+Target for cross-compiling Linux user-mode applications targeting the ARM BE8 architecture.
 
 ## Overview
 BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian ARM systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats).
diff --git a/src/doc/unstable-book/src/compiler-flags/dylib-lto.md b/src/doc/unstable-book/src/compiler-flags/dylib-lto.md
new file mode 100644
index 00000000000..f69ea334f5a
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/dylib-lto.md
@@ -0,0 +1,4 @@
+## `dylib-lto`
+
+This option enables using LTO for the `dylib` crate type. This is currently only used for compiling
+`rustc` itself (more specifically, the `librustc_driver` dylib).
diff --git a/src/doc/unstable-book/src/language-features/asm-sym.md b/src/doc/unstable-book/src/language-features/asm-sym.md
deleted file mode 100644
index 103d91caf4c..00000000000
--- a/src/doc/unstable-book/src/language-features/asm-sym.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# `asm_sym`
-
-The tracking issue for this feature is: [#93333]
-
-[#93333]: https://github.com/rust-lang/rust/issues/93333
-
-------------------------
-
-This feature adds a `sym <path>` operand type to `asm!` and `global_asm!`.
-- `<path>` must refer to a `fn` or `static`.
-- A mangled symbol name referring to the item is substituted into the asm template string.
-- The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
-- `<path>` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.
diff --git a/src/doc/unstable-book/src/language-features/unix-sigpipe.md b/src/doc/unstable-book/src/language-features/unix-sigpipe.md
index aa39b6eb288..7ed6a7de895 100644
--- a/src/doc/unstable-book/src/language-features/unix-sigpipe.md
+++ b/src/doc/unstable-book/src/language-features/unix-sigpipe.md
@@ -36,7 +36,7 @@ hello world
 
 Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
 
-This is what libstd has done by default since 2014. Omitting `#[unix_sigpipe = "..."]` is the same as having `#[unix_sigpipe = "sig_ign"]`.
+This is what libstd has done by default since 2014. (However, see the note on child processes below.)
 
 ### Example
 
@@ -52,3 +52,11 @@ hello world
 thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 ```
+
+### Note on child processes
+
+When spawning child processes, the legacy Rust behavior if `#[unix_sigpipe]` is not specified is to
+reset `SIGPIPE` to `SIG_DFL`.
+
+If `#[unix_sigpipe = "..."]` is specified, no matter what its value is, the signal disposition of
+`SIGPIPE` is no longer reset. This means that the child inherits the parent's `SIGPIPE` behavior.
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 95061ae61e3..7c59e785752 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -13,116 +13,124 @@ pub(crate) struct BlanketImplFinder<'a, 'tcx> {
 
 impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
     pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
-        let param_env = self.cx.tcx.param_env(item_def_id);
-        let ty = self.cx.tcx.bound_type_of(item_def_id);
+        let cx = &mut self.cx;
+        let param_env = cx.tcx.param_env(item_def_id);
+        let ty = cx.tcx.bound_type_of(item_def_id);
 
         trace!("get_blanket_impls({:?})", ty);
         let mut impls = Vec::new();
-        self.cx.with_all_traits(|cx, all_traits| {
-            for &trait_def_id in all_traits {
-                if !cx.cache.access_levels.is_public(trait_def_id)
-                    || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
-                {
+        for trait_def_id in cx.tcx.all_traits() {
+            if !cx.cache.access_levels.is_public(trait_def_id)
+                || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
+            {
+                continue;
+            }
+            // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
+            let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
+            'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
+                trace!(
+                    "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
+                    trait_def_id,
+                    impl_def_id
+                );
+                let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+                if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
                     continue;
                 }
-                // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
-                let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
-                'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
-                    trace!(
-                        "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
-                        trait_def_id,
-                        impl_def_id
-                    );
-                    let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
-                    if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
-                        continue;
-                    }
-                    let infcx = cx.tcx.infer_ctxt().build();
-                    let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
-                    let impl_ty = ty.subst(infcx.tcx, substs);
-                    let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
+                let infcx = cx.tcx.infer_ctxt().build();
+                let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
+                let impl_ty = ty.subst(infcx.tcx, substs);
+                let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
 
-                    let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
-                    let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+                let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+                let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
 
-                    // Require the type the impl is implemented on to match
-                    // our type, and ignore the impl if there was a mismatch.
-                    let cause = traits::ObligationCause::dummy();
-                    let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
+                // Require the type the impl is implemented on to match
+                // our type, and ignore the impl if there was a mismatch.
+                let cause = traits::ObligationCause::dummy();
+                let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
                         continue
                     };
-                    let InferOk { value: (), obligations } = eq_result;
-                    // FIXME(eddyb) ignoring `obligations` might cause false positives.
-                    drop(obligations);
+                let InferOk { value: (), obligations } = eq_result;
+                // FIXME(eddyb) ignoring `obligations` might cause false positives.
+                drop(obligations);
 
-                    trace!(
-                        "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",
+                trace!(
+                    "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",
+                    param_env,
+                    impl_trait_ref,
+                    impl_ty
+                );
+                let predicates = cx
+                    .tcx
+                    .predicates_of(impl_def_id)
+                    .instantiate(cx.tcx, impl_substs)
+                    .predicates
+                    .into_iter()
+                    .chain(Some(
+                        ty::Binder::dummy(impl_trait_ref)
+                            .to_poly_trait_predicate()
+                            .map_bound(ty::PredicateKind::Trait)
+                            .to_predicate(infcx.tcx),
+                    ));
+                for predicate in predicates {
+                    debug!("testing predicate {:?}", predicate);
+                    let obligation = traits::Obligation::new(
+                        traits::ObligationCause::dummy(),
                         param_env,
-                        impl_trait_ref,
-                        impl_ty
+                        predicate,
                     );
-                    let predicates = cx
-                        .tcx
-                        .predicates_of(impl_def_id)
-                        .instantiate(cx.tcx, impl_substs)
-                        .predicates
-                        .into_iter()
-                        .chain(Some(
-                            ty::Binder::dummy(impl_trait_ref)
-                                .to_poly_trait_predicate()
-                                .map_bound(ty::PredicateKind::Trait)
-                                .to_predicate(infcx.tcx),
-                        ));
-                    for predicate in predicates {
-                        debug!("testing predicate {:?}", predicate);
-                        let obligation = traits::Obligation::new(
-                            traits::ObligationCause::dummy(),
-                            param_env,
-                            predicate,
-                        );
-                        match infcx.evaluate_obligation(&obligation) {
-                            Ok(eval_result) if eval_result.may_apply() => {}
-                            Err(traits::OverflowError::Canonical) => {}
-                            Err(traits::OverflowError::ErrorReporting) => {}
-                            _ => continue 'blanket_impls,
-                        }
+                    match infcx.evaluate_obligation(&obligation) {
+                        Ok(eval_result) if eval_result.may_apply() => {}
+                        Err(traits::OverflowError::Canonical) => {}
+                        Err(traits::OverflowError::ErrorReporting) => {}
+                        _ => continue 'blanket_impls,
                     }
-                    debug!(
-                        "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",
-                        trait_ref, ty
-                    );
+                }
+                debug!(
+                    "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",
+                    trait_ref, ty
+                );
 
-                    cx.generated_synthetics.insert((ty.0, trait_def_id));
+                cx.generated_synthetics.insert((ty.0, trait_def_id));
 
-                    impls.push(Item {
-                        name: None,
-                        attrs: Default::default(),
-                        visibility: Inherited,
-                        item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
-                        kind: Box::new(ImplItem(Box::new(Impl {
-                            unsafety: hir::Unsafety::Normal,
-                            generics: clean_ty_generics(
-                                cx,
-                                cx.tcx.generics_of(impl_def_id),
-                                cx.tcx.explicit_predicates_of(impl_def_id),
-                            ),
-                            // FIXME(eddyb) compute both `trait_` and `for_` from
-                            // the post-inference `trait_ref`, as it's more accurate.
-                            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, ThinVec::new())),
-                            for_: clean_middle_ty(ty.0, cx, None),
-                            items: cx.tcx
-                                .associated_items(impl_def_id)
-                                .in_definition_order()
-                                .map(|x| clean_middle_assoc_item(x, cx))
-                                .collect::<Vec<_>>(),
-                            polarity: ty::ImplPolarity::Positive,
-                            kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
-                        }))),
-                        cfg: None,
-                    });
-                }
+                impls.push(Item {
+                    name: None,
+                    attrs: Default::default(),
+                    visibility: Inherited,
+                    item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
+                    kind: Box::new(ImplItem(Box::new(Impl {
+                        unsafety: hir::Unsafety::Normal,
+                        generics: clean_ty_generics(
+                            cx,
+                            cx.tcx.generics_of(impl_def_id),
+                            cx.tcx.explicit_predicates_of(impl_def_id),
+                        ),
+                        // FIXME(eddyb) compute both `trait_` and `for_` from
+                        // the post-inference `trait_ref`, as it's more accurate.
+                        trait_: Some(clean_trait_ref_with_bindings(
+                            cx,
+                            trait_ref.0,
+                            ThinVec::new(),
+                        )),
+                        for_: clean_middle_ty(ty.0, cx, None),
+                        items: cx
+                            .tcx
+                            .associated_items(impl_def_id)
+                            .in_definition_order()
+                            .map(|x| clean_middle_assoc_item(x, cx))
+                            .collect::<Vec<_>>(),
+                        polarity: ty::ImplPolarity::Positive,
+                        kind: ImplKind::Blanket(Box::new(clean_middle_ty(
+                            trait_ref.0.self_ty(),
+                            cx,
+                            None,
+                        ))),
+                    }))),
+                    cfg: None,
+                });
             }
-        });
+        }
 
         impls
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5f674ed7441..d86a2682641 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -774,31 +774,36 @@ fn clean_ty_generics<'tcx>(
     let mut where_predicates =
         where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
 
-    // Type parameters have a Sized bound by default unless removed with
-    // ?Sized. Scan through the predicates and mark any type parameter with
-    // a Sized bound, removing the bounds as we find them.
+    // In the surface language, all type parameters except `Self` have an
+    // implicit `Sized` bound unless removed with `?Sized`.
+    // However, in the list of where-predicates below, `Sized` appears like a
+    // normal bound: It's either present (the type is sized) or
+    // absent (the type is unsized) but never *maybe* (i.e. `?Sized`).
     //
-    // Note that associated types also have a sized bound by default, but we
+    // This is unsuitable for rendering.
+    // Thus, as a first step remove all `Sized` bounds that should be implicit.
+    //
+    // Note that associated types also have an implicit `Sized` bound but we
     // don't actually know the set of associated types right here so that's
-    // handled in cleaning associated types
+    // handled when cleaning associated types.
     let mut sized_params = FxHashSet::default();
-    where_predicates.retain(|pred| match *pred {
-        WherePredicate::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
-            if bounds.iter().any(|b| b.is_sized_bound(cx)) {
-                sized_params.insert(*g);
-                false
-            } else {
-                true
-            }
+    where_predicates.retain(|pred| {
+        if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred
+        && *g != kw::SelfUpper
+        && bounds.iter().any(|b| b.is_sized_bound(cx))
+        {
+            sized_params.insert(*g);
+            false
+        } else {
+            true
         }
-        _ => true,
     });
 
-    // Run through the type parameters again and insert a ?Sized
-    // unbound for any we didn't find to be Sized.
+    // As a final step, go through the type parameters again and insert a
+    // `?Sized` bound for each one we didn't find to be `Sized`.
     for tp in &stripped_params {
-        if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
-            && !sized_params.contains(&tp.name)
+        if let types::GenericParamDefKind::Type { .. } = tp.kind
+        && !sized_params.contains(&tp.name)
         {
             where_predicates.push(WherePredicate::BoundPredicate {
                 ty: Type::Generic(tp.name),
@@ -1201,21 +1206,19 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
             }
 
             if let ty::TraitContainer = assoc_item.container {
-                // FIXME(fmease): `tcx.explicit_item_bounds` does not contain the bounds of GATs,
-                //                e.g. the bounds `Copy`, `Display` & (implicitly) `Sized` in
-                //                `type Assoc<T: Copy> where T: Display`. This also means that we
-                //                later incorrectly render `where T: ?Sized`.
-                //
-                //                The result of `tcx.explicit_predicates_of` *does* contain them but
-                //                it does not contain the other bounds / predicates we need.
-                //                Either merge those two interned lists somehow or refactor
-                //                `clean_ty_generics` to call `explicit_item_bounds` by itself.
                 let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
-                let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                let mut generics =
-                    clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates);
-                // Filter out the bounds that are (likely?) directly attached to the associated type,
-                // as opposed to being located in the where clause.
+                let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
+                let predicates =
+                    tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied());
+                let mut generics = clean_ty_generics(
+                    cx,
+                    tcx.generics_of(assoc_item.def_id),
+                    ty::GenericPredicates { parent: None, predicates },
+                );
+                // Move bounds that are (likely) directly attached to the associated type
+                // from the where clause to the associated type.
+                // There is no guarantee that this is what the user actually wrote but we have
+                // no way of knowing.
                 let mut bounds = generics
                     .where_predicates
                     .drain_filter(|pred| match *pred {
@@ -1273,6 +1276,24 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     }
                     None => bounds.push(GenericBound::maybe_sized(cx)),
                 }
+                // Move bounds that are (likely) directly attached to the parameters of the
+                // (generic) associated type from the where clause to the respective parameter.
+                // There is no guarantee that this is what the user actually wrote but we have
+                // no way of knowing.
+                let mut where_predicates = Vec::new();
+                for mut pred in generics.where_predicates {
+                    if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                    {
+                        param_bounds.extend(mem::take(bounds));
+                    } else {
+                        where_predicates.push(pred);
+                    }
+                }
+                generics.where_predicates = where_predicates;
 
                 if tcx.impl_defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 932533db05c..67ea39fb965 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -142,8 +142,6 @@ pub(crate) struct Options {
     // Options that alter generated documentation pages
     /// Crate version to note on the sidebar of generated docs.
     pub(crate) crate_version: Option<String>,
-    /// Collected options specific to outputting final pages.
-    pub(crate) render_options: RenderOptions,
     /// The format that we output when rendering.
     ///
     /// Currently used only for the `--show-coverage` option.
@@ -159,6 +157,10 @@ pub(crate) struct Options {
     /// Configuration for scraping examples from the current crate. If this option is Some(..) then
     /// the compiler will scrape examples and not generate documentation.
     pub(crate) scrape_examples_options: Option<ScrapeExamplesOptions>,
+
+    /// Note: this field is duplicated in `RenderOptions` because it's useful
+    /// to have it in both places.
+    pub(crate) unstable_features: rustc_feature::UnstableFeatures,
 }
 
 impl fmt::Debug for Options {
@@ -194,7 +196,6 @@ impl fmt::Debug for Options {
             .field("persist_doctests", &self.persist_doctests)
             .field("show_coverage", &self.show_coverage)
             .field("crate_version", &self.crate_version)
-            .field("render_options", &self.render_options)
             .field("runtool", &self.runtool)
             .field("runtool_args", &self.runtool_args)
             .field("enable-per-target-ignores", &self.enable_per_target_ignores)
@@ -202,6 +203,7 @@ impl fmt::Debug for Options {
             .field("no_run", &self.no_run)
             .field("nocapture", &self.nocapture)
             .field("scrape_examples_options", &self.scrape_examples_options)
+            .field("unstable_features", &self.unstable_features)
             .finish()
     }
 }
@@ -267,6 +269,8 @@ pub(crate) struct RenderOptions {
     pub(crate) generate_redirect_map: bool,
     /// Show the memory layout of types in the docs.
     pub(crate) show_type_layout: bool,
+    /// Note: this field is duplicated in `Options` because it's useful to have
+    /// it in both places.
     pub(crate) unstable_features: rustc_feature::UnstableFeatures,
     pub(crate) emit: Vec<EmitType>,
     /// If `true`, HTML source pages will generate links for items to their definition.
@@ -316,7 +320,7 @@ impl Options {
     pub(crate) fn from_matches(
         matches: &getopts::Matches,
         args: Vec<String>,
-    ) -> Result<Options, i32> {
+    ) -> Result<(Options, RenderOptions), i32> {
         let args = &args[1..];
         // Check for unstable options.
         nightly_options::check_nightly_options(matches, &opts());
@@ -710,7 +714,9 @@ impl Options {
         let with_examples = matches.opt_strs("with-examples");
         let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
 
-        Ok(Options {
+        let unstable_features =
+            rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref());
+        let options = Options {
             input,
             proc_macro_crate,
             error_format,
@@ -744,42 +750,42 @@ impl Options {
             run_check,
             no_run,
             nocapture,
-            render_options: RenderOptions {
-                output,
-                external_html,
-                id_map,
-                playground_url,
-                module_sorting,
-                themes,
-                extension_css,
-                extern_html_root_urls,
-                extern_html_root_takes_precedence,
-                default_settings,
-                resource_suffix,
-                enable_minification,
-                enable_index_page,
-                index_page,
-                static_root_path,
-                markdown_no_toc,
-                markdown_css,
-                markdown_playground_url,
-                document_private,
-                document_hidden,
-                generate_redirect_map,
-                show_type_layout,
-                unstable_features: rustc_feature::UnstableFeatures::from_environment(
-                    crate_name.as_deref(),
-                ),
-                emit,
-                generate_link_to_definition,
-                call_locations,
-                no_emit_shared: false,
-            },
             crate_name,
             output_format,
             json_unused_externs,
             scrape_examples_options,
-        })
+            unstable_features,
+        };
+        let render_options = RenderOptions {
+            output,
+            external_html,
+            id_map,
+            playground_url,
+            module_sorting,
+            themes,
+            extension_css,
+            extern_html_root_urls,
+            extern_html_root_takes_precedence,
+            default_settings,
+            resource_suffix,
+            enable_minification,
+            enable_index_page,
+            index_page,
+            static_root_path,
+            markdown_no_toc,
+            markdown_css,
+            markdown_playground_url,
+            document_private,
+            document_hidden,
+            generate_redirect_map,
+            show_type_layout,
+            unstable_features,
+            emit,
+            generate_link_to_definition,
+            call_locations,
+            no_emit_shared: false,
+        };
+        Ok((options, render_options))
     }
 
     /// Returns `true` if the file given as `self.input` is a Markdown file.
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index b463b934e29..8232353f915 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -14,7 +14,6 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_resolve as resolve;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::lint;
-use rustc_session::DiagnosticOutput;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{source_map, Span, Symbol};
@@ -39,7 +38,6 @@ pub(crate) struct ResolverCaches {
     /// Traits in scope for a given module.
     /// See `collect_intra_doc_links::traits_implemented_by` for more details.
     pub(crate) traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
-    pub(crate) all_traits: Option<Vec<DefId>>,
     pub(crate) all_trait_impls: Option<Vec<DefId>>,
     pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>,
 }
@@ -135,12 +133,6 @@ impl<'tcx> DocContext<'tcx> {
         }
     }
 
-    pub(crate) fn with_all_traits(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
-        let all_traits = self.resolver_caches.all_traits.take();
-        f(self, all_traits.as_ref().expect("`all_traits` are already borrowed"));
-        self.resolver_caches.all_traits = all_traits;
-    }
-
     pub(crate) fn with_all_trait_impls(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
         let all_trait_impls = self.resolver_caches.all_trait_impls.take();
         f(self, all_trait_impls.as_ref().expect("`all_trait_impls` are already borrowed"));
@@ -286,7 +278,6 @@ pub(crate) fn create_config(
         output_file: None,
         output_dir: None,
         file_loader: None,
-        diagnostic_output: DiagnosticOutput::Default,
         lint_caps,
         parse_sess_created: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
@@ -355,14 +346,8 @@ pub(crate) fn run_global_ctxt(
     });
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
-    let auto_traits = resolver_caches
-        .all_traits
-        .as_ref()
-        .expect("`all_traits` are already borrowed")
-        .iter()
-        .copied()
-        .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
-        .collect();
+    let auto_traits =
+        tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect();
     let access_levels = tcx.privacy_access_levels(()).map_id(Into::into);
 
     let mut ctxt = DocContext {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index f4ec60735a8..db70029f6ec 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -14,11 +14,10 @@ use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::attr::InnerAttrPolicy;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::parse::ParseSess;
-use rustc_session::{lint, DiagnosticOutput, Session};
+use rustc_session::{lint, Session};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
-use rustc_span::Symbol;
 use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
 use rustc_target::spec::TargetTriple;
 use tempfile::Builder as TempFileBuilder;
@@ -80,7 +79,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
         cg: options.codegen_options.clone(),
         externs: options.externs.clone(),
-        unstable_features: options.render_options.unstable_features,
+        unstable_features: options.unstable_features,
         actually_rustdoc: true,
         edition: options.edition,
         target_triple: options.target.clone(),
@@ -100,7 +99,6 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         output_file: None,
         output_dir: None,
         file_loader: None,
-        diagnostic_output: DiagnosticOutput::Default,
         lint_caps,
         parse_sess_created: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
@@ -125,7 +123,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
                     let opts = scrape_test_config(crate_attrs);
                     let enable_per_target_ignores = options.enable_per_target_ignores;
                     let mut collector = Collector::new(
-                        tcx.crate_name(LOCAL_CRATE),
+                        tcx.crate_name(LOCAL_CRATE).to_string(),
                         options,
                         false,
                         opts,
@@ -210,12 +208,13 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
 pub(crate) fn run_tests(
     mut test_args: Vec<String>,
     nocapture: bool,
-    tests: Vec<test::TestDescAndFn>,
+    mut tests: Vec<test::TestDescAndFn>,
 ) {
     test_args.insert(0, "rustdoctest".to_string());
     if nocapture {
         test_args.push("--nocapture".to_string());
     }
+    tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
     test::test_main(&test_args, tests, None);
 }
 
@@ -909,7 +908,7 @@ pub(crate) struct Collector {
     rustdoc_options: RustdocOptions,
     use_headers: bool,
     enable_per_target_ignores: bool,
-    crate_name: Symbol,
+    crate_name: String,
     opts: GlobalTestOptions,
     position: Span,
     source_map: Option<Lrc<SourceMap>>,
@@ -921,7 +920,7 @@ pub(crate) struct Collector {
 
 impl Collector {
     pub(crate) fn new(
-        crate_name: Symbol,
+        crate_name: String,
         rustdoc_options: RustdocOptions,
         use_headers: bool,
         opts: GlobalTestOptions,
@@ -984,7 +983,7 @@ impl Tester for Collector {
     fn add_test(&mut self, test: String, config: LangString, line: usize) {
         let filename = self.get_filename();
         let name = self.generate_name(line, &filename);
-        let crate_name = self.crate_name.to_string();
+        let crate_name = self.crate_name.clone();
         let opts = self.opts.clone();
         let edition = config.edition.unwrap_or(self.rustdoc_options.edition);
         let rustdoc_options = self.rustdoc_options.clone();
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 68eb5008583..5ce62224d35 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1433,6 +1433,7 @@ static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(||
 fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     let mut map = FxHashMap::default();
     // This is the list of IDs used in Javascript.
+    map.insert("help".into(), 1);
     map.insert("settings".into(), 1);
     map.insert("not-displayed".into(), 1);
     map.insert("alternative-display".into(), 1);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 902b9522429..5733d1f9c79 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -430,7 +430,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             extension_css,
             resource_suffix,
             static_root_path,
-            unstable_features,
             generate_redirect_map,
             show_type_layout,
             generate_link_to_definition,
@@ -511,7 +510,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             resource_suffix,
             static_root_path,
             fs: DocFS::new(sender),
-            codes: ErrorCodes::from(unstable_features.is_nightly_build()),
+            codes: ErrorCodes::from(options.unstable_features.is_nightly_build()),
             playground,
             all: RefCell::new(AllTypes::new()),
             errors: receiver,
@@ -581,6 +580,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         let crate_name = self.tcx().crate_name(LOCAL_CRATE);
         let final_file = self.dst.join(crate_name.as_str()).join("all.html");
         let settings_file = self.dst.join("settings.html");
+        let help_file = self.dst.join("help.html");
         let scrape_examples_help_file = self.dst.join("scrape-examples-help.html");
 
         let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
@@ -657,6 +657,39 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         );
         shared.fs.write(settings_file, v)?;
 
+        // Generating help page.
+        page.title = "Rustdoc help";
+        page.description = "Documentation for Rustdoc";
+        page.root_path = "./";
+
+        let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
+        let v = layout::render(
+            &shared.layout,
+            &page,
+            sidebar,
+            |buf: &mut Buffer| {
+                write!(
+                    buf,
+                    "<div class=\"main-heading\">\
+                     <h1 class=\"fqn\">Rustdoc help</h1>\
+                     <span class=\"out-of-band\">\
+                         <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
+                            Back\
+                        </a>\
+                     </span>\
+                     </div>\
+                     <noscript>\
+                        <section>\
+                            <p>You need to enable Javascript to use keyboard commands or search.</p>\
+                            <p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\
+                        </section>\
+                     </noscript>",
+                )
+            },
+            &shared.style_files,
+        );
+        shared.fs.write(help_file, v)?;
+
         if shared.layout.scrape_examples_extension {
             page.title = "About scraped examples";
             page.description = "How the scraped examples feature works in Rustdoc";
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1e162bf314b..eeec6f8fee7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1884,7 +1884,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     if !it.is_mod() {
         let path: String = cx.current.iter().map(|s| s.as_str()).intersperse("::").collect();
 
-        write!(buffer, "<h2 class=\"location\"><a href=\"index.html\">In {}</a></h2>", path);
+        write!(buffer, "<h2><a href=\"index.html\">In {}</a></h2>", path);
     }
 
     // Closes sidebar-elems div.
@@ -2259,13 +2259,7 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String
 }
 
 fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) {
-    write!(
-        buf,
-        "<h3 class=\"sidebar-title\">\
-             <a href=\"#{}\">{}</a>\
-         </h3>",
-        id, title
-    );
+    write!(buf, "<h3><a href=\"#{}\">{}</a></h3>", id, title);
 }
 
 fn print_sidebar_block(
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 0a19a99abf0..63b35f5d0df 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -14,7 +14,7 @@ rules.
 	display: none;
 }
 
-.sub {
+nav.sub {
 	/* The search bar and related controls don't work without JS */
 	display: none;
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 7989c521774..293c9787609 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -171,7 +171,7 @@ h1.fqn {
 	 Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
 	Underlines elsewhere in the documentation break up visual flow and tend to invert
 	section hierarchies. */
-h2,
+.content h2,
 .top-doc .docblock > h3,
 .top-doc .docblock > h4 {
 	border-bottom: 1px solid var(--headings-border-bottom-color);
@@ -184,7 +184,6 @@ h4.code-header {
 }
 .code-header {
 	font-weight: 600;
-	border-bottom-style: none;
 	margin: 0;
 	padding: 0;
 }
@@ -199,7 +198,7 @@ h1, h2, h3, h4, h5, h6,
 .out-of-band,
 span.since,
 a.srclink,
-#help-button > button,
+#help-button > a,
 details.rustdoc-toggle.top-doc > summary,
 details.rustdoc-toggle.non-exhaustive > summary,
 .scraped-example-title,
@@ -229,44 +228,44 @@ h1 a,
 	color: var(--main-color);
 }
 
-span.enum, a.enum,
-span.struct, a.struct,
-span.union, a.union,
-span.primitive, a.primitive,
-span.type, a.type,
-span.foreigntype, a.foreigntype {
+.content span.enum, .content a.enum,
+.content span.struct, .content a.struct,
+.content span.union, .content a.union,
+.content span.primitive, .content a.primitive,
+.content span.type, .content a.type,
+.content span.foreigntype, .content a.foreigntype {
 	color: var(--type-link-color);
 }
 
-span.trait, a.trait,
-span.traitalias, a.traitalias {
+.content span.trait, .content a.trait,
+.content span.traitalias, .content a.traitalias {
 	color: var(--trait-link-color);
 }
 
-span.associatedtype, a.associatedtype,
-span.constant, a.constant,
-span.static, a.static {
+.content span.associatedtype, .content a.associatedtype,
+.content span.constant, .content a.constant,
+.content span.static, .content a.static {
 	color: var(--assoc-item-link-color);
 }
 
-span.fn, a.fn,
-.fnname,
-span.method, a.method,
-span.tymethod, a.tymethod {
+.content span.fn, .content a.fn,
+.content .fnname,
+.content span.method, .content a.method,
+.content span.tymethod, .content a.tymethod {
 	color: var(--function-link-color);
 }
 
-span.attr, a.attr,
-span.derive, a.derive,
-span.macro, a.macro {
+.content span.attr, .content a.attr,
+.content span.derive, .content a.derive,
+.content span.macro, .content a.macro {
 	color: var(--macro-link-color);
 }
 
-span.mod, a.mod {
+.content span.mod, .content a.mod {
 	color: var(--mod-link-color);
 }
 
-span.keyword, a.keyword {
+.content span.keyword, .content a.keyword {
 	color: var(--keyword-link-color);
 }
 
@@ -365,22 +364,11 @@ img {
 	overflow: visible;
 }
 
-.sub-container {
-	display: flex;
-	flex-direction: row;
-	flex-wrap: nowrap;
-}
-
 .sub-logo-container {
-	display: none;
-	margin-right: 20px;
+	line-height: 0;
 }
 
-.source .sub-logo-container {
-	display: block;
-}
-
-.source .sub-logo-container > img {
+.sub-logo-container > img {
 	height: 60px;
 	width: 60px;
 	object-fit: contain;
@@ -401,15 +389,6 @@ img {
 	left: 0;
 }
 
-.sidebar-elems,
-.sidebar > .location {
-	padding-left: 24px;
-}
-
-.sidebar .location {
-	overflow-wrap: anywhere;
-}
-
 .rustdoc.source .sidebar {
 	width: 50px;
 	min-width: 0px;
@@ -441,6 +420,7 @@ img {
 
 .source-sidebar-expanded .source .sidebar {
 	overflow-y: auto;
+	width: 300px;
 }
 
 .source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) {
@@ -508,8 +488,8 @@ ul.block, .block li {
 }
 
 .block a,
-.sidebar h3 a,
-h2.location a {
+.sidebar h2 a,
+.sidebar h3 a {
 	display: block;
 	padding: 0.25rem;
 	margin-left: -0.25rem;
@@ -519,8 +499,7 @@ h2.location a {
 }
 
 .sidebar h2 {
-	border-bottom: none;
-	font-weight: 500;
+	overflow-wrap: anywhere;
 	padding: 0;
 	margin: 0;
 	margin-top: 0.7rem;
@@ -529,11 +508,15 @@ h2.location a {
 
 .sidebar h3 {
 	font-size: 1.125rem; /* 18px */
-	font-weight: 500;
 	padding: 0;
 	margin: 0;
 }
 
+.sidebar-elems,
+.sidebar > h2 {
+	padding-left: 24px;
+}
+
 .sidebar a, .sidebar .current {
 	color: var(--sidebar-link-color);
 }
@@ -650,7 +633,6 @@ pre.example-line-numbers {
 .out-of-band {
 	flex-grow: 0;
 	font-size: 1.125rem;
-	font-weight: normal;
 }
 
 .docblock code, .docblock-short code,
@@ -705,15 +687,21 @@ pre, .rustdoc.source .example-wrap {
 }
 
 nav.sub {
-	position: relative;
-	font-size: 1rem;
 	flex-grow: 1;
-	margin-bottom: 25px;
+	flex-flow: row nowrap;
+	margin: 4px 0 25px 0;
+	display: flex;
+	align-items: center;
+}
+nav.sub form {
+	flex-grow: 1;
 }
 .source nav.sub {
+	margin: 0 0 15px 0;
+}
+.source nav.sub form {
 	margin-left: 32px;
 }
-nav.sub form { display: inline; }
 
 a {
 	text-decoration: none;
@@ -806,7 +794,6 @@ table,
 	position: relative;
 	display: flex;
 	height: 34px;
-	margin-top: 4px;
 }
 .search-results-title {
 	margin-top: 0;
@@ -932,7 +919,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	flex-flow: row wrap;
 }
 
-.search-results .result-name, .search-results div.desc, .search-results .result-description {
+.search-results .result-name, .search-results div.desc {
 	width: 50%;
 }
 .search-results .result-name {
@@ -974,32 +961,33 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	color: var(--main-color);
 }
 
-#help-button .popover {
+/* use larger max-width for help popover, but not for help.html */
+#help.popover {
 	max-width: 600px;
 }
 
-#help-button .popover::before {
+#help.popover::before {
 	right: 48px;
 }
 
-#help-button dt {
+#help dt {
 	float: left;
 	clear: left;
 	display: block;
 	margin-right: 0.5rem;
 }
-#help-button span.top, #help-button span.bottom {
+#help span.top, #help span.bottom {
 	text-align: center;
 	display: block;
 	font-size: 1.125rem;
 }
-#help-button span.top {
+#help span.top {
 	margin: 10px 0;
 	border-bottom: 1px solid var(--border-color);
 	padding-bottom: 4px;
 	margin-bottom: 6px;
 }
-#help-button span.bottom {
+#help span.bottom {
 	clear: both;
 	border-top: 1px solid var(--border-color);
 }
@@ -1433,24 +1421,29 @@ h3.variant {
 	outline: none;
 }
 
-#settings-menu > a, #help-button > button, #copy-path {
-	padding: 5px;
+#settings-menu > a, #help-button > a, #copy-path {
 	width: 33px;
-	border: 1px solid var(--border-color);
-	border-radius: 2px;
 	cursor: pointer;
 	line-height: 1.5;
 }
 
-#settings-menu > a, #help-button > button {
+#settings-menu > a, #help-button > a {
 	padding: 5px;
 	height: 100%;
 	display: block;
 	background-color: var(--button-background-color);
+	border: 1px solid var(--border-color);
+	border-radius: 2px;
 }
 
 #copy-path {
 	color: var(--copy-path-button-color);
+	background: var(--main-background-color);
+	height: 34px;
+	margin-left: 10px;
+	padding: 0;
+	padding-left: 2px;
+	border: 0;
 }
 #copy-path > img {
 	filter: var(--copy-path-img-filter);
@@ -1471,26 +1464,7 @@ h3.variant {
 	animation: rotating 2s linear infinite;
 }
 
-.setting-line .radio-line input:checked {
-	box-shadow: inset 0 0 0 3px var(--main-background-color);
-	background-color: var(--settings-input-color);
-}
-.setting-line .radio-line input:focus {
-	box-shadow: 0 0 1px 1px var(--settings-input-color);
-}
-/* In here we combine both `:focus` and `:checked` properties. */
-.setting-line .radio-line input:checked:focus {
-	box-shadow: inset 0 0 0 3px var(--main-background-color),
-		0 0 2px 2px var(--settings-input-color);
-}
-.setting-line .radio-line input:hover {
-	border-color: var(--settings-input-color) !important;
-}
-input:checked + .slider {
-	background-color: var(--settings-input-color);
-}
-
-#help-button > button {
+#help-button > a {
 	text-align: center;
 	/* Rare exception to specifying font sizes in rem. Since this is acting
 	   as an icon, it's okay to specify their sizes in pixels. */
@@ -1498,15 +1472,6 @@ input:checked + .slider {
 	padding-top: 2px;
 }
 
-#copy-path {
-	height: 34px;
-	background-color: var(--main-background-color);
-	margin-left: 10px;
-	padding: 0;
-	padding-left: 2px;
-	border: 0;
-}
-
 kbd {
 	display: inline-block;
 	padding: 3px 5px;
@@ -1569,6 +1534,7 @@ details.dir-entry a {
 	https://developer.mozilla.org/en-US/docs/Web/CSS/contain */
 details.rustdoc-toggle {
 	contain: layout;
+	position: relative;
 }
 
 /* The hideme class is used on summary tags that contain a span with
@@ -1662,10 +1628,6 @@ details.rustdoc-toggle[open] > summary.hideme {
 	position: absolute;
 }
 
-details.rustdoc-toggle {
-	position: relative;
-}
-
 details.rustdoc-toggle[open] > summary.hideme > span {
 	display: none;
 }
@@ -1699,37 +1661,20 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 	display: inline-block;
 }
 
-/* Media Queries */
-
-/*
-WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY;
-If you update this line, then you also need to update the line with the same warning
-in storage.js plus the media query with (max-width: 700px)
-*/
-@media (min-width: 701px) {
-	/* In case there is no documentation before a code block, we need to add some margin at the top
-	to prevent an overlay between the "collapse toggle" and the information tooltip.
-	However, it's not needed with smaller screen width because the doc/code block is always put
-	"one line" below. */
-	.docblock > .example-wrap:first-child .tooltip {
-		margin-top: 16px;
-	}
-
-	/* When we expand the sidebar on the source code page, we hide the logo on the left of the
-	search bar to have more space. */
-	.source-sidebar-expanded .source .sidebar + main .width-limiter .sub-logo-container.rust-logo {
-		display: none;
-	}
-
-	.source-sidebar-expanded .source .sidebar {
-		width: 300px;
-	}
+/* In case there is no documentation before a code block, we need to add some margin at the top
+to prevent an overlay between the "collapse toggle" and the information tooltip.
+However, it's not needed with smaller screen width because the doc/code block is always put
+"one line" below. */
+.docblock > .example-wrap:first-child .tooltip {
+	margin-top: 16px;
 }
 
+/* Media Queries */
+
 /*
 WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
 If you update this line, then you also need to update the line with the same warning
-in storage.js plus the media query with (min-width: 701px)
+in storage.js
 */
 @media (max-width: 700px) {
 	/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
@@ -1811,18 +1756,10 @@ in storage.js plus the media query with (min-width: 701px)
 		width: 0;
 	}
 
-	.mobile-topbar .location a {
-		padding: 0;
-		margin: 0;
-	}
-
-	.mobile-topbar .location {
-		border: none;
-		padding: 0;
+	.mobile-topbar h2 {
+		padding-bottom: 0;
 		margin: auto 0.5em auto auto;
-		text-overflow: ellipsis;
 		overflow: hidden;
-		white-space: nowrap;
 		/* Rare exception to specifying font sizes in rem. Since the topbar
 		   height is specified in pixels, this also has to be specified in
 		   pixels to avoid overflowing the topbar when the user sets a bigger
@@ -1830,6 +1767,13 @@ in storage.js plus the media query with (min-width: 701px)
 		font-size: 24px;
 	}
 
+	.mobile-topbar h2 a {
+		display: block;
+		text-overflow: ellipsis;
+		overflow: hidden;
+		white-space: nowrap;
+	}
+
 	.mobile-topbar .logo-container {
 		max-height: 45px;
 	}
@@ -1872,10 +1816,6 @@ in storage.js plus the media query with (min-width: 701px)
 		margin-left: 0px;
 	}
 
-	.source .content {
-		margin-top: 10px;
-	}
-
 	.anchor {
 		display: none !important;
 	}
@@ -1958,10 +1898,10 @@ in storage.js plus the media query with (min-width: 701px)
 		border-bottom: 1px solid #aaa9;
 		padding: 5px 0px;
 	}
-	.search-results .result-name, .search-results div.desc, .search-results .result-description {
+	.search-results .result-name, .search-results div.desc {
 		width: 100%;
 	}
-	.search-results div.desc, .search-results .result-description, .item-right {
+	.search-results div.desc, .item-right {
 		padding-left: 2em;
 	}
 
@@ -1984,6 +1924,11 @@ in storage.js plus the media query with (min-width: 701px)
 	.impl-items > .item-info {
 		margin-left: 34px;
 	}
+
+	.source nav.sub {
+		margin: 0;
+		padding: 8px;
+	}
 }
 
 @media print {
@@ -2003,10 +1948,6 @@ in storage.js plus the media query with (min-width: 701px)
 }
 
 @media (max-width: 464px) {
-	#crate-search {
-		border-radius: 4px;
-	}
-
 	.docblock {
 		margin-left: 12px;
 	}
@@ -2016,15 +1957,15 @@ in storage.js plus the media query with (min-width: 701px)
 		overflow-wrap: anywhere;
 	}
 
-	.sub-container {
+	nav.sub {
 		flex-direction: column;
 	}
 
-	.sub-logo-container {
-		align-self: center;
+	nav.sub form {
+		align-self: stretch;
 	}
 
-	.source .sub-logo-container > img {
+	.sub-logo-container > img {
 		height: 35px;
 		width: 35px;
 	}
@@ -2037,8 +1978,8 @@ in storage.js plus the media query with (min-width: 701px)
 	}
 }
 
-.method-toggle summary,
-.implementors-toggle summary,
+.method-toggle > summary,
+.implementors-toggle > summary,
 .impl,
 #implementors-list > .docblock,
 .impl-items > section,
@@ -2047,10 +1988,7 @@ in storage.js plus the media query with (min-width: 701px)
 	margin-bottom: 0.75em;
 }
 
-.method-toggle[open]:not(:last-child) {
-	margin-bottom: 2em;
-}
-
+.method-toggle[open]:not(:last-child),
 .implementors-toggle[open]:not(:last-child) {
 	margin-bottom: 2em;
 }
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index 821c4e978e8..83939f63b4e 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -89,3 +89,22 @@ input:checked + .slider:before {
 #settings .setting-line {
 	margin: 1.2em 0.6em;
 }
+
+.setting-line .radio-line input:checked {
+	box-shadow: inset 0 0 0 3px var(--main-background-color);
+	background-color: var(--settings-input-color);
+}
+.setting-line .radio-line input:focus {
+	box-shadow: 0 0 1px 1px var(--settings-input-color);
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+	box-shadow: inset 0 0 0 3px var(--main-background-color),
+		0 0 2px 2px var(--settings-input-color);
+}
+.setting-line .radio-line input:hover {
+	border-color: var(--settings-input-color) !important;
+}
+input:checked + .slider {
+	background-color: var(--settings-input-color);
+}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index ee74f81926a..33817c16808 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -248,7 +248,7 @@ kbd {
 	box-shadow: inset 0 -1px 0 #5c6773;
 }
 
-#settings-menu > a, #help-button > button {
+#settings-menu > a, #help-button > a {
 	color: #fff;
 }
 
@@ -257,7 +257,7 @@ kbd {
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button > button:hover, #help-button > button:focus {
+#help-button > a:hover, #help-button > a:focus {
 	border-color: #e0e0e0;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 06baceca01d..d88710288b9 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -153,12 +153,12 @@ kbd {
 	box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#settings-menu > a, #help-button > button {
+#settings-menu > a, #help-button > a {
 	color: #000;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button > button:hover, #help-button > button:focus {
+#help-button > a:hover, #help-button > a:focus {
 	border-color: #ffb900;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 058974c078c..cadc71dab95 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -147,8 +147,12 @@ kbd {
 	box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
+#settings-menu > a, #help-button > a {
+	color: #000;
+}
+
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button > button:hover, #help-button > button:focus {
+#help-button > a:hover, #help-button > a:focus {
 	border-color: #717171;
 }
 
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index dc5b8acdf53..0b816eace64 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -55,7 +55,7 @@ function blurHandler(event, parentElem, hideCallback) {
 function setMobileTopbar() {
     // FIXME: It would be nicer to generate this text content directly in HTML,
     // but with the current code it's hard to get the right information in the right place.
-    const mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
+    const mobileLocationTitle = document.querySelector(".mobile-topbar h2");
     const locationTitle = document.querySelector(".sidebar h2.location");
     if (mobileLocationTitle && locationTitle) {
         mobileLocationTitle.innerHTML = locationTitle.innerHTML;
@@ -192,6 +192,8 @@ function loadCss(cssFileName) {
 }
 
 (function() {
+    const isHelpPage = window.location.pathname.endsWith("/help.html");
+
     function loadScript(url) {
         const script = document.createElement("script");
         script.src = url;
@@ -199,6 +201,9 @@ function loadCss(cssFileName) {
     }
 
     getSettingsButton().onclick = event => {
+        if (event.ctrlKey || event.altKey || event.metaKey) {
+            return;
+        }
         addClass(getSettingsButton(), "rotate");
         event.preventDefault();
         // Sending request for the CSS and the JS files at the same time so it will
@@ -404,9 +409,12 @@ function loadCss(cssFileName) {
                 break;
 
             case "+":
+                ev.preventDefault();
+                expandAllDocs();
+                break;
             case "-":
                 ev.preventDefault();
-                toggleAllDocs();
+                collapseAllDocs();
                 break;
 
             case "?":
@@ -609,15 +617,31 @@ function loadCss(cssFileName) {
         sidebarElems.appendChild(ul);
     }
 
+    function expandAllDocs() {
+        const innerToggle = document.getElementById(toggleAllDocsId);
+        removeClass(innerToggle, "will-expand");
+        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+            if (!hasClass(e, "type-contents-toggle")) {
+                e.open = true;
+            }
+        });
+        innerToggle.title = "collapse all docs";
+        innerToggle.children[0].innerText = "\u2212"; // "\u2212" is "−" minus sign
+    }
 
-    function labelForToggleButton(sectionIsCollapsed) {
-        if (sectionIsCollapsed) {
-            // button will expand the section
-            return "+";
-        }
-        // button will collapse the section
-        // note that this text is also set in the HTML template in ../render/mod.rs
-        return "\u2212"; // "\u2212" is "−" minus sign
+    function collapseAllDocs() {
+        const innerToggle = document.getElementById(toggleAllDocsId);
+        addClass(innerToggle, "will-expand");
+        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+            if (e.parentNode.id !== "implementations-list" ||
+                (!hasClass(e, "implementors-toggle") &&
+                 !hasClass(e, "type-contents-toggle"))
+            ) {
+                e.open = false;
+            }
+        });
+        innerToggle.title = "expand all docs";
+        innerToggle.children[0].innerText = "+";
     }
 
     function toggleAllDocs() {
@@ -625,29 +649,11 @@ function loadCss(cssFileName) {
         if (!innerToggle) {
             return;
         }
-        let sectionIsCollapsed = false;
         if (hasClass(innerToggle, "will-expand")) {
-            removeClass(innerToggle, "will-expand");
-            onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
-                if (!hasClass(e, "type-contents-toggle")) {
-                    e.open = true;
-                }
-            });
-            innerToggle.title = "collapse all docs";
+            expandAllDocs();
         } else {
-            addClass(innerToggle, "will-expand");
-            onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
-                if (e.parentNode.id !== "implementations-list" ||
-                    (!hasClass(e, "implementors-toggle") &&
-                     !hasClass(e, "type-contents-toggle"))
-                ) {
-                    e.open = false;
-                }
-            });
-            sectionIsCollapsed = true;
-            innerToggle.title = "expand all docs";
+            collapseAllDocs();
         }
-        innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
     }
 
     (function() {
@@ -728,43 +734,57 @@ function loadCss(cssFileName) {
 
     let oldSidebarScrollPosition = null;
 
-    function showSidebar() {
+    // Scroll locking used both here and in source-script.js
+
+    window.rustdocMobileScrollLock = function() {
         const mobile_topbar = document.querySelector(".mobile-topbar");
-        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && mobile_topbar) {
+        if (window.innerWidth <= window.RUSTDOC_MOBILE_BREAKPOINT) {
             // This is to keep the scroll position on mobile.
             oldSidebarScrollPosition = window.scrollY;
             document.body.style.width = `${document.body.offsetWidth}px`;
             document.body.style.position = "fixed";
             document.body.style.top = `-${oldSidebarScrollPosition}px`;
-            mobile_topbar.style.top = `${oldSidebarScrollPosition}px`;
-            mobile_topbar.style.position = "relative";
+            if (mobile_topbar) {
+                mobile_topbar.style.top = `${oldSidebarScrollPosition}px`;
+                mobile_topbar.style.position = "relative";
+            }
         } else {
             oldSidebarScrollPosition = null;
         }
-        const sidebar = document.getElementsByClassName("sidebar")[0];
-        addClass(sidebar, "shown");
-    }
+    };
 
-    function hideSidebar() {
+    window.rustdocMobileScrollUnlock = function() {
         const mobile_topbar = document.querySelector(".mobile-topbar");
-        if (oldSidebarScrollPosition !== null && mobile_topbar) {
+        if (oldSidebarScrollPosition !== null) {
             // This is to keep the scroll position on mobile.
             document.body.style.width = "";
             document.body.style.position = "";
             document.body.style.top = "";
-            mobile_topbar.style.top = "";
-            mobile_topbar.style.position = "";
+            if (mobile_topbar) {
+                mobile_topbar.style.top = "";
+                mobile_topbar.style.position = "";
+            }
             // The scroll position is lost when resetting the style, hence why we store it in
             // `oldSidebarScrollPosition`.
             window.scrollTo(0, oldSidebarScrollPosition);
             oldSidebarScrollPosition = null;
         }
+    };
+
+    function showSidebar() {
+        window.rustdocMobileScrollLock();
+        const sidebar = document.getElementsByClassName("sidebar")[0];
+        addClass(sidebar, "shown");
+    }
+
+    function hideSidebar() {
+        window.rustdocMobileScrollUnlock();
         const sidebar = document.getElementsByClassName("sidebar")[0];
         removeClass(sidebar, "shown");
     }
 
     window.addEventListener("resize", () => {
-        if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT &&
+        if (window.innerWidth > window.RUSTDOC_MOBILE_BREAKPOINT &&
             oldSidebarScrollPosition !== null) {
             // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
             // we need to switch away from mobile mode and make the main content area scrollable.
@@ -873,7 +893,10 @@ function loadCss(cssFileName) {
         rustdoc_version.appendChild(rustdoc_version_code);
 
         const container = document.createElement("div");
-        container.className = "popover";
+        if (!isHelpPage) {
+            container.className = "popover";
+        }
+        container.id = "help";
         container.style.display = "none";
 
         const side_by_side = document.createElement("div");
@@ -885,15 +908,22 @@ function loadCss(cssFileName) {
         container.appendChild(side_by_side);
         container.appendChild(rustdoc_version);
 
-        const help_button = getHelpButton();
-        help_button.appendChild(container);
-
-        container.onblur = helpBlurHandler;
-        container.onclick = event => {
-            event.preventDefault();
-        };
-        help_button.onblur = helpBlurHandler;
-        help_button.children[0].onblur = helpBlurHandler;
+        if (isHelpPage) {
+            const help_section = document.createElement("section");
+            help_section.appendChild(container);
+            document.getElementById("main-content").appendChild(help_section);
+            container.style.display = "block";
+        } else {
+            const help_button = getHelpButton();
+            help_button.appendChild(container);
+
+            container.onblur = helpBlurHandler;
+            container.onclick = event => {
+                event.preventDefault();
+            };
+            help_button.onblur = helpBlurHandler;
+            help_button.children[0].onblur = helpBlurHandler;
+        }
 
         return container;
     }
@@ -934,19 +964,43 @@ function loadCss(cssFileName) {
         }
     }
 
-    document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => {
-        const target = event.target;
-        if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) {
-            return;
-        }
-        const menu = getHelpMenu(true);
-        const shouldShowHelp = menu.style.display === "none";
-        if (shouldShowHelp) {
-            showHelp();
-        } else {
-            window.hidePopoverMenus();
-        }
-    });
+    if (isHelpPage) {
+        showHelp();
+        document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
+            // Already on the help page, make help button a no-op.
+            const target = event.target;
+            if (target.tagName !== "A" ||
+                target.parentElement.id !== HELP_BUTTON_ID ||
+                event.ctrlKey ||
+                event.altKey ||
+                event.metaKey) {
+                return;
+            }
+            event.preventDefault();
+        });
+    } else {
+        document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
+            // By default, have help button open docs in a popover.
+            // If user clicks with a moderator, though, use default browser behavior,
+            // probably opening in a new window or tab.
+            const target = event.target;
+            if (target.tagName !== "A" ||
+                target.parentElement.id !== HELP_BUTTON_ID ||
+                event.ctrlKey ||
+                event.altKey ||
+                event.metaKey) {
+                return;
+            }
+            event.preventDefault();
+            const menu = getHelpMenu(true);
+            const shouldShowHelp = menu.style.display === "none";
+            if (shouldShowHelp) {
+                showHelp();
+            } else {
+                window.hidePopoverMenus();
+            }
+        });
+    }
 
     setMobileTopbar();
     addSidebarItems();
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 1c5d33e2127..5e1c7e6f03e 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -216,7 +216,9 @@
         const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`;
         const el = document.createElement(elementKind);
         el.id = "settings";
-        el.className = "popover";
+        if (!isSettingsPage) {
+            el.className = "popover";
+        }
         el.innerHTML = innerHTML;
 
         if (isSettingsPage) {
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 8286e9201e6..0b9368dd899 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -10,7 +10,6 @@
 (function() {
 
 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
-let oldScrollPosition = null;
 
 const NAME_OFFSET = 0;
 const DIRS_OFFSET = 1;
@@ -70,44 +69,18 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
 function toggleSidebar() {
     const child = this.parentNode.children[0];
     if (child.innerText === ">") {
-        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
-            // This is to keep the scroll position on mobile.
-            oldScrollPosition = window.scrollY;
-            document.body.style.position = "fixed";
-            document.body.style.top = `-${oldScrollPosition}px`;
-        } else {
-            oldScrollPosition = null;
-        }
+        window.rustdocMobileScrollLock();
         addClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = "<";
         updateLocalStorage("source-sidebar-show", "true");
     } else {
-        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
-            // This is to keep the scroll position on mobile.
-            document.body.style.position = "";
-            document.body.style.top = "";
-            // The scroll position is lost when resetting the style, hence why we store it in
-            // `oldScrollPosition`.
-            window.scrollTo(0, oldScrollPosition);
-            oldScrollPosition = null;
-        }
+        window.rustdocMobileScrollUnlock();
         removeClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = ">";
         updateLocalStorage("source-sidebar-show", "false");
     }
 }
 
-window.addEventListener("resize", () => {
-    if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
-        // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
-        // we need to switch away from mobile mode and make the main content area scrollable.
-        document.body.style.position = "";
-        document.body.style.top = "";
-        window.scrollTo(0, oldScrollPosition);
-        oldScrollPosition = null;
-    }
-});
-
 function createSidebarToggle() {
     const sidebarToggle = document.createElement("div");
     sidebarToggle.id = "sidebar-toggle";
@@ -125,7 +98,7 @@ function createSidebarToggle() {
     return sidebarToggle;
 }
 
-// This function is called from "source-files.js", generated in `html/render/mod.rs`.
+// This function is called from "source-files.js", generated in `html/render/write_shared.rs`.
 // eslint-disable-next-line no-unused-vars
 function createSourceSidebar() {
     const container = document.querySelector("nav.sidebar");
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 0c5389d45e5..b462a2c50f1 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -10,9 +10,9 @@ window.currentTheme = document.getElementById("themeStyle");
 window.mainTheme = document.getElementById("mainThemeStyle");
 
 // WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
-// If you update this line, then you also need to update the two media queries with the same
+// If you update this line, then you also need to update the media query with the same
 // warning in rustdoc.css
-window.RUSTDOC_MOBILE_BREAKPOINT = 701;
+window.RUSTDOC_MOBILE_BREAKPOINT = 700;
 
 const settingsDataset = (function() {
     const settingsElement = document.getElementById("default-settings");
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 01a2ea6c2ec..2a111f94e50 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -85,7 +85,7 @@
             {%- endif -%}
             </div> {#- -#}
         </a> {#- -#}
-        <h2 class="location"></h2> {#- -#}
+        <h2></h2> {#- -#}
     </nav> {#- -#}
     {%- endif -%}
     <nav class="sidebar"> {#- -#}
@@ -102,7 +102,8 @@
     </nav> {#- -#}
     <main> {#- -#}
         <div class="width-limiter"> {#- -#}
-            <div class="sub-container"> {#- -#}
+            <nav class="sub"> {#- -#}
+                {%- if page.css_class == "source" -%}
                 <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
                     {%- if !layout.logo.is_empty()  %}
                         <img src="{{layout.logo}}" alt="logo"> {#- -#}
@@ -110,30 +111,29 @@
                         <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
                     {%- endif -%}
                 </a> {#- -#}
-                <nav class="sub"> {#- -#}
-                    <form class="search-form"> {#- -#}
-                        <div class="search-container"> {#- -#}
-                            <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
-                            <input {# -#}
-                                class="search-input" {# -#}
-                                name="search" {# -#}
-                                autocomplete="off" {# -#}
-                                spellcheck="false" {# -#}
-                                placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
-                                type="search"> {#- -#}
-                            <div id="help-button" title="help" tabindex="-1"> {#- -#}
-                                <button type="button">?</button> {#- -#}
-                            </div> {#- -#}
-                            <div id="settings-menu" tabindex="-1"> {#- -#}
-                                <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
-                                    <img width="22" height="22" alt="Change settings" {# -#}
-                                     src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
-                                </a> {#- -#}
-                            </div> {#- -#}
+                {%- endif -%}
+                <form class="search-form"> {#- -#}
+                    <div class="search-container"> {#- -#}
+                        <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
+                        <input {# -#}
+                            class="search-input" {# -#}
+                            name="search" {# -#}
+                            autocomplete="off" {# -#}
+                            spellcheck="false" {# -#}
+                            placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+                            type="search"> {#- -#}
+                        <div id="help-button" title="help" tabindex="-1"> {#- -#}
+                            <a href="{{page.root_path|safe}}help.html">?</a> {#- -#}
                         </div> {#- -#}
-                    </form> {#- -#}
-                </nav> {#- -#}
-            </div> {#- -#}
+                        <div id="settings-menu" tabindex="-1"> {#- -#}
+                            <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
+                                <img width="22" height="22" alt="Change settings" {# -#}
+                                 src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
+                            </a> {#- -#}
+                        </div> {#- -#}
+                    </div> {#- -#}
+                </form> {#- -#}
+            </nav> {#- -#}
             <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
         </div> {#- -#}
     </main> {#- -#}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ef01b854e5a..793061a9f7a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -674,39 +674,6 @@ fn usage(argv0: &str) {
 /// A result type used by several functions under `main()`.
 type MainResult = Result<(), ErrorGuaranteed>;
 
-fn main_args(at_args: &[String]) -> MainResult {
-    let args = rustc_driver::args::arg_expand_all(at_args);
-
-    let mut options = getopts::Options::new();
-    for option in opts() {
-        (option.apply)(&mut options);
-    }
-    let matches = match options.parse(&args[1..]) {
-        Ok(m) => m,
-        Err(err) => {
-            early_error(ErrorOutputType::default(), &err.to_string());
-        }
-    };
-
-    // Note that we discard any distinction between different non-zero exit
-    // codes from `from_matches` here.
-    let options = match config::Options::from_matches(&matches, args) {
-        Ok(opts) => opts,
-        Err(code) => {
-            return if code == 0 {
-                Ok(())
-            } else {
-                Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
-            };
-        }
-    };
-    rustc_interface::util::run_in_thread_pool_with_globals(
-        options.edition,
-        1, // this runs single-threaded, even in a parallel compiler
-        move || main_options(options),
-    )
-}
-
 fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult {
     match res {
         Ok(()) => Ok(()),
@@ -737,7 +704,33 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     }
 }
 
-fn main_options(options: config::Options) -> MainResult {
+fn main_args(at_args: &[String]) -> MainResult {
+    let args = rustc_driver::args::arg_expand_all(at_args);
+
+    let mut options = getopts::Options::new();
+    for option in opts() {
+        (option.apply)(&mut options);
+    }
+    let matches = match options.parse(&args[1..]) {
+        Ok(m) => m,
+        Err(err) => {
+            early_error(ErrorOutputType::default(), &err.to_string());
+        }
+    };
+
+    // Note that we discard any distinction between different non-zero exit
+    // codes from `from_matches` here.
+    let (options, render_options) = match config::Options::from_matches(&matches, args) {
+        Ok(opts) => opts,
+        Err(code) => {
+            return if code == 0 {
+                Ok(())
+            } else {
+                Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+            };
+        }
+    };
+
     let diag = core::new_handler(
         options.error_format,
         None,
@@ -749,9 +742,18 @@ fn main_options(options: config::Options) -> MainResult {
         (true, true) => return wrap_return(&diag, markdown::test(options)),
         (true, false) => return doctest::run(options),
         (false, true) => {
+            let input = options.input.clone();
+            let edition = options.edition;
+            let config = core::create_config(options);
+
+            // `markdown::render` can invoke `doctest::make_test`, which
+            // requires session globals and a thread pool, so we use
+            // `run_compiler`.
             return wrap_return(
                 &diag,
-                markdown::render(&options.input, options.render_options, options.edition),
+                interface::run_compiler(config, |_compiler| {
+                    markdown::render(&input, render_options, edition)
+                }),
             );
         }
         (false, false) => {}
@@ -772,14 +774,12 @@ fn main_options(options: config::Options) -> MainResult {
     let crate_version = options.crate_version.clone();
 
     let output_format = options.output_format;
-    // FIXME: fix this clone (especially render_options)
     let externs = options.externs.clone();
-    let render_options = options.render_options.clone();
     let scrape_examples_options = options.scrape_examples_options.clone();
-    let document_private = options.render_options.document_private;
+
     let config = core::create_config(options);
 
-    interface::create_compiler_and_run(config, |compiler| {
+    interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
 
         if sess.opts.describe_lints {
@@ -811,7 +811,7 @@ fn main_options(options: config::Options) -> MainResult {
                         sess,
                         krate,
                         externs,
-                        document_private,
+                        render_options.document_private,
                     )
                 });
                 (resolver.clone(), resolver_caches)
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 0b557ef244e..044e051440c 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -5,7 +5,6 @@ use std::path::Path;
 
 use rustc_span::edition::Edition;
 use rustc_span::source_map::DUMMY_SP;
-use rustc_span::Symbol;
 
 use crate::config::{Options, RenderOptions};
 use crate::doctest::{Collector, GlobalTestOptions};
@@ -36,6 +35,8 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
 
 /// Render `input` (e.g., "foo.md") into an HTML file in `output`
 /// (e.g., output = "bar" => "bar/foo.html").
+///
+/// Requires session globals to be available, for symbol interning.
 pub(crate) fn render<P: AsRef<Path>>(
     input: P,
     options: RenderOptions,
@@ -133,7 +134,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
     let mut opts = GlobalTestOptions::default();
     opts.no_crate_inject = true;
     let mut collector = Collector::new(
-        Symbol::intern(&options.input.display().to_string()),
+        options.input.display().to_string(),
         options.clone(),
         true,
         opts,
@@ -142,7 +143,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
         options.enable_per_target_ignores,
     );
     collector.set_position(DUMMY_SP);
-    let codes = ErrorCodes::from(options.render_options.unstable_features.is_nightly_build());
+    let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
 
     find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 3beda708bf2..3513c13d522 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -80,10 +80,10 @@ impl Res {
         }
     }
 
-    fn def_id(self, tcx: TyCtxt<'_>) -> DefId {
+    fn def_id(self, tcx: TyCtxt<'_>) -> Option<DefId> {
         match self {
-            Res::Def(_, id) => id,
-            Res::Primitive(prim) => *PrimitiveType::primitive_locations(tcx).get(&prim).unwrap(),
+            Res::Def(_, id) => Some(id),
+            Res::Primitive(prim) => PrimitiveType::primitive_locations(tcx).get(&prim).copied(),
         }
     }
 
@@ -1127,10 +1127,10 @@ impl LinkCollector<'_, '_> {
                     }
                 }
 
-                Some(ItemLink {
+                res.def_id(self.cx.tcx).map(|page_id| ItemLink {
                     link: ori_link.link.clone(),
                     link_text: link_text.clone(),
-                    page_id: res.def_id(self.cx.tcx),
+                    page_id,
                     fragment,
                 })
             }
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 38cfd7a27dd..d121a3e2aa4 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -37,7 +37,6 @@ pub(crate) fn early_resolve_intra_doc_links(
         markdown_links: Default::default(),
         doc_link_resolutions: Default::default(),
         traits_in_scope: Default::default(),
-        all_traits: Default::default(),
         all_trait_impls: Default::default(),
         all_macro_rules: Default::default(),
         document_private_items,
@@ -48,7 +47,6 @@ pub(crate) fn early_resolve_intra_doc_links(
     link_resolver.resolve_doc_links_local(&krate.attrs);
     link_resolver.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
     visit::walk_crate(&mut link_resolver, krate);
-    link_resolver.process_extern_impls();
 
     // FIXME: somehow rustdoc is still missing crates even though we loaded all
     // the known necessary crates. Load them all unconditionally until we find a way to fix this.
@@ -58,11 +56,12 @@ pub(crate) fn early_resolve_intra_doc_links(
         link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
     }
 
+    link_resolver.process_extern_impls();
+
     ResolverCaches {
         markdown_links: Some(link_resolver.markdown_links),
         doc_link_resolutions: link_resolver.doc_link_resolutions,
         traits_in_scope: link_resolver.traits_in_scope,
-        all_traits: Some(link_resolver.all_traits),
         all_trait_impls: Some(link_resolver.all_trait_impls),
         all_macro_rules: link_resolver.all_macro_rules,
     }
@@ -80,7 +79,6 @@ struct EarlyDocLinkResolver<'r, 'ra> {
     markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
     doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
     traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
-    all_traits: Vec<DefId>,
     all_trait_impls: Vec<DefId>,
     all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
     document_private_items: bool,
@@ -121,8 +119,6 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
         loop {
             let crates = Vec::from_iter(self.resolver.cstore().crates_untracked());
             for &cnum in &crates[start_cnum..] {
-                let all_traits =
-                    Vec::from_iter(self.resolver.cstore().traits_in_crate_untracked(cnum));
                 let all_trait_impls =
                     Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
                 let all_inherent_impls =
@@ -131,20 +127,18 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
                     self.resolver.cstore().incoherent_impls_in_crate_untracked(cnum),
                 );
 
-                // Querying traits in scope is expensive so we try to prune the impl and traits lists
-                // using privacy, private traits and impls from other crates are never documented in
+                // Querying traits in scope is expensive so we try to prune the impl lists using
+                // privacy, private traits and impls from other crates are never documented in
                 // the current crate, and links in their doc comments are not resolved.
-                for &def_id in &all_traits {
-                    if self.resolver.cstore().visibility_untracked(def_id).is_public() {
-                        self.resolve_doc_links_extern_impl(def_id, false);
-                    }
-                }
                 for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
                     if self.resolver.cstore().visibility_untracked(trait_def_id).is_public()
                         && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| {
                             self.resolver.cstore().visibility_untracked(ty_def_id).is_public()
                         })
                     {
+                        if self.visited_mods.insert(trait_def_id) {
+                            self.resolve_doc_links_extern_impl(trait_def_id, false);
+                        }
                         self.resolve_doc_links_extern_impl(impl_def_id, false);
                     }
                 }
@@ -157,7 +151,6 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
                     self.resolve_doc_links_extern_impl(impl_def_id, true);
                 }
 
-                self.all_traits.extend(all_traits);
                 self.all_trait_impls
                     .extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id));
             }
@@ -306,15 +299,20 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
                     let scope_id = match child.res {
-                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id),
+                        Res::Def(
+                            DefKind::Variant
+                            | DefKind::AssocTy
+                            | DefKind::AssocFn
+                            | DefKind::AssocConst,
+                            ..,
+                        ) => self.resolver.parent(def_id),
                         _ => def_id,
                     };
                     self.resolve_doc_links_extern_outer(def_id, scope_id); // Outer attribute scope
                     if let Res::Def(DefKind::Mod, ..) = child.res {
                         self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
                     }
-                    // `DefKind::Trait`s are processed in `process_extern_impls`.
-                    if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
+                    if let Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, ..) = child.res {
                         self.process_module_children_or_reexports(def_id);
                     }
                     if let Res::Def(DefKind::Struct | DefKind::Union | DefKind::Variant, _) =
@@ -356,9 +354,6 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
             self.parent_scope.module = old_module;
         } else {
             match &item.kind {
-                ItemKind::Trait(..) => {
-                    self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
-                }
                 ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
                     self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
                 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index e6cef4a326a..b8522ea5d8f 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
 use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{TyCtxt, Visibility};
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
@@ -230,7 +230,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     } else {
                         // All items need to be handled here in case someone wishes to link
                         // to them with intra-doc links
-                        self.cx.cache.access_levels.set_access_level(did, AccessLevel::Public);
+                        self.cx.cache.access_levels.set_access_level(
+                            did,
+                            || Visibility::Restricted(CRATE_DEF_ID),
+                            AccessLevel::Public,
+                        );
                     }
                 }
             }
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 8221e0998d7..0511494668b 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{TyCtxt, Visibility};
 
 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
 
@@ -41,7 +41,11 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
         let old_level = self.access_levels.get_access_level(did);
         // Accessibility levels can only grow
         if level > old_level && !is_hidden {
-            self.access_levels.set_access_level(did, level.unwrap());
+            self.access_levels.set_access_level(
+                did,
+                || Visibility::Restricted(CRATE_DEF_ID),
+                level.unwrap(),
+            );
             level
         } else {
             old_level
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 9567f08afc94332d59025744f3a8198104949d3
+Subproject 4b85255772114ca4946d95fe591933dae7d6199
diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs
index 04b5f4aed9b..66c39a48c6e 100644
--- a/src/test/assembly/asm/aarch64-types.rs
+++ b/src/test/assembly/asm/aarch64-types.rs
@@ -2,7 +2,7 @@
 // compile-flags: --target aarch64-unknown-linux-gnu
 // needs-llvm-components: aarch64
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs
index 5ac1af6afd6..b22a26ce36f 100644
--- a/src/test/assembly/asm/arm-types.rs
+++ b/src/test/assembly/asm/arm-types.rs
@@ -3,7 +3,7 @@
 // compile-flags: -C target-feature=+neon
 // needs-llvm-components: arm
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/avr-types.rs b/src/test/assembly/asm/avr-types.rs
index 58bf1ad9e35..b2d11a8826f 100644
--- a/src/test/assembly/asm/avr-types.rs
+++ b/src/test/assembly/asm/avr-types.rs
@@ -2,7 +2,7 @@
 // compile-flags: --target avr-unknown-gnu-atmega328
 // needs-llvm-components: avr
 
-#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
diff --git a/src/test/assembly/asm/bpf-types.rs b/src/test/assembly/asm/bpf-types.rs
index f894644cc20..e177b8d0dbe 100644
--- a/src/test/assembly/asm/bpf-types.rs
+++ b/src/test/assembly/asm/bpf-types.rs
@@ -2,7 +2,7 @@
 // compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
 // needs-llvm-components: bpf
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs
index 4cf73b40faf..0b361a7ed96 100644
--- a/src/test/assembly/asm/global_asm.rs
+++ b/src/test/assembly/asm/global_asm.rs
@@ -4,7 +4,7 @@
 // compile-flags: -C llvm-args=--x86-asm-syntax=intel
 // compile-flags: -C symbol-mangling-version=v0
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 #![crate_type = "rlib"]
 
 use std::arch::global_asm;
@@ -28,4 +28,6 @@ global_asm!("lea rax, [rip + {}]", sym MY_STATIC);
 // CHECK: call _RNvCsiubXh4Yz005_10global_asm6foobar
 global_asm!("call {}", sym foobar);
 // CHECK: _RNvCsiubXh4Yz005_10global_asm6foobar:
-fn foobar() { loop {} }
+fn foobar() {
+    loop {}
+}
diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs
index eff9a0bb431..af16faedbc4 100644
--- a/src/test/assembly/asm/hexagon-types.rs
+++ b/src/test/assembly/asm/hexagon-types.rs
@@ -2,7 +2,7 @@
 // compile-flags: --target hexagon-unknown-linux-musl
 // needs-llvm-components: hexagon
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs
index 04bf49a40ef..6aa28b062db 100644
--- a/src/test/assembly/asm/mips-types.rs
+++ b/src/test/assembly/asm/mips-types.rs
@@ -5,7 +5,7 @@
 //[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
 //[mips64] needs-llvm-components: mips
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/msp430-types.rs b/src/test/assembly/asm/msp430-types.rs
index 4fa2e8081f8..2c73b3b098d 100644
--- a/src/test/assembly/asm/msp430-types.rs
+++ b/src/test/assembly/asm/msp430-types.rs
@@ -2,7 +2,7 @@
 // compile-flags: --target msp430-none-elf
 // needs-llvm-components: msp430
 
-#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch, asm_const)]
+#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch, asm_const)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs
index 3ebd5b4b896..c319946b5f5 100644
--- a/src/test/assembly/asm/nvptx-types.rs
+++ b/src/test/assembly/asm/nvptx-types.rs
@@ -3,7 +3,7 @@
 // compile-flags: --crate-type cdylib
 // needs-llvm-components: nvptx
 
-#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
 #![no_core]
 
 #[rustc_builtin_macro]
diff --git a/src/test/assembly/asm/powerpc-types.rs b/src/test/assembly/asm/powerpc-types.rs
index 0ca8908497a..e27b0052068 100644
--- a/src/test/assembly/asm/powerpc-types.rs
+++ b/src/test/assembly/asm/powerpc-types.rs
@@ -5,7 +5,7 @@
 //[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
 //[powerpc64] needs-llvm-components: powerpc
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs
index 68dc186ea0c..f18ba294d0c 100644
--- a/src/test/assembly/asm/riscv-types.rs
+++ b/src/test/assembly/asm/riscv-types.rs
@@ -6,7 +6,7 @@
 //[riscv32] needs-llvm-components: riscv
 // compile-flags: -C target-feature=+d
 
-#![feature(no_core, lang_items, rustc_attrs, asm_sym)]
+#![feature(no_core, lang_items, rustc_attrs)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register)]
diff --git a/src/test/assembly/asm/s390x-types.rs b/src/test/assembly/asm/s390x-types.rs
index 6a12902a046..2fb404dd9b2 100644
--- a/src/test/assembly/asm/s390x-types.rs
+++ b/src/test/assembly/asm/s390x-types.rs
@@ -3,7 +3,7 @@
 //[s390x] compile-flags: --target s390x-unknown-linux-gnu
 //[s390x] needs-llvm-components: systemz
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/assembly/asm/wasm-types.rs b/src/test/assembly/asm/wasm-types.rs
index 3aa128c46ac..3b1ac1b455a 100644
--- a/src/test/assembly/asm/wasm-types.rs
+++ b/src/test/assembly/asm/wasm-types.rs
@@ -3,7 +3,7 @@
 // compile-flags: --crate-type cdylib
 // needs-llvm-components: webassembly
 
-#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
 #![no_core]
 
 #[rustc_builtin_macro]
diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs
index e871535cfde..81be79cbaac 100644
--- a/src/test/assembly/asm/x86-types.rs
+++ b/src/test/assembly/asm/x86-types.rs
@@ -7,7 +7,7 @@
 // compile-flags: -C llvm-args=--x86-asm-syntax=intel
 // compile-flags: -C target-feature=+avx512bw
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/src/test/codegen/deduced-param-attrs.rs b/src/test/codegen/deduced-param-attrs.rs
new file mode 100644
index 00000000000..153046eef3c
--- /dev/null
+++ b/src/test/codegen/deduced-param-attrs.rs
@@ -0,0 +1,60 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+#![allow(incomplete_features)]
+#![feature(unsized_locals, unsized_fn_params)]
+
+use std::cell::Cell;
+use std::hint;
+
+// Check to make sure that we can deduce the `readonly` attribute from function bodies for
+// parameters passed indirectly.
+
+pub struct BigStruct {
+    blah: [i32; 1024],
+}
+
+pub struct BigCellContainer {
+    blah: [Cell<i32>; 1024],
+}
+
+// The by-value parameter for this big struct can be marked readonly.
+//
+// CHECK: @use_big_struct_immutably({{.*}} readonly {{.*}} %big_struct)
+#[no_mangle]
+pub fn use_big_struct_immutably(big_struct: BigStruct) {
+    hint::black_box(&big_struct);
+}
+
+// The by-value parameter for this big struct can't be marked readonly, because we mutate it.
+//
+// CHECK-NOT: @use_big_struct_mutably({{.*}} readonly {{.*}} %big_struct)
+#[no_mangle]
+pub fn use_big_struct_mutably(mut big_struct: BigStruct) {
+    big_struct.blah[987] = 654;
+    hint::black_box(&big_struct);
+}
+
+// The by-value parameter for this big struct can't be marked readonly, because it contains
+// UnsafeCell.
+//
+// CHECK-NOT: @use_big_cell_container({{.*}} readonly {{.*}} %big_cell_container)
+#[no_mangle]
+pub fn use_big_cell_container(big_cell_container: BigCellContainer) {
+    hint::black_box(&big_cell_container);
+}
+
+// Make sure that we don't mistakenly mark a big struct as `readonly` when passed through a generic
+// type parameter if it contains UnsafeCell.
+//
+// CHECK-NOT: @use_something({{.*}} readonly {{.*}} %something)
+#[no_mangle]
+#[inline(never)]
+pub fn use_something<T>(something: T) {
+    hint::black_box(&something);
+}
+
+#[no_mangle]
+pub fn forward_big_cell_container(big_cell_container: BigCellContainer) {
+    use_something(big_cell_container)
+}
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index bc650ebf5ee..44fee952307 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -127,7 +127,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
 pub fn notunpin_borrow(_: &NotUnpin) {
 }
 
-// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef dereferenceable(32) %_1)
+// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
 }
diff --git a/src/test/pretty/issue-85089.pp b/src/test/pretty/issue-85089.pp
new file mode 100644
index 00000000000..f84e9df04a2
--- /dev/null
+++ b/src/test/pretty/issue-85089.pp
@@ -0,0 +1,20 @@
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+// Test to print lifetimes on HIR pretty-printing.
+
+// pretty-compare-only
+// pretty-mode:hir
+// pp-exact:issue-85089.pp
+
+trait A<'x> { }
+trait B<'x> { }
+
+struct Foo<'b> {
+    bar: &'b dyn for<'a> A<'a>,
+}
+
+impl <'a> B<'a> for dyn for<'b> A<'b> { }
+
+impl <'a> A<'a> for Foo<'a> { }
diff --git a/src/test/pretty/issue-85089.rs b/src/test/pretty/issue-85089.rs
new file mode 100644
index 00000000000..eb45d473119
--- /dev/null
+++ b/src/test/pretty/issue-85089.rs
@@ -0,0 +1,16 @@
+// Test to print lifetimes on HIR pretty-printing.
+
+// pretty-compare-only
+// pretty-mode:hir
+// pp-exact:issue-85089.pp
+
+trait A<'x> {}
+trait B<'x> {}
+
+struct Foo<'b> {
+    pub bar: &'b dyn for<'a> A<'a>,
+}
+
+impl<'a> B<'a> for dyn for<'b> A<'b> {}
+
+impl<'a> A<'a> for Foo<'a> {}
diff --git a/src/test/pretty/raw-str-nonexpr.rs b/src/test/pretty/raw-str-nonexpr.rs
index 7af80979b43..12440b5ae6e 100644
--- a/src/test/pretty/raw-str-nonexpr.rs
+++ b/src/test/pretty/raw-str-nonexpr.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // pp-exact
 
 #[cfg(foo = r#"just parse this"#)]
diff --git a/src/test/pretty/tests-are-sorted.pp b/src/test/pretty/tests-are-sorted.pp
new file mode 100644
index 00000000000..15dcd4ed97d
--- /dev/null
+++ b/src/test/pretty/tests-are-sorted.pp
@@ -0,0 +1,69 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+// compile-flags: --crate-type=lib --test
+// pretty-compare-only
+// pretty-mode:expanded
+// pp-exact:tests-are-sorted.pp
+
+extern crate test;
+#[cfg(test)]
+#[rustc_test_marker = "m_test"]
+pub const m_test: test::TestDescAndFn =
+    test::TestDescAndFn {
+        desc: test::TestDesc {
+            name: test::StaticTestName("m_test"),
+            ignore: false,
+            ignore_message: ::core::option::Option::None,
+            compile_fail: false,
+            no_run: false,
+            should_panic: test::ShouldPanic::No,
+            test_type: test::TestType::Unknown,
+        },
+        testfn: test::StaticTestFn(|| test::assert_test_result(m_test())),
+    };
+fn m_test() {}
+
+extern crate test;
+#[cfg(test)]
+#[rustc_test_marker = "z_test"]
+pub const z_test: test::TestDescAndFn =
+    test::TestDescAndFn {
+        desc: test::TestDesc {
+            name: test::StaticTestName("z_test"),
+            ignore: false,
+            ignore_message: ::core::option::Option::None,
+            compile_fail: false,
+            no_run: false,
+            should_panic: test::ShouldPanic::No,
+            test_type: test::TestType::Unknown,
+        },
+        testfn: test::StaticTestFn(|| test::assert_test_result(z_test())),
+    };
+fn z_test() {}
+
+extern crate test;
+#[cfg(test)]
+#[rustc_test_marker = "a_test"]
+pub const a_test: test::TestDescAndFn =
+    test::TestDescAndFn {
+        desc: test::TestDesc {
+            name: test::StaticTestName("a_test"),
+            ignore: false,
+            ignore_message: ::core::option::Option::None,
+            compile_fail: false,
+            no_run: false,
+            should_panic: test::ShouldPanic::No,
+            test_type: test::TestType::Unknown,
+        },
+        testfn: test::StaticTestFn(|| test::assert_test_result(a_test())),
+    };
+fn a_test() {}
+#[rustc_main]
+pub fn main() -> () {
+    extern crate test;
+    test::test_main_static(&[&a_test, &m_test, &z_test])
+}
diff --git a/src/test/pretty/tests-are-sorted.rs b/src/test/pretty/tests-are-sorted.rs
new file mode 100644
index 00000000000..1f737d54719
--- /dev/null
+++ b/src/test/pretty/tests-are-sorted.rs
@@ -0,0 +1,13 @@
+// compile-flags: --crate-type=lib --test
+// pretty-compare-only
+// pretty-mode:expanded
+// pp-exact:tests-are-sorted.pp
+
+#[test]
+fn m_test() {}
+
+#[test]
+fn z_test() {}
+
+#[test]
+fn a_test() {}
diff --git a/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile b/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile
index 3c4dade0f52..ff9cc57098c 100644
--- a/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile
+++ b/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile
@@ -1,5 +1,6 @@
 include ../tools.mk
 
+# needs-asm-support
 # ignore-windows-msvc
 #
 # Because of Windows exception handling, the code is not necessarily any shorter.
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index fd294b018af..7e1b6aeb315 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -5,7 +5,6 @@ extern crate rustc_driver;
 extern crate rustc_session;
 extern crate rustc_span;
 
-use rustc_session::DiagnosticOutput;
 use rustc_session::config::{Input, Options, OutputType, OutputTypes};
 use rustc_interface::interface;
 use rustc_span::source_map::FileName;
@@ -55,7 +54,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         output_file: Some(output),
         output_dir: None,
         file_loader: None,
-        diagnostic_output: DiagnosticOutput::Default,
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
diff --git a/src/test/run-make/coverage-reports/Makefile b/src/test/run-make/coverage-reports/Makefile
index 6fc2a6bada9..407992c9f43 100644
--- a/src/test/run-make/coverage-reports/Makefile
+++ b/src/test/run-make/coverage-reports/Makefile
@@ -1,6 +1,11 @@
 # needs-profiler-support
 # ignore-windows-gnu
 
+# FIXME(pietroalbini): this test currently does not work on cross-compiled
+# targets because remote-test is not capable of sending back the *.profraw
+# files generated by the LLVM instrumentation.
+# ignore-cross-compile
+
 # Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
 # corresponding with LLVM versions 12 and 13, respectively.
 # When upgrading LLVM versions, consider whether to enforce a minimum LLVM
@@ -81,13 +86,13 @@ include clear_expected_if_blessed
 	# Compile the test library with coverage instrumentation
 	$(RUSTC) $(SOURCEDIR)/lib/$@.rs \
 			$$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/lib/$@.rs ) \
-			--crate-type rlib -Cinstrument-coverage
+			--crate-type rlib -Cinstrument-coverage --target $(TARGET)
 
 %: $(SOURCEDIR)/%.rs
 	# Compile the test program with coverage instrumentation
 	$(RUSTC) $(SOURCEDIR)/$@.rs \
 			$$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \
-			-L "$(TMPDIR)" -Cinstrument-coverage
+			-L "$(TMPDIR)" -Cinstrument-coverage --target $(TARGET)
 
 	# Run it in order to generate some profiling data,
 	# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml
index 6673e9c20fe..fb8e288fae8 100644
--- a/src/test/rustdoc-gui/anchors.goml
+++ b/src/test/rustdoc-gui/anchors.goml
@@ -1,154 +1,107 @@
 // This test is to ensure that the anchors (`§`) have the expected color and position.
-goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
 
-// This is needed to ensure that the text color is computed.
-show-text: true
-
-// Set the theme to light.
-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
-// We reload the page so the local storage settings are being used.
-reload:
-
-assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"})
-assert-css: (".fqn a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"})
-assert-css: (".fqn a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"})
-assert-css: (
-    ".rightside .srclink",
-    {"color": "rgb(56, 115, 173)", "text-decoration": "none solid rgb(56, 115, 173)"},
-    ALL,
-)
-compare-elements-css: (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"])
-compare-elements-css: (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"])
-
-move-cursor-to: ".main-heading .srclink"
-assert-css: (
-    ".main-heading .srclink",
-    {"color": "rgb(56, 115, 173)", "text-decoration": "underline solid rgb(56, 115, 173)"},
-)
-move-cursor-to: ".impl-items .rightside .srclink"
-assert-css: (
-    ".impl-items .rightside .srclink",
-    {"color": "rgb(56, 115, 173)", "text-decoration": "none solid rgb(56, 115, 173)"},
-)
-move-cursor-to: ".impl-items .rightside.srclink"
-assert-css: (
-    ".impl-items .rightside.srclink",
-    {"color": "rgb(56, 115, 173)", "text-decoration": "none solid rgb(56, 115, 173)"},
-)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-
-assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
-
-assert-css: (".sidebar a", {"color": "rgb(53, 109, 164)"})
-assert-css: ("h1.fqn a", {"color": "rgb(0, 0, 0)"})
-
-// We move the cursor over the "Implementations" title so the anchor is displayed.
-move-cursor-to: "h2#implementations"
-assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"})
-
-// Same thing with the impl block title.
-move-cursor-to: "#impl-HeavilyDocumentedStruct"
-assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(0, 0, 0)"})
-
-assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
-
-//
-// We do the same checks with the dark theme now.
-//
-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
-goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
-
-assert-css: ("#toggle-all-docs", {"color": "rgb(221, 221, 221)"})
-assert-css: (".fqn a:nth-of-type(1)", {"color": "rgb(221, 221, 221)"})
-assert-css: (".fqn a:nth-of-type(2)", {"color": "rgb(45, 191, 184)"})
-assert-css: (
-    ".rightside .srclink",
-    {"color": "rgb(210, 153, 29)", "text-decoration": "none solid rgb(210, 153, 29)"},
-    ALL,
-)
-compare-elements-css: (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"])
-compare-elements-css: (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"])
-
-move-cursor-to: ".main-heading .srclink"
-assert-css: (
-    ".main-heading .srclink",
-    {"color": "rgb(210, 153, 29)", "text-decoration": "underline solid rgb(210, 153, 29)"},
+define-function: (
+    "check-colors",
+    (theme, main_color, title_color, fqn_color, fqn_type_color, src_link_color, sidebar_link_color),
+    [
+        ("goto", "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"),
+        // This is needed to ensure that the text color is computed.
+        ("show-text", true),
+
+        // Setting the theme.
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        // We reload the page so the local storage settings are being used.
+        ("reload"),
+
+        ("assert-css", ("#toggle-all-docs", {"color": |main_color|})),
+        ("assert-css", (".fqn a:nth-of-type(1)", {"color": |fqn_color|})),
+        ("assert-css", (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})),
+        ("assert-css", (
+             ".rightside .srclink",
+             {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
+             ALL,
+        )),
+        (
+            "compare-elements-css",
+            (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"]),
+        ),
+        (
+            "compare-elements-css",
+            (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"]),
+        ),
+
+        ("move-cursor-to", ".main-heading .srclink"),
+        ("assert-css", (
+             ".main-heading .srclink",
+             {"color": |src_link_color|, "text-decoration": "underline solid " + |src_link_color|},
+        )),
+        ("move-cursor-to", ".impl-items .rightside .srclink"),
+        ("assert-css", (
+             ".impl-items .rightside .srclink",
+             {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
+        )),
+        ("move-cursor-to", ".impl-items .rightside.srclink"),
+        ("assert-css", (
+             ".impl-items .rightside.srclink",
+             {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
+        )),
+
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"),
+        // Since we changed page, we need to set the theme again.
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        // We reload the page so the local storage settings are being used.
+        ("reload"),
+
+        ("assert-css", ("#top-doc-prose-title", {"color": |title_color|})),
+
+        ("assert-css", (".sidebar a", {"color": |sidebar_link_color|})),
+        ("assert-css", ("h1.fqn a", {"color": |title_color|})),
+
+        // We move the cursor over the "Implementations" title so the anchor is displayed.
+        ("move-cursor-to", "h2#implementations"),
+        ("assert-css", ("h2#implementations a.anchor", {"color": |main_color|})),
+
+        // Same thing with the impl block title.
+        ("move-cursor-to", "#impl-HeavilyDocumentedStruct"),
+        ("assert-css", ("#impl-HeavilyDocumentedStruct a.anchor", {"color": |main_color|})),
+
+        ("assert-css", ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})),
+    ],
 )
-move-cursor-to: ".impl-items .rightside .srclink"
-assert-css: (
-    ".impl-items .rightside .srclink",
-    {"color": "rgb(210, 153, 29)", "text-decoration": "none solid rgb(210, 153, 29)"},
-)
-move-cursor-to: ".impl-items .rightside.srclink"
-assert-css: (
-    ".impl-items .rightside.srclink",
-    {"color": "rgb(210, 153, 29)", "text-decoration": "none solid rgb(210, 153, 29)"},
-)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-
-assert-css: ("#top-doc-prose-title", {"color": "rgb(221, 221, 221)"})
-
-assert-css: (".sidebar a", {"color": "rgb(253, 191, 53)"})
-assert-css: ("h1.fqn a", {"color": "rgb(221, 221, 221)"})
-
-// We move the cursor over the "Implementations" title so the anchor is displayed.
-move-cursor-to: "h2#implementations"
-assert-css: ("h2#implementations a.anchor", {"color": "rgb(221, 221, 221)"})
-
-// Same thing with the impl block title.
-move-cursor-to: "#impl-HeavilyDocumentedStruct"
-assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(221, 221, 221)"})
-
-assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
-
-//
-// We do the same checks with the ayu theme now.
-//
-local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"}
-goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
 
-assert-css: ("#toggle-all-docs", {"color": "rgb(197, 197, 197)"})
-assert-css: (".fqn a:nth-of-type(1)", {"color": "rgb(255, 255, 255)"})
-assert-css: (".fqn a:nth-of-type(2)", {"color": "rgb(255, 160, 165)"})
-assert-css: (
-    ".rightside .srclink",
-    {"color": "rgb(57, 175, 215)", "text-decoration": "none solid rgb(57, 175, 215)"},
-    ALL,
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "main_color": "rgb(197, 197, 197)",
+        "title_color": "rgb(255, 255, 255)",
+        "fqn_color": "rgb(255, 255, 255)",
+        "fqn_type_color": "rgb(255, 160, 165)",
+        "src_link_color": "rgb(57, 175, 215)",
+        "sidebar_link_color": "rgb(83, 177, 219)",
+    },
 )
-compare-elements-css: (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"])
-compare-elements-css: (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"])
-
-move-cursor-to: ".main-heading .srclink"
-assert-css: (
-    ".main-heading .srclink",
-    {"color": "rgb(57, 175, 215)", "text-decoration": "underline solid rgb(57, 175, 215)"},
-)
-move-cursor-to: ".impl-items .rightside .srclink"
-assert-css: (
-    ".impl-items .rightside .srclink",
-    {"color": "rgb(57, 175, 215)", "text-decoration": "none solid rgb(57, 175, 215)"},
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "main_color": "rgb(221, 221, 221)",
+        "title_color": "rgb(221, 221, 221)",
+        "fqn_color": "rgb(221, 221, 221)",
+        "fqn_type_color": "rgb(45, 191, 184)",
+        "src_link_color": "rgb(210, 153, 29)",
+        "sidebar_link_color": "rgb(253, 191, 53)",
+    },
 )
-move-cursor-to: ".impl-items .rightside.srclink"
-assert-css: (
-    ".impl-items .rightside.srclink",
-    {"color": "rgb(57, 175, 215)", "text-decoration": "none solid rgb(57, 175, 215)"},
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "main_color": "rgb(0, 0, 0)",
+        "title_color": "rgb(0, 0, 0)",
+        "fqn_color": "rgb(0, 0, 0)",
+        "fqn_type_color": "rgb(173, 55, 138)",
+        "src_link_color": "rgb(56, 115, 173)",
+        "sidebar_link_color": "rgb(53, 109, 164)",
+    },
 )
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-
-assert-css: ("#top-doc-prose-title", {"color": "rgb(255, 255, 255)"})
-
-assert-css: (".sidebar a", {"color": "rgb(83, 177, 219)"})
-assert-css: ("h1.fqn a", {"color": "rgb(255, 255, 255)"})
-
-// We move the cursor over the "Implementations" title so the anchor is displayed.
-move-cursor-to: "h2#implementations"
-assert-css: ("h2#implementations a.anchor", {"color": "rgb(197, 197, 197)"})
-
-// Same thing with the impl block title.
-move-cursor-to: "#impl-HeavilyDocumentedStruct"
-assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(197, 197, 197)"})
-
-assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
diff --git a/src/test/rustdoc-gui/code-color.goml b/src/test/rustdoc-gui/code-color.goml
index 4136677cdd5..118f04ad6dc 100644
--- a/src/test/rustdoc-gui/code-color.goml
+++ b/src/test/rustdoc-gui/code-color.goml
@@ -5,26 +5,20 @@
 goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
 // If the text isn't displayed, the browser doesn't compute color style correctly...
 show-text: true
-// Set the theme to dark.
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
-// We reload the page so the local storage settings are being used.
-reload:
 
-assert-css: (".docblock pre > code", {"color": "rgb(221, 221, 221)"}, ALL)
-assert-css: (".docblock > p > code", {"color": "rgb(221, 221, 221)"}, ALL)
+define-function: (
+    "check-colors",
+    (theme, doc_code_color, doc_inline_code_color),
+    [
+        // Set the theme.
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        // We reload the page so the local storage settings are being used.
+        ("reload"),
+        ("assert-css", (".docblock pre > code", {"color": |doc_code_color|}, ALL)),
+        ("assert-css", (".docblock > p > code", {"color": |doc_inline_code_color|}, ALL)),
+    ],
+)
 
-// Set the theme to ayu.
-local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"}
-// We reload the page so the local storage settings are being used.
-reload:
-
-assert-css: (".docblock pre > code", {"color": "rgb(230, 225, 207)"}, ALL)
-assert-css: (".docblock > p > code", {"color": "rgb(255, 180, 84)"}, ALL)
-
-// Set the theme to light.
-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
-// We reload the page so the local storage settings are being used.
-reload:
-
-assert-css: (".docblock pre > code", {"color": "rgb(0, 0, 0)"}, ALL)
-assert-css: (".docblock > p > code", {"color": "rgb(0, 0, 0)"}, ALL)
+call-function: ("check-colors", ("ayu", "rgb(230, 225, 207)", "rgb(255, 180, 84)"))
+call-function: ("check-colors", ("dark", "rgb(221, 221, 221)", "rgb(221, 221, 221)"))
+call-function: ("check-colors", ("light", "rgb(0, 0, 0)", "rgb(0, 0, 0)"))
diff --git a/src/test/rustdoc-gui/codeblock-tooltip.goml b/src/test/rustdoc-gui/codeblock-tooltip.goml
index f01e0c3c6cc..8e681a2a0c3 100644
--- a/src/test/rustdoc-gui/codeblock-tooltip.goml
+++ b/src/test/rustdoc-gui/codeblock-tooltip.goml
@@ -2,95 +2,79 @@
 goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
 show-text: true
 
-// Dark theme.
-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
-reload:
-
-// compile_fail block
-assert-css: (".docblock .example-wrap.compile_fail .tooltip", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
-
-move-cursor-to: ".docblock .example-wrap.compile_fail"
-
-assert-css: (".docblock .example-wrap.compile_fail .tooltip", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
-
-// should_panic block
-assert-css: (".docblock .example-wrap.should_panic .tooltip", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
-
-move-cursor-to: ".docblock .example-wrap.should_panic"
-
-assert-css: (".docblock .example-wrap.should_panic .tooltip", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
-
-// ignore block
-assert-css: (".docblock .example-wrap.ignore .tooltip", {"color": "rgba(255, 142, 0, 0.6)"})
-assert-css: (".docblock .example-wrap.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
-
-move-cursor-to: ".docblock .example-wrap.ignore"
-
-assert-css: (".docblock .example-wrap.ignore .tooltip", {"color": "rgb(255, 142, 0)"})
-assert-css: (".docblock .example-wrap.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
-
-
-// Light theme.
-local-storage: {"rustdoc-theme": "light"}
-reload:
-
-assert-css: (".docblock .example-wrap.compile_fail .tooltip", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
-
-move-cursor-to: ".docblock .example-wrap.compile_fail"
-
-assert-css: (".docblock .example-wrap.compile_fail .tooltip", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
-
-// should_panic block
-assert-css: (".docblock .example-wrap.should_panic .tooltip", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
-
-move-cursor-to: ".docblock .example-wrap.should_panic"
-
-assert-css: (".docblock .example-wrap.should_panic .tooltip", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
-
-// ignore block
-assert-css: (".docblock .example-wrap.ignore .tooltip", {"color": "rgba(255, 142, 0, 0.6)"})
-assert-css: (".docblock .example-wrap.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
-
-move-cursor-to: ".docblock .example-wrap.ignore"
-
-assert-css: (".docblock .example-wrap.ignore .tooltip", {"color": "rgb(255, 142, 0)"})
-assert-css: (".docblock .example-wrap.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
-
-
-// Ayu theme.
-local-storage: {"rustdoc-theme": "ayu"}
-reload:
-
-assert-css: (".docblock .example-wrap.compile_fail .tooltip", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
-
-move-cursor-to: ".docblock .example-wrap.compile_fail"
-
-assert-css: (".docblock .example-wrap.compile_fail .tooltip", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
-
-// should_panic block
-assert-css: (".docblock .example-wrap.should_panic .tooltip", {"color": "rgba(255, 0, 0, 0.5)"})
-assert-css: (".docblock .example-wrap.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
-
-move-cursor-to: ".docblock .example-wrap.should_panic"
-
-assert-css: (".docblock .example-wrap.should_panic .tooltip", {"color": "rgb(255, 0, 0)"})
-assert-css: (".docblock .example-wrap.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
-
-// ignore block
-assert-css: (".docblock .example-wrap.ignore .tooltip", {"color": "rgba(255, 142, 0, 0.6)"})
-assert-css: (".docblock .example-wrap.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
-
-move-cursor-to: ".docblock .example-wrap.ignore"
-
-assert-css: (".docblock .example-wrap.ignore .tooltip", {"color": "rgb(255, 142, 0)"})
-assert-css: (".docblock .example-wrap.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+define-function: (
+    "check-colors",
+    (theme),
+    [
+        // Setting the theme.
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+
+        // compile_fail block
+        ("assert-css", (
+            ".docblock .example-wrap.compile_fail .tooltip",
+            {"color": "rgba(255, 0, 0, 0.5)"},
+        )),
+        ("assert-css", (
+            ".docblock .example-wrap.compile_fail",
+            {"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
+        )),
+
+        ("move-cursor-to", ".docblock .example-wrap.compile_fail"),
+
+        ("assert-css", (
+            ".docblock .example-wrap.compile_fail .tooltip",
+            {"color": "rgb(255, 0, 0)"},
+        )),
+        ("assert-css", (
+            ".docblock .example-wrap.compile_fail",
+            {"border-left": "2px solid rgb(255, 0, 0)"},
+        )),
+
+        // should_panic block
+        ("assert-css", (
+            ".docblock .example-wrap.should_panic .tooltip",
+            {"color": "rgba(255, 0, 0, 0.5)"},
+        )),
+        ("assert-css", (
+            ".docblock .example-wrap.should_panic",
+            {"border-left": "2px solid rgba(255, 0, 0, 0.5)"},
+        )),
+
+        ("move-cursor-to", ".docblock .example-wrap.should_panic"),
+
+        ("assert-css", (
+            ".docblock .example-wrap.should_panic .tooltip",
+            {"color": "rgb(255, 0, 0)"},
+        )),
+        ("assert-css", (
+            ".docblock .example-wrap.should_panic",
+            {"border-left": "2px solid rgb(255, 0, 0)"},
+        )),
+
+        // ignore block
+        ("assert-css", (
+            ".docblock .example-wrap.ignore .tooltip",
+            {"color": "rgba(255, 142, 0, 0.6)"},
+        )),
+        ("assert-css", (
+            ".docblock .example-wrap.ignore",
+            {"border-left": "2px solid rgba(255, 142, 0, 0.6)"},
+        )),
+
+        ("move-cursor-to", ".docblock .example-wrap.ignore"),
+
+        ("assert-css", (
+            ".docblock .example-wrap.ignore .tooltip",
+            {"color": "rgb(255, 142, 0)"},
+        )),
+        ("assert-css", (
+            ".docblock .example-wrap.ignore",
+            {"border-left": "2px solid rgb(255, 142, 0)"},
+        )),
+    ],
+)
+
+call-function: ("check-colors", ("ayu"))
+call-function: ("check-colors", ("dark"))
+call-function: ("check-colors", ("light"))
diff --git a/src/test/rustdoc-gui/docblock-details.goml b/src/test/rustdoc-gui/docblock-details.goml
index f3cbe5767ae..9ae571efbb5 100644
--- a/src/test/rustdoc-gui/docblock-details.goml
+++ b/src/test/rustdoc-gui/docblock-details.goml
@@ -21,3 +21,14 @@ assert-property: (".top-doc .docblock summary h4", {"offsetHeight": "33"})
 assert-css: (".top-doc .docblock summary h4", {"margin-top": "15px", "margin-bottom": "5px"})
 // So `33 + 15 + 5` == `53`
 assert-property: (".top-doc .docblock summary", {"offsetHeight": "53"})
+
+// We now check the `<summary>` on a method.
+assert-css: (
+    ".method-toggle .docblock summary h4",
+    {"border-bottom-width": "0px"},
+)
+// This allows to ensure that summary is on one line only!
+assert-property: (".method-toggle .docblock summary h4", {"offsetHeight": "30"})
+assert-css: (".method-toggle .docblock summary h4", {"margin-top": "15px", "margin-bottom": "5px"})
+// So `30 + 15 + 5` == `50`
+assert-property: (".method-toggle .docblock summary", {"offsetHeight": "50"})
diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml
index 9b7e3a23112..c80a49c52f0 100644
--- a/src/test/rustdoc-gui/headers-color.goml
+++ b/src/test/rustdoc-gui/headers-color.goml
@@ -1,117 +1,70 @@
 // This test check for headers text and background colors for the different themes.
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 
-// This is needed so that the text color is computed.
-show-text: true
-
-// Ayu theme
-local-storage: {
-    "rustdoc-theme": "ayu",
-    "rustdoc-preferred-dark-theme": "ayu",
-    "rustdoc-use-system-theme": "false",
-}
-reload:
-
-assert-css: (
-    ".impl",
-    {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
-    ALL,
-)
-assert-css: (
-    ".impl .code-header",
-    {"color": "rgb(230, 225, 207)", "background-color": "rgba(0, 0, 0, 0)"},
-    ALL,
+define-function: (
+    "check-colors",
+    (theme, color, code_header_color, focus_background_color, headings_color),
+    [
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"),
+        // This is needed so that the text color is computed.
+        ("show-text", true),
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("assert-css", (
+            ".impl",
+            {"color": |color|, "background-color": "rgba(0, 0, 0, 0)"},
+            ALL,
+        )),
+        ("assert-css", (
+            ".impl .code-header",
+            {"color": |code_header_color|, "background-color": "rgba(0, 0, 0, 0)"},
+            ALL,
+        )),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"),
+        ("assert-css", (
+            "#impl-Foo",
+            {"color": |color|, "background-color": |focus_background_color|},
+        )),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"),
+        ("assert-css", (
+            "#method\.must_use",
+            {"color": |color|, "background-color": |focus_background_color|},
+            ALL,
+        )),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/index.html"),
+        ("assert-css", (".small-section-header a", {"color": |color|}, ALL)),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"),
+        // We select headings (h2, h3, h...).
+        ("assert-css", (".docblock > :not(p) > a", {"color": |headings_color|}, ALL)),
+    ],
 )
 
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"
-assert-css: (
-    "#impl-Foo",
-    {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "color": "rgb(197, 197, 197)",
+        "code_header_color": "rgb(230, 225, 207)",
+        "focus_background_color": "rgba(255, 236, 164, 0.06)",
+        "headings_color": "rgb(57, 175, 215)",
+    },
 )
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"
-assert-css: (
-    "#method\.must_use",
-    {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
-    ALL,
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "color": "rgb(221, 221, 221)",
+        "code_header_color": "rgb(221, 221, 221)",
+        "focus_background_color": "rgb(73, 74, 61)",
+        "headings_color": "rgb(210, 153, 29)",
+    },
 )
-
-goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-css: (".small-section-header a", {"color": "rgb(197, 197, 197)"}, ALL)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-// We select headings (h2, h3, h...).
-assert-css: (".docblock > :not(p) > a", {"color": "rgb(57, 175, 215)"}, ALL)
-
-// Dark theme
-local-storage: {
-    "rustdoc-theme": "dark",
-    "rustdoc-preferred-dark-theme": "dark",
-    "rustdoc-use-system-theme": "false",
-}
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-
-assert-css: (
-    ".impl",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-    ALL,
-)
-assert-css: (
-    ".impl .code-header",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
-    ALL,
-)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"
-assert-css: (
-    "#impl-Foo",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
-)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"
-assert-css: (
-    "#method\.must_use",
-    {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
-    ALL,
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "color": "rgb(0, 0, 0)",
+        "code_header_color": "rgb(0, 0, 0)",
+        "focus_background_color": "rgb(253, 255, 211)",
+        "headings_color": "rgb(56, 115, 173)",
+    },
 )
-
-goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-css: (".small-section-header a", {"color": "rgb(221, 221, 221)"}, ALL)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-// We select headings (h2, h3, h...).
-assert-css: (".docblock > :not(p) > a", {"color": "rgb(210, 153, 29)"}, ALL)
-
-// Light theme
-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
-reload:
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-
-assert-css: (
-    ".impl",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-    ALL,
-)
-assert-css: (
-    ".impl .code-header",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
-    ALL,
-)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#impl-Foo"
-assert-css: ("#impl-Foo", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"})
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html#method.must_use"
-assert-css: (
-    "#method\.must_use",
-    {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"},
-    ALL,
-)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-css: (".small-section-header a", {"color": "rgb(0, 0, 0)"}, ALL)
-
-goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-// We select headings (h2, h3, h...).
-assert-css: (".docblock > :not(p) > a", {"color": "rgb(56, 115, 173)"}, ALL)
diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml
index 9a77d8bbd15..85e17ca9551 100644
--- a/src/test/rustdoc-gui/headings.goml
+++ b/src/test/rustdoc-gui/headings.goml
@@ -150,109 +150,85 @@ assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
 
-// Checking colors now.
+// Needed to check colors
 show-text: true
-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
-assert-css: (
-    ".top-doc .docblock h2",
-    {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"},
-)
-assert-css: (
-    ".top-doc .docblock h3",
-    {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"},
-)
-assert-css: (
-    ".top-doc .docblock h4",
-    {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"},
-)
-assert-css: (
-    ".top-doc .docblock h5",
-    {"color": "rgb(0, 0, 0)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h4",
-    {"color": "rgb(0, 0, 0)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h5",
-    {"color": "rgb(0, 0, 0)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h6",
-    {"color": "rgb(0, 0, 0)", "border-bottom-width": "0px"},
-)
 
-local-storage: {"rustdoc-theme": "dark"}
-reload:
-assert-css: (
-    ".top-doc .docblock h2",
-    {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"},
-)
-assert-css: (
-    ".top-doc .docblock h3",
-    {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"},
-)
-assert-css: (
-    ".top-doc .docblock h4",
-    {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"},
-)
-assert-css: (
-    ".top-doc .docblock h5",
-    {"color": "rgb(221, 221, 221)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h4",
-    {"color": "rgb(221, 221, 221)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h5",
-    {"color": "rgb(221, 221, 221)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h6",
-    {"color": "rgb(221, 221, 221)", "border-bottom-width": "0px"},
+define-function: (
+    "check-colors",
+    (theme, heading_color, small_heading_color, heading_border_color),
+    [
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("assert-css", (
+            ".top-doc .docblock h2",
+            {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
+        )),
+        ("assert-css", (
+            ".top-doc .docblock h3",
+            {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
+        )),
+        ("assert-css", (
+            ".top-doc .docblock h4",
+            {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|},
+        )),
+        ("assert-css", (
+            ".top-doc .docblock h5",
+            {"color": |small_heading_color|, "border-bottom-width": "0px"},
+        )),
+        ("assert-css", (
+            "#implementations-list .docblock h4",
+            {"color": |heading_color|, "border-bottom-width": "0px"},
+        )),
+        ("assert-css", (
+            "#implementations-list .docblock h5",
+            {"color": |small_heading_color|, "border-bottom-width": "0px"},
+        )),
+        ("assert-css", (
+            "#implementations-list .docblock h6",
+            {"color": |small_heading_color|, "border-bottom-width": "0px"},
+        )),
+    ],
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "heading_color": "rgb(255, 255, 255)",
+        "small_heading_color": "rgb(197, 197, 197)",
+        "heading_border_color": "rgb(92, 103, 115)",
+    },
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "heading_color": "rgb(221, 221, 221)",
+        "small_heading_color": "rgb(221, 221, 221)",
+        "heading_border_color": "rgb(210, 210, 210)",
+    },
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "heading_color": "rgb(0, 0, 0)",
+        "small_heading_color": "rgb(0, 0, 0)",
+        "heading_border_color": "rgb(221, 221, 221)",
+    },
+)
+
+define-function: (
+    "check-since-color",
+    (theme),
+    [
+        ("local-storage", {"rustdoc-theme": |theme|}),
+        ("reload"),
+        ("assert-css", (".since", {"color": "rgb(128, 128, 128)"}, ALL)),
+    ],
 )
 
-local-storage: {"rustdoc-theme": "ayu"}
-reload:
-assert-css: (
-    ".top-doc .docblock h2",
-    {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"},
-)
-assert-css: (
-    ".top-doc .docblock h2",
-    {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"},
-)
-assert-css: (
-    ".top-doc .docblock h4",
-    {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"},
-)
-assert-css: (
-    ".top-doc .docblock h5",
-    {"color": "rgb(197, 197, 197)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h4",
-    {"color": "rgb(255, 255, 255)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h5",
-    {"color": "rgb(197, 197, 197)", "border-bottom-width": "0px"},
-)
-assert-css: (
-    "#implementations-list .docblock h6",
-    {"color": "rgb(197, 197, 197)", "border-bottom-width": "0px"},
-)
-
-local-storage: {"rustdoc-theme": "light"}
 goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
-assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
-
-local-storage: {"rustdoc-theme": "dark"}
-reload:
-assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
-
-local-storage: {"rustdoc-theme": "ayu"}
-reload:
-assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
+call-function: ("check-since-color", ("ayu"))
+call-function: ("check-since-color", ("dark"))
+call-function: ("check-since-color", ("light"))
diff --git a/src/test/rustdoc-gui/help-page.goml b/src/test/rustdoc-gui/help-page.goml
new file mode 100644
index 00000000000..521e14748af
--- /dev/null
+++ b/src/test/rustdoc-gui/help-page.goml
@@ -0,0 +1,24 @@
+// This test ensures that opening the help page in its own tab works.
+goto: "file://" + |DOC_PATH| + "/help.html"
+size: (1000, 1000) // Try desktop size first.
+wait-for: "#help"
+assert-css: ("#help", {"display": "block"})
+click: "#help-button > a"
+assert-css: ("#help", {"display": "block"})
+compare-elements-property: (".sub", "#help", ["offsetWidth"])
+compare-elements-position: (".sub", "#help", ("x"))
+size: (500, 1000) // Try mobile next.
+assert-css: ("#help", {"display": "block"})
+compare-elements-property: (".sub", "#help", ["offsetWidth"])
+compare-elements-position: (".sub", "#help", ("x"))
+
+// This test ensures that opening the help popover without switching pages works.
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+size: (1000, 1000) // Only supported on desktop.
+assert-false: "#help"
+click: "#help-button > a"
+assert-css: ("#help", {"display": "block"})
+click: "#help-button > a"
+assert-css: ("#help", {"display": "none"})
+compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
+compare-elements-position-false: (".sub", "#help", ("x"))
diff --git a/src/test/rustdoc-gui/item-decl-colors.goml b/src/test/rustdoc-gui/item-decl-colors.goml
new file mode 100644
index 00000000000..ce688287a74
--- /dev/null
+++ b/src/test/rustdoc-gui/item-decl-colors.goml
@@ -0,0 +1,74 @@
+// This test ensures that the color of the items in the type decl are working as expected.
+define-function: (
+    "check-colors",
+    (
+        theme,
+        attr_color,
+        trait_color,
+        struct_color,
+        enum_color,
+        primitive_color,
+        constant_color,
+        fn_color,
+        assoc_type_color,
+    ),
+    [
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"),
+        ("show-text", true),
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("assert-css", (".item-decl .code-attribute", {"color": |attr_color|}, ALL)),
+        ("assert-css", (".item-decl .trait", {"color": |trait_color|}, ALL)),
+        // We need to add `code` here because otherwise it would select the parent too.
+        ("assert-css", (".item-decl code .struct", {"color": |struct_color|}, ALL)),
+        ("assert-css", (".item-decl .enum", {"color": |enum_color|}, ALL)),
+        ("assert-css", (".item-decl .primitive", {"color": |primitive_color|}, ALL)),
+        ("goto", "file://" + |DOC_PATH| + "/test_docs/trait.TraitWithoutGenerics.html"),
+        ("assert-css", (".item-decl .constant", {"color": |constant_color|}, ALL)),
+        ("assert-css", (".item-decl .fnname", {"color": |fn_color|}, ALL)),
+        ("assert-css", (".item-decl .associatedtype", {"color": |assoc_type_color|}, ALL)),
+    ],
+)
+
+call-function: (
+    "check-colors",
+    {
+        "theme": "ayu",
+        "attr_color": "rgb(153, 153, 153)",
+        "trait_color": "rgb(57, 175, 215)",
+        "struct_color": "rgb(255, 160, 165)",
+        "enum_color": "rgb(255, 160, 165)",
+        "primitive_color": "rgb(255, 160, 165)",
+        "constant_color": "rgb(57, 175, 215)",
+        "fn_color": "rgb(253, 214, 135)",
+        "assoc_type_color": "rgb(57, 175, 215)",
+    },
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "dark",
+        "attr_color": "rgb(153, 153, 153)",
+        "trait_color": "rgb(183, 140, 242)",
+        "struct_color": "rgb(45, 191, 184)",
+        "enum_color": "rgb(45, 191, 184)",
+        "primitive_color": "rgb(45, 191, 184)",
+        "constant_color": "rgb(210, 153, 29)",
+        "fn_color": "rgb(43, 171, 99)",
+        "assoc_type_color": "rgb(210, 153, 29)",
+    },
+)
+call-function: (
+    "check-colors",
+    {
+        "theme": "light",
+        "attr_color": "rgb(153, 153, 153)",
+        "trait_color": "rgb(110, 79, 201)",
+        "struct_color": "rgb(173, 55, 138)",
+        "enum_color": "rgb(173, 55, 138)",
+        "primitive_color": "rgb(173, 55, 138)",
+        "constant_color": "rgb(56, 115, 173)",
+        "fn_color": "rgb(173, 124, 55)",
+        "assoc_type_color": "rgb(56, 115, 173)",
+    },
+)
diff --git a/src/test/rustdoc-gui/jump-to-def-background.goml b/src/test/rustdoc-gui/jump-to-def-background.goml
index 31c7d0ce3c8..b65faf13d0c 100644
--- a/src/test/rustdoc-gui/jump-to-def-background.goml
+++ b/src/test/rustdoc-gui/jump-to-def-background.goml
@@ -1,43 +1,22 @@
 // We check the background color on the jump to definition links in the source code page.
 goto: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html"
 
-// Set the theme to dark.
-local-storage: {
-    "rustdoc-theme": "dark",
-    "rustdoc-preferred-dark-theme": "dark",
-    "rustdoc-use-system-theme": "false",
-}
-// We reload the page so the local storage settings are being used.
-reload:
-
-assert-css: (
-    "body.source .example-wrap pre.rust a",
-    {"background-color": "rgb(51, 51, 51)"},
-    ALL,
-)
-
-// Set the theme to ayu.
-local-storage: {
-    "rustdoc-theme": "ayu",
-    "rustdoc-preferred-dark-theme": "ayu",
-    "rustdoc-use-system-theme": "false",
-}
-// We reload the page so the local storage settings are being used.
-reload:
-
-assert-css: (
-    "body.source .example-wrap pre.rust a",
-    {"background-color": "rgb(51, 51, 51)"},
-    ALL,
+define-function: (
+    "check-background-color",
+    (theme, background_color),
+    [
+        // Set the theme.
+        ("local-storage", { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }),
+        // We reload the page so the local storage settings are being used.
+        ("reload"),
+        ("assert-css", (
+            "body.source .example-wrap pre.rust a",
+            {"background-color": |background_color|},
+            ALL,
+        )),
+    ],
 )
 
-// Set the theme to light.
-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
-// We reload the page so the local storage settings are being used.
-reload:
-
-assert-css: (
-    "body.source .example-wrap pre.rust a",
-    {"background-color": "rgb(238, 238, 238)"},
-    ALL,
-)
+call-function: ("check-background-color", ("ayu", "rgb(51, 51, 51)"))
+call-function: ("check-background-color", ("dark", "rgb(51, 51, 51)"))
+call-function: ("check-background-color", ("light", "rgb(238, 238, 238)"))
diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml
index 22a53dea616..704542a39d2 100644
--- a/src/test/rustdoc-gui/mobile.goml
+++ b/src/test/rustdoc-gui/mobile.goml
@@ -12,7 +12,7 @@ assert-css: (".main-heading", {
   "flex-direction": "column"
 })
 
-assert-property: (".mobile-topbar h2.location", {"offsetHeight": 36})
+assert-property: (".mobile-topbar h2", {"offsetHeight": 36})
 
 // Note: We can't use assert-text here because the 'Since' is set by CSS and
 // is therefore not part of the DOM.
diff --git a/src/test/rustdoc-gui/search-form-elements.goml b/src/test/rustdoc-gui/search-form-elements.goml
index fba9cc8777f..542db348c3b 100644
--- a/src/test/rustdoc-gui/search-form-elements.goml
+++ b/src/test/rustdoc-gui/search-form-elements.goml
@@ -33,7 +33,7 @@ assert-css: (
     {"border-color": "rgb(197, 197, 197)"},
 )
 assert-css: (
-    "#help-button > button",
+    "#help-button > a",
     {
         "color": "rgb(255, 255, 255)",
         "border-color": "rgb(92, 103, 115)",
@@ -47,13 +47,21 @@ assert-css: (
 )
 // Only "border-color" should change.
 assert-css: (
-    "#help-button:hover > button",
+    "#help-button:hover > a",
     {
         "color": "rgb(255, 255, 255)",
         "border-color": "rgb(224, 224, 224)",
         "background-color": "rgb(20, 25, 32)",
     },
 )
+// Link color inside
+click: "#help-button"
+assert-css: (
+    "#help a",
+    {
+        "color": "rgb(57, 175, 215)",
+    },
+)
 
 assert-css: (
     "#settings-menu",
@@ -62,7 +70,6 @@ assert-css: (
 assert-css: (
     "#settings-menu > a",
     {
-        "color": "rgb(255, 255, 255)",
         "border-color": "rgb(92, 103, 115)",
         "background-color": "rgb(20, 25, 32)",
     },
@@ -76,7 +83,6 @@ assert-css: (
 assert-css: (
     "#settings-menu:hover > a",
     {
-        "color": "rgb(255, 255, 255)",
         "border-color": "rgb(224, 224, 224)",
         "background-color": "rgb(20, 25, 32)",
     },
@@ -113,7 +119,7 @@ assert-css: (
     {"border-color": "rgb(221, 221, 221)"},
 )
 assert-css: (
-    "#help-button > button",
+    "#help-button > a",
     {
         "color": "rgb(0, 0, 0)",
         "border-color": "rgb(224, 224, 224)",
@@ -127,13 +133,21 @@ assert-css: (
 )
 // Only "border-color" should change.
 assert-css: (
-    "#help-button:hover > button",
+    "#help-button:hover > a",
     {
         "color": "rgb(0, 0, 0)",
         "border-color": "rgb(255, 185, 0)",
         "background-color": "rgb(240, 240, 240)",
     },
 )
+// Link color inside
+click: "#help-button"
+assert-css: (
+    "#help a",
+    {
+        "color": "rgb(210, 153, 29)",
+    },
+)
 
 assert-css: (
     "#settings-menu",
@@ -142,7 +156,6 @@ assert-css: (
 assert-css: (
     "#settings-menu > a",
     {
-        "color": "rgb(0, 0, 0)",
         "border-color": "rgb(224, 224, 224)",
         "background-color": "rgb(240, 240, 240)",
     },
@@ -193,7 +206,7 @@ assert-css: (
     {"border-color": "rgb(0, 0, 0)"},
 )
 assert-css: (
-    "#help-button > button",
+    "#help-button > a",
     {
         "color": "rgb(0, 0, 0)",
         "border-color": "rgb(224, 224, 224)",
@@ -207,13 +220,21 @@ assert-css: (
 )
 // Only "border-color" should change.
 assert-css: (
-    "#help-button:hover > button",
+    "#help-button:hover > a",
     {
         "color": "rgb(0, 0, 0)",
         "border-color": "rgb(113, 113, 113)",
         "background-color": "rgb(255, 255, 255)",
     },
 )
+// Link color inside
+click: "#help-button"
+assert-css: (
+    "#help a",
+    {
+        "color": "rgb(56, 115, 173)",
+    },
+)
 
 assert-css: (
     "#settings-menu",
@@ -222,7 +243,6 @@ assert-css: (
 assert-css: (
     "#settings-menu > a",
     {
-        "color": "rgb(56, 115, 173)",
         "border-color": "rgb(224, 224, 224)",
         "background-color": "rgb(255, 255, 255)",
     },
@@ -236,7 +256,7 @@ assert-css: (
 assert-css: (
     "#settings-menu:hover > a",
     {
-        "color": "rgb(56, 115, 173)",
+        "color": "rgb(0, 0, 0)",
         "border-color": "rgb(113, 113, 113)",
         "background-color": "rgb(255, 255, 255)",
     },
diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml
index dfbf1d38e0e..f258f4d2a83 100644
--- a/src/test/rustdoc-gui/settings.goml
+++ b/src/test/rustdoc-gui/settings.goml
@@ -1,4 +1,5 @@
-// This test ensures that the settings menu display is working as expected.
+// This test ensures that the settings menu display is working as expected and that
+// the settings page is also rendered as expected.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true // needed when we check for colors below.
 // First, we check that the settings page doesn't exist.
@@ -140,7 +141,13 @@ assert-css: ("#settings-menu .popover", {"display": "none"})
 // Now we go to the settings page to check that the CSS is loaded as expected.
 goto: "file://" + |DOC_PATH| + "/settings.html"
 wait-for: "#settings"
-assert-css: (".setting-line .toggle .slider", {"width": "45px", "margin-right": "20px"})
+assert-css: (
+    ".setting-line .toggle .slider",
+    {"width": "45px", "margin-right": "20px", "border": "0px none rgb(0, 0, 0)"},
+)
+
+assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
+compare-elements-position: (".sub form", "#settings", ("x"))
 
 // We now check the display with JS disabled.
 assert-false: "noscript section"
diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml
index ea6f55272ff..9068680d640 100644
--- a/src/test/rustdoc-gui/shortcuts.goml
+++ b/src/test/rustdoc-gui/shortcuts.goml
@@ -11,3 +11,21 @@ press-key: "?"
 assert-css: ("#help-button .popover", {"display": "block"})
 press-key: "Escape"
 assert-css: ("#help-button .popover", {"display": "none"})
+// Checking doc collapse and expand.
+// It should be displaying a "-":
+assert-text: ("#toggle-all-docs", "[\u2212]")
+press-key: "-"
+wait-for-text: ("#toggle-all-docs", "[+]")
+assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
+// Pressing it again shouldn't do anything.
+press-key: "-"
+assert-text: ("#toggle-all-docs", "[+]")
+assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
+// Expanding now.
+press-key: "+"
+wait-for-text: ("#toggle-all-docs", "[\u2212]")
+assert-attribute: ("#toggle-all-docs", {"class": ""})
+// Pressing it again shouldn't do anything.
+press-key: "+"
+assert-text: ("#toggle-all-docs", "[\u2212]")
+assert-attribute: ("#toggle-all-docs", {"class": ""})
diff --git a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
index f1cba172ee3..2449269b192 100644
--- a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
@@ -1,12 +1,12 @@
 // This test ensures that the mobile sidebar preserves scroll position.
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 // Switching to "mobile view" by reducing the width to 600px.
-size: (600, 600)
+size: (700, 600)
 assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 
 // Scroll down.
 scroll-to: "//h2[@id='blanket-implementations']"
-assert-window-property: {"pageYOffset": "651"}
+assert-window-property: {"pageYOffset": "627"}
 
 // Open the sidebar menu.
 click: ".sidebar-menu-toggle"
@@ -21,11 +21,11 @@ assert-window-property: {"pageYOffset": "0"}
 // Close the sidebar menu. Make sure the scroll position gets restored.
 click: ".sidebar-menu-toggle"
 wait-for-css: (".sidebar", {"left": "-1000px"})
-assert-window-property: {"pageYOffset": "651"}
+assert-window-property: {"pageYOffset": "627"}
 
 // Now test that scrollability returns when the browser window is just resized.
 click: ".sidebar-menu-toggle"
 wait-for-css: (".sidebar", {"left": "0px"})
 assert-window-property: {"pageYOffset": "0"}
 size: (900, 600)
-assert-window-property: {"pageYOffset": "651"}
+assert-window-property: {"pageYOffset": "627"}
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
index 4cded2c773d..453873f1b81 100644
--- a/src/test/rustdoc-gui/sidebar-mobile.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -13,7 +13,7 @@ click: ".sidebar-menu-toggle"
 assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 // Force the sidebar open by focusing a link inside it.
 // This makes it easier for keyboard users to get to it.
-focus: ".sidebar-title a"
+focus: ".sidebar-elems h3 a"
 assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // When we tab out of the sidebar, close it.
 focus: ".search-input"
@@ -23,6 +23,11 @@ assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 click: ".sidebar-menu-toggle"
 assert-css: (".sidebar", {"left": "0px"})
 
+// Make sure the "struct Foo" header is hidden, since the mobile topbar already does it.
+assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='Foo']/parent::h2", {"display": "none"})
+// Make sure the global navigation is still here.
+assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In test_docs']/parent::h2", {"display": "block"})
+
 // Click elsewhere.
 click: "body"
 assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
@@ -39,7 +44,7 @@ assert-position: ("#method\.must_use", {"y": 45})
 // Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
 click: ".sidebar-menu-toggle"
 scroll-to: ".block.keyword li:nth-child(1)"
-compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
+compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543.19})
 
 // Now checking the background color of the sidebar.
 show-text: true
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
index 54193234af9..5058630f469 100644
--- a/src/test/rustdoc-gui/sidebar.goml
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -9,6 +9,7 @@ reload:
 assert-text: (".sidebar > .location", "Crate test_docs")
 // In modules, we only have one "location" element.
 assert-count: (".sidebar .location", 1)
+assert-count: (".sidebar h2", 1)
 assert-text: ("#all-types", "All Items")
 assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"})
 // We check that we have the crates list and that the "current" on is "test_docs".
@@ -19,16 +20,18 @@ assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Modules")
 assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Macros")
 assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Structs")
 assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Enums")
-assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Traits")
-assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Functions")
-assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Type Definitions")
-assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Unions")
-assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Keywords")
+assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Constants")
+assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Traits")
+assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Functions")
+assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Type Definitions")
+assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Unions")
+assert-text: (".sidebar-elems section ul > li:nth-child(11)", "Keywords")
 assert-text: ("#structs + .item-table .item-left > a", "Foo")
 click: "#structs + .item-table .item-left > a"
 
 // PAGE: struct.Foo.html
-assert-count: (".sidebar .location", 2)
+assert-count: (".sidebar .location", 1)
+assert-count: (".sidebar h2", 2)
 // We check that there is no crate listed outside of the top level.
 assert-false: ".sidebar-elems > .crate"
 
@@ -60,10 +63,11 @@ assert-text: ("#functions + .item-table .item-left > a", "foobar")
 click: "#functions + .item-table .item-left > a"
 
 // PAGE: fn.foobar.html
-// In items containing no items (like functions or constants) and in modules, we have one
-// "location" elements.
-assert-count: (".sidebar .location", 1)
-assert-text: (".sidebar .sidebar-elems .location", "In lib2")
+// In items containing no items (like functions or constants) and in modules, we have no
+// "location" elements. Only the parent module h2.
+assert-count: (".sidebar .location", 0)
+assert-count: (".sidebar h2", 1)
+assert-text: (".sidebar .sidebar-elems h2", "In lib2")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index 76260d621ea..29d65fc7ebc 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -23,7 +23,7 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
 show-text: true
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
-assert-position: ("//*[@id='1']", {"x": 104, "y": 103})
+assert-position: ("//*[@id='1']", {"x": 104, "y": 112})
 // We click on the left of the "1" span but still in the "src-line-number" `<pre>`.
 click: (103, 103)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
@@ -47,3 +47,25 @@ assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
 
 // Check the spacing.
 assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
+
+// Check the search form
+assert-css: ("nav.sub", {"flex-direction": "row"})
+// The goal of this test is to ensure the search input is perfectly centered
+// between the top of the page and the top of the gray code block.
+// To check this, we maintain the invariant:
+//
+// offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
+assert-property: ("nav.sub form", {"offsetTop": 28, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 90})
+// 28 = 90 - 34 - 28
+
+// Now do the same check on moderately-sized mobile.
+size: (700, 700)
+assert-css: ("nav.sub", {"flex-direction": "row"})
+assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 76})
+// 21 = 76 - 34 - 21
+
+// Tiny mobile gets a different display where the logo is stacked on top.
+size: (450, 700)
+assert-css: ("nav.sub", {"flex-direction": "column"})
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index cc0efe7231a..fdf97e492aa 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -5,6 +5,7 @@
 #![crate_name = "test_docs"]
 #![feature(rustdoc_internals)]
 #![feature(doc_cfg)]
+#![feature(associated_type_defaults)]
 
 /*!
 Enable the feature <span class="stab portability"><code>some-feature</code></span> to enjoy
@@ -316,6 +317,18 @@ pub mod details {
     /// <div>I'm the content of the details!</div>
     /// </details>
     pub struct Details;
+
+    impl Details {
+        /// We check the appearance of the `<details>`/`<summary>` in here.
+        ///
+        /// ## Hello
+        ///
+        /// <details>
+        /// <summary><h4>I'm a summary</h4></summary>
+        /// <div>I'm the content of the details!</div>
+        /// </details>
+        pub fn method() {}
+    }
 }
 
 pub mod doc_block_table {
@@ -386,3 +399,20 @@ impl TypeWithNoDocblocks {
 pub unsafe fn unsafe_fn() {}
 
 pub fn safe_fn() {}
+
+#[repr(C)]
+pub struct WithGenerics<T: TraitWithNoDocblocks, S = String, E = WhoLetTheDogOut, P = i8> {
+    s: S,
+    t: T,
+    e: E,
+    p: P,
+}
+
+pub const CONST: u8 = 0;
+
+pub trait TraitWithoutGenerics {
+    const C: u8 = CONST;
+    type T = SomeType;
+
+    fn foo();
+}
diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml
index 657c3cfa4b6..fce3002e750 100644
--- a/src/test/rustdoc-gui/type-declation-overflow.goml
+++ b/src/test/rustdoc-gui/type-declation-overflow.goml
@@ -32,6 +32,6 @@ assert-property: (".item-decl pre", {"scrollWidth": "950"})
 size: (600, 600)
 goto: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
 // It shouldn't have an overflow in the topbar either.
-store-property: (scrollWidth, ".mobile-topbar .location", "scrollWidth")
-assert-property: (".mobile-topbar .location", {"clientWidth": |scrollWidth|})
-assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
+store-property: (scrollWidth, ".mobile-topbar h2", "scrollWidth")
+assert-property: (".mobile-topbar h2", {"clientWidth": |scrollWidth|})
+assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index dbf3a8f00ee..46f11d2e5d1 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -36,6 +36,7 @@
     -Z                       dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
     -Z                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
+    -Z                               dylib-lto=val -- enables LTO for dylib crate type
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
     -Z               export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
diff --git a/src/test/rustdoc/associated-consts.rs b/src/test/rustdoc/associated-consts.rs
index 9319a073bb7..adb155bb525 100644
--- a/src/test/rustdoc/associated-consts.rs
+++ b/src/test/rustdoc/associated-consts.rs
@@ -9,7 +9,7 @@ pub trait Trait {
 pub struct Bar;
 
 // @has 'foo/struct.Bar.html'
-// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @!has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @!has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Bar {
     const FOO: u32 = 1;
@@ -22,7 +22,7 @@ pub enum Foo {
 }
 
 // @has 'foo/enum.Foo.html'
-// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @!has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @!has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Foo {
     const FOO: u32 = 1;
@@ -33,7 +33,7 @@ impl Trait for Foo {
 pub struct Baz;
 
 // @has 'foo/struct.Baz.html'
-// @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Baz {
     pub const FOO: u32 = 42;
@@ -44,7 +44,7 @@ pub enum Quux {
 }
 
 // @has 'foo/enum.Quux.html'
-// @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Quux {
     pub const FOO: u32 = 42;
diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs
index 746df9c804e..be2b42b5ac6 100644
--- a/src/test/rustdoc/deref-recursive-pathbuf.rs
+++ b/src/test/rustdoc/deref-recursive-pathbuf.rs
@@ -7,9 +7,9 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
 // @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
 // @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
 // @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists'
 
 #![crate_name = "foo"]
diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs
index d5f8473f284..0436f2f86f5 100644
--- a/src/test/rustdoc/deref-recursive.rs
+++ b/src/test/rustdoc/deref-recursive.rs
@@ -7,9 +7,9 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
 // @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz'
 
 #![crate_name = "foo"]
diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs
index 28f977e315a..32424d13eb8 100644
--- a/src/test/rustdoc/deref-typedef.rs
+++ b/src/test/rustdoc/deref-typedef.rs
@@ -6,7 +6,7 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c'
diff --git a/src/test/rustdoc/escape-deref-methods.rs b/src/test/rustdoc/escape-deref-methods.rs
index a62ad2c4001..66919d73eeb 100644
--- a/src/test/rustdoc/escape-deref-methods.rs
+++ b/src/test/rustdoc/escape-deref-methods.rs
@@ -27,7 +27,7 @@ impl Deref for TitleList {
 }
 
 // @has foo/struct.TitleList.html
-// @has - '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Vec<Title>>'
+// @has - '//div[@class="sidebar-elems"]//h3' 'Methods from Deref<Target=Vec<Title>>'
 impl DerefMut for TitleList {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.members
diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html
new file mode 100644
index 00000000000..8934bc1ee33
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html
@@ -0,0 +1 @@
+<h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a>&lt;Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>&gt;</h4>
\ No newline at end of file
diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html
new file mode 100644
index 00000000000..bf330670ed0
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html
@@ -0,0 +1 @@
+<h4 class="code-header">type <a href="#associatedtype.Out2" class="associatedtype">Out2</a>&lt;T&gt;: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a>&lt;Item = T&gt;</h4>
\ No newline at end of file
diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html
index 69d84e1b2c1..69d84e1b2c1 100644
--- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html
+++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html
diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs
index 00976aa7442..5f4712aab5b 100644
--- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs
+++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs
@@ -1,13 +1,10 @@
 // Regression test for issues #77763, #84579 and #102142.
 #![crate_name = "main"]
 
-// aux-build:assoc_item_trait_bounds_with_bindings.rs
+// aux-build:assoc_item_trait_bounds.rs
 // build-aux-docs
 // ignore-cross-compile
-extern crate assoc_item_trait_bounds_with_bindings as aux;
-
-// FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters
-//                of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed.
+extern crate assoc_item_trait_bounds as aux;
 
 // @has main/trait.Main.html
 // @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support<Item = ()>'
@@ -24,11 +21,15 @@ extern crate assoc_item_trait_bounds_with_bindings as aux;
 // @has - '//*[@id="associatedtype.Out11"]' "type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>"
 // @has - '//*[@id="associatedtype.Out12"]' "type Out12: for<'w> Helper<B<'w> = Cow<'w, str>, A<'w> = bool>"
 // @has - '//*[@id="associatedtype.Out13"]' "type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>"
+// @has - '//*[@id="associatedtype.Out14"]' "type Out14<P: Copy + Eq, Q: ?Sized>"
 //
-// Snapshots: Check that we do not render any where-clauses for those associated types since all of
-// the trait bounds contained within were moved to the bounds of the respective item.
+// Snapshots:
+// Check that we don't render any where-clauses for the following associated types since
+// all corresponding projection equality predicates should have already been re-sugared
+// to associated type bindings:
 //
 // @snapshot out0 - '//*[@id="associatedtype.Out0"]/*[@class="code-header"]'
+// @snapshot out2 - '//*[@id="associatedtype.Out2"]/*[@class="code-header"]'
 // @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]'
 //
 // @has - '//*[@id="tymethod.make"]' \
diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html
deleted file mode 100644
index 927a1a42a1f..00000000000
--- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html
+++ /dev/null
@@ -1 +0,0 @@
-<h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds_with_bindings/trait.Support.html" title="trait assoc_item_trait_bounds_with_bindings::Support">Support</a>&lt;Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>&gt;</h4>
\ No newline at end of file
diff --git a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
index f451b1a0e99..d326e61daea 100644
--- a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs
+++ b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
@@ -15,6 +15,7 @@ pub trait Main {
     type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>;
     type Out12: for<'w> Helper<B<'w> = std::borrow::Cow<'w, str>, A<'w> = bool>;
     type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>;
+    type Out14<P: Copy + Eq, Q: ?Sized>;
 
     fn make<F>(_: F, _: impl FnMut(&str) -> bool)
     where
diff --git a/src/test/rustdoc/inline_cross/auxiliary/issue-24183.rs b/src/test/rustdoc/inline_cross/auxiliary/issue-24183.rs
new file mode 100644
index 00000000000..e7a13acc6f8
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/auxiliary/issue-24183.rs
@@ -0,0 +1,14 @@
+#![crate_type = "lib"]
+
+pub trait U/*: ?Sized */ {
+    fn modified(self) -> Self
+    where
+        Self: Sized
+    {
+        self
+    }
+
+    fn touch(&self)/* where Self: ?Sized */{}
+}
+
+pub trait S: Sized {}
diff --git a/src/test/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html b/src/test/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html
new file mode 100644
index 00000000000..6955a961499
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html
@@ -0,0 +1 @@
+<h4 class="code-header">fn <a href="#method.touch" class="fnname">touch</a>(&amp;self)</h4>
\ No newline at end of file
diff --git a/src/test/rustdoc/inline_cross/issue-24183.rs b/src/test/rustdoc/inline_cross/issue-24183.rs
new file mode 100644
index 00000000000..d11b6955f3c
--- /dev/null
+++ b/src/test/rustdoc/inline_cross/issue-24183.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+#![crate_name = "usr"]
+
+// aux-crate:issue_24183=issue-24183.rs
+// edition: 2021
+
+// @has usr/trait.U.html
+// @has - '//*[@class="item-decl"]' "pub trait U {"
+// @has - '//*[@id="method.modified"]' \
+// "fn modified(self) -> Self\
+// where \
+//     Self: Sized"
+// @snapshot method_no_where_self_sized - '//*[@id="method.touch"]/*[@class="code-header"]'
+pub use issue_24183::U;
+
+// @has usr/trait.S.html
+// @has - '//*[@class="item-decl"]' 'pub trait S: Sized {'
+pub use issue_24183::S;
diff --git a/src/test/rustdoc/intra-doc/no-doc-primitive.rs b/src/test/rustdoc/intra-doc/no-doc-primitive.rs
new file mode 100644
index 00000000000..e5eba1d8d48
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/no-doc-primitive.rs
@@ -0,0 +1,15 @@
+// Crate tree without a `doc(primitive)` module for primitive type linked to by a doc link.
+
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+#![rustc_coherence_is_core]
+#![crate_type = "rlib"]
+
+// @has no_doc_primitive/index.html
+//! A [`char`] and its [`char::len_utf8`].
+impl char {
+    pub fn len_utf8(self) -> usize {
+        42
+    }
+}
diff --git a/src/test/rustdoc/issue-100241.rs b/src/test/rustdoc/issue-100241.rs
new file mode 100644
index 00000000000..9e9cba13a22
--- /dev/null
+++ b/src/test/rustdoc/issue-100241.rs
@@ -0,0 +1,12 @@
+//! See [`S`].
+
+// Check that this isn't an ICE
+// should-fail
+
+mod foo {
+    pub use inner::S;
+    //~^ ERROR unresolved imports `inner`, `foo::S`
+}
+
+use foo::*;
+use foo::S;
diff --git a/src/test/rustdoc/logo-class-default.rs b/src/test/rustdoc/logo-class-default.rs
index a7016d227b1..d2d4391997f 100644
--- a/src/test/rustdoc/logo-class-default.rs
+++ b/src/test/rustdoc/logo-class-default.rs
@@ -1,4 +1,4 @@
 // Note: this test is paired with logo-class.rs.
 // @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
-// @has logo_class_default/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+// @has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
 pub struct SomeStruct;
diff --git a/src/test/rustdoc/logo-class.rs b/src/test/rustdoc/logo-class.rs
index f071f356a6d..d3aa446dab9 100644
--- a/src/test/rustdoc/logo-class.rs
+++ b/src/test/rustdoc/logo-class.rs
@@ -5,6 +5,6 @@
 // @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
 // @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
 //
-// @has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
-// @!has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+// @has src/logo_class/logo-class.rs.html '//*[@class="sub-logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
+// @!has src/logo_class/logo-class.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
 pub struct SomeStruct;
diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs
index b995fff1f9a..4af6d008492 100644
--- a/src/test/rustdoc/negative-impl-sidebar.rs
+++ b/src/test/rustdoc/negative-impl-sidebar.rs
@@ -4,6 +4,6 @@
 pub struct Foo;
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#trait-implementations"]' 'Trait Implementations'
 // @has - '//*[@class="sidebar-elems"]//section//a' '!Sync'
 impl !Sync for Foo {}
diff --git a/src/test/rustdoc/not-wf-ambiguous-normalization.rs b/src/test/rustdoc/not-wf-ambiguous-normalization.rs
new file mode 100644
index 00000000000..1e9f925f845
--- /dev/null
+++ b/src/test/rustdoc/not-wf-ambiguous-normalization.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Znormalize-docs
+
+#![feature(type_alias_impl_trait)]
+
+trait Allocator {
+    type Buffer;
+}
+
+struct DefaultAllocator;
+
+// This unconstrained impl parameter causes the normalization of
+// `<DefaultAllocator as Allocator>::Buffer` to be ambiguous,
+// which caused an ICE with `-Znormalize-docs`.
+impl<T> Allocator for DefaultAllocator {
+    type Buffer = ();
+}
+
+type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
+
+fn foo() -> A {
+    |_| ()
+}
+
+fn main() {}
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
index b5b681ab085..6f7afa59bdd 100644
--- a/src/test/rustdoc/sidebar-items.rs
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -2,17 +2,17 @@
 #![crate_name = "foo"]
 
 // @has foo/trait.Foo.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-methods"]' 'Required Methods'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
-// @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-methods"]' 'Provided Methods'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
-// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-consts"]' 'Required Associated Constants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'FOO'
-// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
-// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-types"]' 'Required Associated Types'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
-// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-types"]' 'Provided Associated Types'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Extra'
 pub trait Foo {
     const FOO: usize;
@@ -25,7 +25,7 @@ pub trait Foo {
 }
 
 // @has foo/struct.Bar.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u'
 // @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
@@ -36,7 +36,7 @@ pub struct Bar {
 }
 
 // @has foo/enum.En.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#variants"]' 'Variants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Bar'
 pub enum En {
@@ -45,7 +45,7 @@ pub enum En {
 }
 
 // @has foo/union.MyUnion.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2'
 // @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
index 6712af527a3..11e94694802 100644
--- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -3,7 +3,7 @@
 #![crate_name = "foo"]
 
 // @has foo/trait.Foo.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
 // @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32'
diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs
index 66bb409325c..8ab1143d1f7 100644
--- a/src/test/rustdoc/tuple-struct-fields-doc.rs
+++ b/src/test/rustdoc/tuple-struct-fields-doc.rs
@@ -2,7 +2,7 @@
 
 // @has foo/struct.Foo.html
 // @has - '//h2[@id="fields"]' 'Tuple Fields'
-// @has - '//h3[@class="sidebar-title"]/a[@href="#fields"]' 'Tuple Fields'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Tuple Fields'
 // @has - '//*[@id="structfield.0"]' '0: u32'
 // @has - '//*[@id="main-content"]/div[@class="docblock"]' 'hello'
 // @!has - '//*[@id="structfield.1"]' ''
diff --git a/src/test/ui-fulldeps/fluent-messages/test.rs b/src/test/ui-fulldeps/fluent-messages/test.rs
index 256857e52a7..4e8147e2b76 100644
--- a/src/test/ui-fulldeps/fluent-messages/test.rs
+++ b/src/test/ui-fulldeps/fluent-messages/test.rs
@@ -49,6 +49,7 @@ mod duplicate {
     use super::fluent_messages;
 
     fluent_messages! {
+//~^ ERROR the name `a_b_key` is defined multiple times
         a => "./duplicate-a.ftl",
         a_b => "./duplicate-a-b.ftl",
 //~^ ERROR overrides existing message: `a_b_key`
@@ -80,7 +81,7 @@ mod valid {
         valid => "./valid.ftl",
     }
 
-    use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, valid::key};
+    use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, valid_key};
 }
 
 mod missing_crate_name {
@@ -93,5 +94,5 @@ mod missing_crate_name {
 //~| ERROR name `with-hyphens` does not start with the crate name
     }
 
-    use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, test_crate::{foo, with_hyphens}};
+    use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, test_crate_foo, with_hyphens};
 }
diff --git a/src/test/ui-fulldeps/fluent-messages/test.stderr b/src/test/ui-fulldeps/fluent-messages/test.stderr
index 26d87430a8f..d1cd4fe26da 100644
--- a/src/test/ui-fulldeps/fluent-messages/test.stderr
+++ b/src/test/ui-fulldeps/fluent-messages/test.stderr
@@ -30,19 +30,31 @@ error: expected a message field for "missing_message"
   |
 
 error: overrides existing message: `a_b_key`
-  --> $DIR/test.rs:53:16
+  --> $DIR/test.rs:54:16
    |
 LL |         a_b => "./duplicate-a-b.ftl",
    |                ^^^^^^^^^^^^^^^^^^^^^
    |
 help: previously defined in this resource
-  --> $DIR/test.rs:52:14
+  --> $DIR/test.rs:53:14
    |
 LL |         a => "./duplicate-a.ftl",
    |              ^^^^^^^^^^^^^^^^^^^
 
+error[E0428]: the name `a_b_key` is defined multiple times
+  --> $DIR/test.rs:51:5
+   |
+LL |     fluent_messages! {
+   |     ^^^^^^^^^^^^^^^^
+   |     |
+   |     `a_b_key` redefined here
+   |     previous definition of the value `a_b_key` here
+   |
+   = note: os-specific message
+   = note: os-specific message
+
 error: name `slug_with_hyphens_this-slug-has-hyphens` contains a '-' character
-  --> $DIR/test.rs:62:30
+  --> $DIR/test.rs:63:30
    |
 LL |         slug_with_hyphens => "./slug-with-hyphens.ftl",
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +62,7 @@ LL |         slug_with_hyphens => "./slug-with-hyphens.ftl",
    = help: replace any '-'s with '_'s
 
 error: attribute `label-has-hyphens` contains a '-' character
-  --> $DIR/test.rs:71:31
+  --> $DIR/test.rs:72:31
    |
 LL |         label_with_hyphens => "./label-with-hyphens.ftl",
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -58,7 +70,7 @@ LL |         label_with_hyphens => "./label-with-hyphens.ftl",
    = help: replace any '-'s with '_'s
 
 error: name `with-hyphens` contains a '-' character
-  --> $DIR/test.rs:90:23
+  --> $DIR/test.rs:91:23
    |
 LL |         test_crate => "./missing-crate-name.ftl",
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -66,7 +78,7 @@ LL |         test_crate => "./missing-crate-name.ftl",
    = help: replace any '-'s with '_'s
 
 error: name `with-hyphens` does not start with the crate name
-  --> $DIR/test.rs:90:23
+  --> $DIR/test.rs:91:23
    |
 LL |         test_crate => "./missing-crate-name.ftl",
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -74,12 +86,13 @@ LL |         test_crate => "./missing-crate-name.ftl",
    = help: prepend `test_crate_` to the slug name: `test_crate_with_hyphens`
 
 error: name `test-crate_foo` contains a '-' character
-  --> $DIR/test.rs:90:23
+  --> $DIR/test.rs:91:23
    |
 LL |         test_crate => "./missing-crate-name.ftl",
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: replace any '-'s with '_'s
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
+For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
index 462f5e78498..643e81d99c6 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
@@ -19,14 +19,14 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct DeriveDiagnostic {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[note(compiletest::example)]
+#[note(compiletest_example)]
 struct Note {
     #[primary_span]
     span: Span,
@@ -45,7 +45,7 @@ pub struct TranslatableInIntoDiagnostic;
 
 impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        handler.struct_err(fluent::compiletest::example)
+        handler.struct_err(fluent::compiletest_example)
     }
 }
 
@@ -68,12 +68,12 @@ impl AddToDiagnostic for TranslatableInAddToDiagnostic {
     where
         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
     {
-        diag.note(fluent::compiletest::note);
+        diag.note(fluent::note);
     }
 }
 
 pub fn make_diagnostics<'a>(handler: &'a Handler) {
-    let _diag = handler.struct_err(fluent::compiletest::example);
+    let _diag = handler.struct_err(fluent::compiletest_example);
     //~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
 
     let _diag = handler.struct_err("untranslatable diagnostic");
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
index ac820a79db2..510d6a17108 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -19,7 +19,7 @@ LL |         diag.note("untranslatable diagnostic");
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
   --> $DIR/diagnostics.rs:76:25
    |
-LL |     let _diag = handler.struct_err(fluent::compiletest::example);
+LL |     let _diag = handler.struct_err(fluent::compiletest_example);
    |                         ^^^^^^^^^^
    |
 note: the lint level is defined here
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index e873c36e0b3..46164d573b0 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -28,15 +28,15 @@ use rustc_errors::{Applicability, MultiSpan};
 extern crate rustc_session;
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct Hello {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct HelloWarn {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 //~^ ERROR unsupported type attribute for diagnostic derive enum
 enum DiagnosticOnEnum {
     Foo,
@@ -46,13 +46,13 @@ enum DiagnosticOnEnum {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 #[diag = "E0123"]
 //~^ ERROR `#[diag = ...]` is not a valid attribute
 struct WrongStructAttrStyle {}
 
 #[derive(Diagnostic)]
-#[nonsense(compiletest::example, code = "E0123")]
+#[nonsense(compiletest_example, code = "E0123")]
 //~^ ERROR `#[nonsense(...)]` is not a valid attribute
 //~^^ ERROR diagnostic slug not specified
 //~^^^ ERROR cannot find attribute `nonsense` in this scope
@@ -90,12 +90,12 @@ struct InvalidNestedStructAttr2 {}
 struct InvalidNestedStructAttr3 {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123", slug = "foo")]
+#[diag(compiletest_example, code = "E0123", slug = "foo")]
 //~^ ERROR `#[diag(slug = ...)]` is not a valid attribute
 struct InvalidNestedStructAttr4 {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct WrongPlaceField {
     #[suggestion = "bar"]
     //~^ ERROR `#[suggestion = ...]` is not a valid attribute
@@ -103,20 +103,20 @@ struct WrongPlaceField {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
-#[diag(compiletest::example, code = "E0456")]
+#[diag(compiletest_example, code = "E0123")]
+#[diag(compiletest_example, code = "E0456")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
 struct DiagSpecifiedTwice {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0456", code = "E0457")]
+#[diag(compiletest_example, code = "E0456", code = "E0457")]
 //~^ ERROR specified multiple times
 struct CodeSpecifiedTwice {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, compiletest::example, code = "E0456")]
-//~^ ERROR `#[diag(compiletest::example)]` is not a valid attribute
+#[diag(compiletest_example, compiletest_example, code = "E0456")]
+//~^ ERROR `#[diag(compiletest_example)]` is not a valid attribute
 struct SlugSpecifiedTwice {}
 
 #[derive(Diagnostic)]
@@ -128,11 +128,11 @@ struct KindNotProvided {} //~ ERROR diagnostic slug not specified
 struct SlugNotProvided {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct CodeNotProvided {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct MessageWrongType {
     #[primary_span]
     //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
@@ -140,7 +140,7 @@ struct MessageWrongType {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct InvalidPathFieldAttr {
     #[nonsense]
     //~^ ERROR `#[nonsense]` is not a valid attribute
@@ -149,34 +149,34 @@ struct InvalidPathFieldAttr {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithField {
     name: String,
-    #[label(compiletest::label)]
+    #[label(label)]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithMessageAppliedToField {
-    #[label(compiletest::label)]
+    #[label(label)]
     //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
     name: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithNonexistentField {
-    #[suggestion(compiletest::suggestion, code = "{name}")]
+    #[suggestion(suggestion, code = "{name}")]
     //~^ ERROR `name` doesn't refer to a field on this type
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
 //~^ ERROR invalid format string: expected `'}'`
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorMissingClosingBrace {
-    #[suggestion(compiletest::suggestion, code = "{name")]
+    #[suggestion(suggestion, code = "{name")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
@@ -184,49 +184,49 @@ struct ErrorMissingClosingBrace {
 
 #[derive(Diagnostic)]
 //~^ ERROR invalid format string: unmatched `}`
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorMissingOpeningBrace {
-    #[suggestion(compiletest::suggestion, code = "name}")]
+    #[suggestion(suggestion, code = "name}")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct LabelOnSpan {
-    #[label(compiletest::label)]
+    #[label(label)]
     sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct LabelOnNonSpan {
-    #[label(compiletest::label)]
+    #[label(label)]
     //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
     id: u32,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct Suggest {
-    #[suggestion(compiletest::suggestion, code = "This is the suggested code")]
-    #[suggestion_short(compiletest::suggestion, code = "This is the suggested code")]
-    #[suggestion_hidden(compiletest::suggestion, code = "This is the suggested code")]
-    #[suggestion_verbose(compiletest::suggestion, code = "This is the suggested code")]
+    #[suggestion(suggestion, code = "This is the suggested code")]
+    #[suggestion_short(suggestion, code = "This is the suggested code")]
+    #[suggestion_hidden(suggestion, code = "This is the suggested code")]
+    #[suggestion_verbose(suggestion, code = "This is the suggested code")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithoutCode {
-    #[suggestion(compiletest::suggestion)]
+    #[suggestion(suggestion)]
     //~^ ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithBadKey {
     #[suggestion(nonsense = "bar")]
     //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
@@ -235,7 +235,7 @@ struct SuggestWithBadKey {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithShorthandMsg {
     #[suggestion(msg = "bar")]
     //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
@@ -244,52 +244,52 @@ struct SuggestWithShorthandMsg {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithoutMsg {
     #[suggestion(code = "bar")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithTypesSwapped {
-    #[suggestion(compiletest::suggestion, code = "This is suggested code")]
+    #[suggestion(suggestion, code = "This is suggested code")]
     suggestion: (Applicability, Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithWrongTypeApplicabilityOnly {
-    #[suggestion(compiletest::suggestion, code = "This is suggested code")]
+    #[suggestion(suggestion, code = "This is suggested code")]
     //~^ ERROR wrong field type for suggestion
     suggestion: Applicability,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithSpanOnly {
-    #[suggestion(compiletest::suggestion, code = "This is suggested code")]
+    #[suggestion(suggestion, code = "This is suggested code")]
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithDuplicateSpanAndApplicability {
-    #[suggestion(compiletest::suggestion, code = "This is suggested code")]
+    #[suggestion(suggestion, code = "This is suggested code")]
     suggestion: (Span, Span, Applicability),
     //~^ ERROR specified multiple times
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct SuggestWithDuplicateApplicabilityAndSpan {
-    #[suggestion(compiletest::suggestion, code = "This is suggested code")]
+    #[suggestion(suggestion, code = "This is suggested code")]
     suggestion: (Applicability, Applicability, Span),
     //~^ ERROR specified multiple times
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct WrongKindOfAnnotation {
     #[label = "bar"]
     //~^ ERROR `#[label = ...]` is not a valid attribute
@@ -297,38 +297,38 @@ struct WrongKindOfAnnotation {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct OptionsInErrors {
-    #[label(compiletest::label)]
+    #[label(label)]
     label: Option<Span>,
-    #[suggestion(compiletest::suggestion, code = "...")]
+    #[suggestion(suggestion, code = "...")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0456")]
+#[diag(compiletest_example, code = "E0456")]
 struct MoveOutOfBorrowError<'tcx> {
     name: Ident,
     ty: Ty<'tcx>,
     #[primary_span]
-    #[label(compiletest::label)]
+    #[label(label)]
     span: Span,
-    #[label(compiletest::label)]
+    #[label(label)]
     other_span: Span,
-    #[suggestion(compiletest::suggestion, code = "{name}.clone()")]
+    #[suggestion(suggestion, code = "{name}.clone()")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithLifetime<'a> {
-    #[label(compiletest::label)]
+    #[label(label)]
     span: Span,
     name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithDefaultLabelAttr<'a> {
     #[label]
     span: Span,
@@ -337,7 +337,7 @@ struct ErrorWithDefaultLabelAttr<'a> {
 
 #[derive(Diagnostic)]
 //~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ArgFieldWithoutSkip {
     #[primary_span]
     span: Span,
@@ -345,7 +345,7 @@ struct ArgFieldWithoutSkip {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ArgFieldWithSkip {
     #[primary_span]
     span: Span,
@@ -356,132 +356,132 @@ struct ArgFieldWithSkip {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithSpannedNote {
     #[note]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithSpannedNoteCustom {
-    #[note(compiletest::note)]
+    #[note(note)]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 #[note]
 struct ErrorWithNote {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
-#[note(compiletest::note)]
+#[diag(compiletest_example, code = "E0123")]
+#[note(note)]
 struct ErrorWithNoteCustom {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithSpannedHelp {
     #[help]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithSpannedHelpCustom {
-    #[help(compiletest::help)]
+    #[help(help)]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 #[help]
 struct ErrorWithHelp {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
-#[help(compiletest::help)]
+#[diag(compiletest_example, code = "E0123")]
+#[help(help)]
 struct ErrorWithHelpCustom {
     val: String,
 }
 
 #[derive(Diagnostic)]
 #[help]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithHelpWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[help(compiletest::help)]
-#[diag(compiletest::example, code = "E0123")]
+#[help(help)]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithHelpCustomWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
 #[note]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithNoteWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[note(compiletest::note)]
-#[diag(compiletest::example, code = "E0123")]
+#[note(note)]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithNoteCustomWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ApplicabilityInBoth {
-    #[suggestion(compiletest::suggestion, code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
     //~^ ERROR specified multiple times
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct InvalidApplicability {
-    #[suggestion(compiletest::suggestion, code = "...", applicability = "batman")]
+    #[suggestion(suggestion, code = "...", applicability = "batman")]
     //~^ ERROR invalid applicability
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ValidApplicability {
-    #[suggestion(compiletest::suggestion, code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct NoApplicability {
-    #[suggestion(compiletest::suggestion, code = "...")]
+    #[suggestion(suggestion, code = "...")]
     suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[note(parser::add_paren)]
+#[note(parser_add_paren)]
 struct Note;
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct Subdiagnostic {
     #[subdiagnostic]
     note: Note,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct VecField {
     #[primary_span]
     #[label]
@@ -489,58 +489,58 @@ struct VecField {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct UnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: (),
-    #[help(compiletest::help)]
+    #[help(help)]
     bar: (),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct OptUnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: Option<()>,
-    #[help(compiletest::help)]
+    #[help(help)]
     bar: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct LabelWithTrailingPath {
-    #[label(compiletest::label, foo)]
+    #[label(label, foo)]
     //~^ ERROR `#[label(foo)]` is not a valid attribute
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct LabelWithTrailingNameValue {
-    #[label(compiletest::label, foo = "...")]
+    #[label(label, foo = "...")]
     //~^ ERROR `#[label(foo = ...)]` is not a valid attribute
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct LabelWithTrailingList {
-    #[label(compiletest::label, foo("..."))]
+    #[label(label, foo("..."))]
     //~^ ERROR `#[label(foo(...))]` is not a valid attribute
     span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct LintsGood {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct PrimarySpanOnLint {
     #[primary_span]
     //~^ ERROR `#[primary_span]` is not a valid attribute
@@ -548,42 +548,42 @@ struct PrimarySpanOnLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct ErrorWithMultiSpan {
     #[primary_span]
     span: MultiSpan,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 #[warning]
 struct ErrorWithWarn {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[error(compiletest::example, code = "E0123")]
+#[error(compiletest_example, code = "E0123")]
 //~^ ERROR `#[error(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `error` in this scope
 struct ErrorAttribute {}
 
 #[derive(Diagnostic)]
-#[warn_(compiletest::example, code = "E0123")]
+#[warn_(compiletest_example, code = "E0123")]
 //~^ ERROR `#[warn_(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `warn_` in this scope
 struct WarnAttribute {}
 
 #[derive(Diagnostic)]
-#[lint(compiletest::example, code = "E0123")]
+#[lint(compiletest_example, code = "E0123")]
 //~^ ERROR `#[lint(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `lint` in this scope
 struct LintAttributeOnSessionDiag {}
 
 #[derive(LintDiagnostic)]
-#[lint(compiletest::example, code = "E0123")]
+#[lint(compiletest_example, code = "E0123")]
 //~^ ERROR `#[lint(...)]` is not a valid attribute
 //~| ERROR `#[lint(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
@@ -591,55 +591,55 @@ struct LintAttributeOnSessionDiag {}
 struct LintAttributeOnLintDiag {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct DuplicatedSuggestionCode {
-    #[suggestion(compiletest::suggestion, code = "...", code = ",,,")]
+    #[suggestion(suggestion, code = "...", code = ",,,")]
     //~^ ERROR specified multiple times
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct InvalidTypeInSuggestionTuple {
-    #[suggestion(compiletest::suggestion, code = "...")]
+    #[suggestion(suggestion, code = "...")]
     suggestion: (Span, usize),
     //~^ ERROR wrong types for suggestion
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct MissingApplicabilityInSuggestionTuple {
-    #[suggestion(compiletest::suggestion, code = "...")]
+    #[suggestion(suggestion, code = "...")]
     suggestion: (Span,),
     //~^ ERROR wrong types for suggestion
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct MissingCodeInSuggestion {
-    #[suggestion(compiletest::suggestion)]
+    #[suggestion(suggestion)]
     //~^ ERROR suggestion without `code = "..."`
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
-#[multipart_suggestion(compiletest::suggestion)]
+#[diag(compiletest_example, code = "E0123")]
+#[multipart_suggestion(suggestion)]
 //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
 //~| ERROR cannot find attribute `multipart_suggestion` in this scope
 #[multipart_suggestion()]
 //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
 //~| ERROR cannot find attribute `multipart_suggestion` in this scope
 struct MultipartSuggestion {
-    #[multipart_suggestion(compiletest::suggestion)]
+    #[multipart_suggestion(suggestion)]
     //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
     //~| ERROR cannot find attribute `multipart_suggestion` in this scope
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
-#[suggestion(compiletest::suggestion, code = "...")]
+#[diag(compiletest_example, code = "E0123")]
+#[suggestion(suggestion, code = "...")]
 //~^ ERROR `#[suggestion(...)]` is not a valid attribute
 struct SuggestionOnStruct {
     #[primary_span]
@@ -647,7 +647,7 @@ struct SuggestionOnStruct {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 #[label]
 //~^ ERROR `#[label]` is not a valid attribute
 struct LabelOnStruct {
@@ -657,30 +657,30 @@ struct LabelOnStruct {
 
 #[derive(Diagnostic)]
 enum ExampleEnum {
-    #[diag(compiletest::example)]
+    #[diag(compiletest_example)]
     Foo {
         #[primary_span]
         sp: Span,
         #[note]
         note_sp: Span,
     },
-    #[diag(compiletest::example)]
+    #[diag(compiletest_example)]
     Bar {
         #[primary_span]
         sp: Span,
     },
-    #[diag(compiletest::example)]
+    #[diag(compiletest_example)]
     Baz,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example, code = "E0123")]
+#[diag(compiletest_example, code = "E0123")]
 struct RawIdentDiagnosticArg {
     pub r#type: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticBad {
     #[subdiagnostic(bad)]
 //~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
@@ -688,7 +688,7 @@ struct SubdiagnosticBad {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticBadStr {
     #[subdiagnostic = "bad"]
 //~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute
@@ -696,7 +696,7 @@ struct SubdiagnosticBadStr {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticBadTwice {
     #[subdiagnostic(bad, bad)]
 //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
@@ -704,7 +704,7 @@ struct SubdiagnosticBadTwice {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticBadLitStr {
     #[subdiagnostic("bad")]
 //~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
@@ -712,7 +712,7 @@ struct SubdiagnosticBadLitStr {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticEagerLint {
     #[subdiagnostic(eager)]
 //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
@@ -720,7 +720,7 @@ struct SubdiagnosticEagerLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticEagerCorrect {
     #[subdiagnostic(eager)]
     note: Note,
@@ -732,7 +732,7 @@ struct SubdiagnosticEagerCorrect {
 
 #[derive(Subdiagnostic)]
 #[suggestion_short(
-    parser::use_instead,
+    use_instead,
     applicability = "machine-applicable",
     code = "{correct}"
 )]
@@ -744,8 +744,17 @@ pub(crate) struct SubdiagnosticWithSuggestion {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest::example)]
+#[diag(compiletest_example)]
 struct SubdiagnosticEagerSuggestion {
     #[subdiagnostic(eager)]
     sub: SubdiagnosticWithSuggestion,
 }
+
+/// with a doc comment on the type..
+#[derive(Diagnostic)]
+#[diag(compiletest_example, code = "E0123")]
+struct WithDocComment {
+    /// ..and the field
+    #[primary_span]
+    span: Span,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 7a42d618707..0a1c4bddb06 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,8 +1,8 @@
 error: unsupported type attribute for diagnostic derive enum
   --> $DIR/diagnostic-derive.rs:39:1
    |
-LL | #[diag(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[diag(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:42:5
@@ -10,7 +10,7 @@ error: diagnostic slug not specified
 LL |     Foo,
    |     ^^^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:44:5
@@ -18,7 +18,7 @@ error: diagnostic slug not specified
 LL |     Bar,
    |     ^^^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:50:1
@@ -29,20 +29,20 @@ LL | #[diag = "E0123"]
 error: `#[nonsense(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:55:1
    |
-LL | #[nonsense(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[nonsense(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:55:1
    |
-LL | / #[nonsense(compiletest::example, code = "E0123")]
+LL | / #[nonsense(compiletest_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
 LL | | struct InvalidStructAttr {}
    | |___________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag("...")]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:62:8
@@ -61,7 +61,7 @@ LL | |
 LL | | struct InvalidLitNestedAttr {}
    | |______________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(nonsense(...))]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:73:8
@@ -80,7 +80,7 @@ LL | |
 LL | | struct InvalidNestedStructAttr1 {}
    | |__________________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(nonsense = ...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:79:8
@@ -108,7 +108,7 @@ LL | |
 LL | | struct InvalidNestedStructAttr2 {}
    | |__________________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(nonsense = ...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:86:8
@@ -134,13 +134,13 @@ LL | |
 LL | | struct InvalidNestedStructAttr3 {}
    | |__________________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:93:46
+  --> $DIR/diagnostic-derive.rs:93:45
    |
-LL | #[diag(compiletest::example, code = "E0123", slug = "foo")]
-   |                                              ^^^^^^^^^^^^
+LL | #[diag(compiletest_example, code = "E0123", slug = "foo")]
+   |                                             ^^^^^^^^^^^^
    |
    = help: only `code` is a valid nested attributes following the slug
 
@@ -153,44 +153,44 @@ LL |     #[suggestion = "bar"]
 error: specified multiple times
   --> $DIR/diagnostic-derive.rs:107:8
    |
-LL | #[diag(compiletest::example, code = "E0456")]
-   |        ^^^^^^^^^^^^^^^^^^^^
+LL | #[diag(compiletest_example, code = "E0456")]
+   |        ^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
   --> $DIR/diagnostic-derive.rs:106:8
    |
-LL | #[diag(compiletest::example, code = "E0123")]
-   |        ^^^^^^^^^^^^^^^^^^^^
+LL | #[diag(compiletest_example, code = "E0123")]
+   |        ^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:107:37
+  --> $DIR/diagnostic-derive.rs:107:36
    |
-LL | #[diag(compiletest::example, code = "E0456")]
-   |                                     ^^^^^^^
+LL | #[diag(compiletest_example, code = "E0456")]
+   |                                    ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:106:37
+  --> $DIR/diagnostic-derive.rs:106:36
    |
-LL | #[diag(compiletest::example, code = "E0123")]
-   |                                     ^^^^^^^
+LL | #[diag(compiletest_example, code = "E0123")]
+   |                                    ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:113:53
+  --> $DIR/diagnostic-derive.rs:113:52
    |
-LL | #[diag(compiletest::example, code = "E0456", code = "E0457")]
-   |                                                     ^^^^^^^
+LL | #[diag(compiletest_example, code = "E0456", code = "E0457")]
+   |                                                    ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:113:37
+  --> $DIR/diagnostic-derive.rs:113:36
    |
-LL | #[diag(compiletest::example, code = "E0456", code = "E0457")]
-   |                                     ^^^^^^^
+LL | #[diag(compiletest_example, code = "E0456", code = "E0457")]
+   |                                    ^^^^^^^
 
-error: `#[diag(compiletest::example)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:118:30
+error: `#[diag(compiletest_example)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:118:29
    |
-LL | #[diag(compiletest::example, compiletest::example, code = "E0456")]
-   |                              ^^^^^^^^^^^^^^^^^^^^
+LL | #[diag(compiletest_example, compiletest_example, code = "E0456")]
+   |                             ^^^^^^^^^^^^^^^^^^^
    |
    = help: diagnostic slug must be the first argument
 
@@ -200,7 +200,7 @@ error: diagnostic slug not specified
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:126:1
@@ -210,7 +210,7 @@ LL | |
 LL | | struct SlugNotProvided {}
    | |_________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:137:5
@@ -227,14 +227,14 @@ LL |     #[nonsense]
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:162:5
    |
-LL |     #[label(compiletest::label)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[label(label)]
+   |     ^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:170:50
+  --> $DIR/diagnostic-derive.rs:170:37
    |
-LL |     #[suggestion(compiletest::suggestion, code = "{name}")]
-   |                                                  ^^^^^^^^
+LL |     #[suggestion(suggestion, code = "{name}")]
+   |                                     ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
   --> $DIR/diagnostic-derive.rs:175:10
@@ -257,14 +257,14 @@ LL | #[derive(Diagnostic)]
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:205:5
    |
-LL |     #[label(compiletest::label)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[label(label)]
+   |     ^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:223:5
    |
-LL |     #[suggestion(compiletest::suggestion)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:231:18
@@ -297,7 +297,7 @@ LL |     #[suggestion(msg = "bar")]
 error: wrong field type for suggestion
   --> $DIR/diagnostic-derive.rs:263:5
    |
-LL | /     #[suggestion(compiletest::suggestion, code = "This is suggested code")]
+LL | /     #[suggestion(suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: Applicability,
    | |_____________________________^
@@ -335,10 +335,10 @@ LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:445:57
+  --> $DIR/diagnostic-derive.rs:445:44
    |
-LL |     #[suggestion(compiletest::suggestion, code = "...", applicability = "maybe-incorrect")]
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
   --> $DIR/diagnostic-derive.rs:447:24
@@ -347,30 +347,30 @@ LL |     suggestion: (Span, Applicability),
    |                        ^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:453:57
+  --> $DIR/diagnostic-derive.rs:453:44
    |
-LL |     #[suggestion(compiletest::suggestion, code = "...", applicability = "batman")]
-   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(suggestion, code = "...", applicability = "batman")]
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(foo)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:516:33
+  --> $DIR/diagnostic-derive.rs:516:20
    |
-LL |     #[label(compiletest::label, foo)]
-   |                                 ^^^
+LL |     #[label(label, foo)]
+   |                    ^^^
    |
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: `#[label(foo = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:524:33
+  --> $DIR/diagnostic-derive.rs:524:20
    |
-LL |     #[label(compiletest::label, foo = "...")]
-   |                                 ^^^^^^^^^^^
+LL |     #[label(label, foo = "...")]
+   |                    ^^^^^^^^^^^
 
 error: `#[label(foo(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:532:33
+  --> $DIR/diagnostic-derive.rs:532:20
    |
-LL |     #[label(compiletest::label, foo("..."))]
-   |                                 ^^^^^^^^^^
+LL |     #[label(label, foo("..."))]
+   |                    ^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:545:5
@@ -383,73 +383,73 @@ LL |     #[primary_span]
 error: `#[error(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:565:1
    |
-LL | #[error(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:565:1
    |
-LL | / #[error(compiletest::example, code = "E0123")]
+LL | / #[error(compiletest_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
 LL | | struct ErrorAttribute {}
    | |________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[warn_(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:572:1
    |
-LL | #[warn_(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[warn_(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:572:1
    |
-LL | / #[warn_(compiletest::example, code = "E0123")]
+LL | / #[warn_(compiletest_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
 LL | | struct WarnAttribute {}
    | |_______________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:579:1
    |
-LL | #[lint(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[lint(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:579:1
    |
-LL | / #[lint(compiletest::example, code = "E0123")]
+LL | / #[lint(compiletest_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
 LL | | struct LintAttributeOnSessionDiag {}
    | |____________________________________^
    |
-   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis::example_error)]`
+   = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:586:1
    |
-LL | #[lint(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[lint(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:586:1
    |
-LL | #[lint(compiletest::example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[lint(compiletest_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:586:1
    |
-LL | / #[lint(compiletest::example, code = "E0123")]
+LL | / #[lint(compiletest_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -457,19 +457,19 @@ LL | |
 LL | | struct LintAttributeOnLintDiag {}
    | |_________________________________^
    |
-   = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest::example)]`
+   = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:596:57
+  --> $DIR/diagnostic-derive.rs:596:44
    |
-LL |     #[suggestion(compiletest::suggestion, code = "...", code = ",,,")]
-   |                                                         ^^^^^^^^^^^^
+LL |     #[suggestion(suggestion, code = "...", code = ",,,")]
+   |                                            ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:596:43
+  --> $DIR/diagnostic-derive.rs:596:30
    |
-LL |     #[suggestion(compiletest::suggestion, code = "...", code = ",,,")]
-   |                                           ^^^^^^^^^^^^
+LL |     #[suggestion(suggestion, code = "...", code = ",,,")]
+   |                              ^^^^^^^^^^^^
 
 error: wrong types for suggestion
   --> $DIR/diagnostic-derive.rs:605:24
@@ -490,14 +490,14 @@ LL |     suggestion: (Span,),
 error: suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:620:5
    |
-LL |     #[suggestion(compiletest::suggestion)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:627:1
    |
-LL | #[multipart_suggestion(compiletest::suggestion)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[multipart_suggestion(suggestion)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider creating a `Subdiagnostic` instead
 
@@ -512,16 +512,16 @@ LL | #[multipart_suggestion()]
 error: `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:634:5
    |
-LL |     #[multipart_suggestion(compiletest::suggestion)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[multipart_suggestion(suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:642:1
    |
-LL | #[suggestion(compiletest::suggestion, code = "...")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(suggestion, code = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
@@ -576,7 +576,7 @@ LL |     #[subdiagnostic(eager)]
 error: cannot find attribute `nonsense` in this scope
   --> $DIR/diagnostic-derive.rs:55:3
    |
-LL | #[nonsense(compiletest::example, code = "E0123")]
+LL | #[nonsense(compiletest_example, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
@@ -588,31 +588,31 @@ LL |     #[nonsense]
 error: cannot find attribute `error` in this scope
   --> $DIR/diagnostic-derive.rs:565:3
    |
-LL | #[error(compiletest::example, code = "E0123")]
+LL | #[error(compiletest_example, code = "E0123")]
    |   ^^^^^
 
 error: cannot find attribute `warn_` in this scope
   --> $DIR/diagnostic-derive.rs:572:3
    |
-LL | #[warn_(compiletest::example, code = "E0123")]
+LL | #[warn_(compiletest_example, code = "E0123")]
    |   ^^^^^ help: a built-in attribute with a similar name exists: `warn`
 
 error: cannot find attribute `lint` in this scope
   --> $DIR/diagnostic-derive.rs:579:3
    |
-LL | #[lint(compiletest::example, code = "E0123")]
+LL | #[lint(compiletest_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `lint` in this scope
   --> $DIR/diagnostic-derive.rs:586:3
    |
-LL | #[lint(compiletest::example, code = "E0123")]
+LL | #[lint(compiletest_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `multipart_suggestion` in this scope
   --> $DIR/diagnostic-derive.rs:627:3
    |
-LL | #[multipart_suggestion(compiletest::suggestion)]
+LL | #[multipart_suggestion(suggestion)]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
@@ -624,7 +624,7 @@ LL | #[multipart_suggestion()]
 error: cannot find attribute `multipart_suggestion` in this scope
   --> $DIR/diagnostic-derive.rs:634:7
    |
-LL |     #[multipart_suggestion(compiletest::suggestion)]
+LL |     #[multipart_suggestion(suggestion)]
    |       ^^^^^^^^^^^^^^^^^^^^
 
 error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index 84ee5af42de..9088ca6ce46 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -20,7 +20,7 @@ use rustc_span::Span;
 use rustc_macros::Subdiagnostic;
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct A {
     #[primary_span]
     span: Span,
@@ -29,13 +29,13 @@ struct A {
 
 #[derive(Subdiagnostic)]
 enum B {
-    #[label(parser::add_paren)]
+    #[label(parser_add_paren)]
     A {
         #[primary_span]
         span: Span,
         var: String,
     },
-    #[label(parser::add_paren)]
+    #[label(parser_add_paren)]
     B {
         #[primary_span]
         span: Span,
@@ -44,7 +44,7 @@ enum B {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 //~^ ERROR label without `#[primary_span]` field
 struct C {
     var: String,
@@ -138,7 +138,7 @@ struct M {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren, code = "...")]
+#[label(parser_add_paren, code = "...")]
 //~^ ERROR `#[label(code = ...)]` is not a valid attribute
 struct N {
     #[primary_span]
@@ -147,7 +147,7 @@ struct N {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren, applicability = "machine-applicable")]
+#[label(parser_add_paren, applicability = "machine-applicable")]
 //~^ ERROR `#[label(applicability = ...)]` is not a valid attribute
 struct O {
     #[primary_span]
@@ -160,7 +160,7 @@ struct O {
 //~^ ERROR cannot find attribute `foo` in this scope
 //~^^ ERROR unsupported type attribute for subdiagnostic enum
 enum P {
-    #[label(parser::add_paren)]
+    #[label(parser_add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -230,14 +230,13 @@ enum U {
 
 #[derive(Subdiagnostic)]
 enum V {
-    #[label(parser::add_paren)]
+    #[label(parser_add_paren)]
     A {
         #[primary_span]
         span: Span,
         var: String,
     },
     B {
-    //~^ ERROR subdiagnostic kind not specified
         #[primary_span]
         span: Span,
         var: String,
@@ -245,7 +244,7 @@ enum V {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 //~^ ERROR label without `#[primary_span]` field
 struct W {
     #[primary_span]
@@ -254,7 +253,7 @@ struct W {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct X {
     #[primary_span]
     span: Span,
@@ -264,7 +263,7 @@ struct X {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct Y {
     #[primary_span]
     span: Span,
@@ -275,7 +274,7 @@ struct Y {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct Z {
     #[primary_span]
     span: Span,
@@ -286,7 +285,7 @@ struct Z {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct AA {
     #[primary_span]
     span: Span,
@@ -297,7 +296,7 @@ struct AA {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct AB {
     #[primary_span]
     span: Span,
@@ -313,23 +312,23 @@ union AC {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
+#[label(parser_add_paren)]
 struct AD {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren, parser::add_paren)]
-//~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute
+#[label(parser_add_paren, parser_add_paren)]
+//~^ ERROR `#[label(parser_add_paren)]` is not a valid attribute
 struct AE {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct AF {
     #[primary_span]
     //~^ NOTE previously specified here
@@ -347,7 +346,7 @@ struct AG {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...")]
+#[suggestion(parser_add_paren, code = "...")]
 struct AH {
     #[primary_span]
     span: Span,
@@ -358,7 +357,7 @@ struct AH {
 
 #[derive(Subdiagnostic)]
 enum AI {
-    #[suggestion(parser::add_paren, code = "...")]
+    #[suggestion(parser_add_paren, code = "...")]
     A {
         #[primary_span]
         span: Span,
@@ -366,7 +365,7 @@ enum AI {
         applicability: Applicability,
         var: String,
     },
-    #[suggestion(parser::add_paren, code = "...")]
+    #[suggestion(parser_add_paren, code = "...")]
     B {
         #[primary_span]
         span: Span,
@@ -377,7 +376,7 @@ enum AI {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...", code = "...")]
+#[suggestion(parser_add_paren, code = "...", code = "...")]
 //~^ ERROR specified multiple times
 //~^^ NOTE previously specified here
 struct AJ {
@@ -388,7 +387,7 @@ struct AJ {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...")]
+#[suggestion(parser_add_paren, code = "...")]
 struct AK {
     #[primary_span]
     span: Span,
@@ -401,7 +400,7 @@ struct AK {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...")]
+#[suggestion(parser_add_paren, code = "...")]
 struct AL {
     #[primary_span]
     span: Span,
@@ -411,14 +410,14 @@ struct AL {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...")]
+#[suggestion(parser_add_paren, code = "...")]
 struct AM {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren)]
+#[suggestion(parser_add_paren)]
 //~^ ERROR suggestion without `code = "..."`
 struct AN {
     #[primary_span]
@@ -428,7 +427,7 @@ struct AN {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code ="...", applicability = "foo")]
+#[suggestion(parser_add_paren, code ="...", applicability = "foo")]
 //~^ ERROR invalid applicability
 struct AO {
     #[primary_span]
@@ -436,24 +435,24 @@ struct AO {
 }
 
 #[derive(Subdiagnostic)]
-#[help(parser::add_paren)]
+#[help(parser_add_paren)]
 struct AP {
     var: String
 }
 
 #[derive(Subdiagnostic)]
-#[note(parser::add_paren)]
+#[note(parser_add_paren)]
 struct AQ;
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...")]
+#[suggestion(parser_add_paren, code = "...")]
 //~^ ERROR suggestion without `#[primary_span]` field
 struct AR {
     var: String,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code ="...", applicability = "machine-applicable")]
+#[suggestion(parser_add_paren, code ="...", applicability = "machine-applicable")]
 struct AS {
     #[primary_span]
     span: Span,
@@ -463,7 +462,7 @@ struct AS {
 #[label]
 //~^ ERROR unsupported type attribute for subdiagnostic enum
 enum AT {
-    #[label(parser::add_paren)]
+    #[label(parser_add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -472,7 +471,7 @@ enum AT {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+#[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
 struct AU {
     #[primary_span]
     span: Span,
@@ -480,7 +479,7 @@ struct AU {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+#[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
 struct AV {
     #[primary_span]
@@ -489,7 +488,7 @@ struct AV {
 
 #[derive(Subdiagnostic)]
 enum AW {
-    #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+    #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
     A {
         #[primary_span]
         span: Span,
@@ -499,7 +498,7 @@ enum AW {
 
 #[derive(Subdiagnostic)]
 enum AX {
-    #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+    #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
     A {
         #[primary_span]
@@ -508,18 +507,18 @@ enum AX {
 }
 
 #[derive(Subdiagnostic)]
-#[warning(parser::add_paren)]
+#[warning(parser_add_paren)]
 struct AY {}
 
 #[derive(Subdiagnostic)]
-#[warning(parser::add_paren)]
+#[warning(parser_add_paren)]
 struct AZ {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parser::add_paren, code = "...")]
+#[suggestion(parser_add_paren, code = "...")]
 //~^ ERROR suggestion without `#[primary_span]` field
 struct BA {
     #[suggestion_part]
@@ -534,7 +533,7 @@ struct BA {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
 //~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
 //~| ERROR `#[multipart_suggestion(code = ...)]` is not a valid attribute
 struct BBa {
@@ -542,7 +541,7 @@ struct BBa {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, applicability = "machine-applicable")]
 struct BBb {
     #[suggestion_part]
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
@@ -550,7 +549,7 @@ struct BBb {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, applicability = "machine-applicable")]
 struct BBc {
     #[suggestion_part()]
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
@@ -558,7 +557,7 @@ struct BBc {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren)]
+#[multipart_suggestion(parser_add_paren)]
 //~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
 struct BC {
     #[primary_span]
@@ -567,7 +566,7 @@ struct BC {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren)]
+#[multipart_suggestion(parser_add_paren)]
 struct BD {
     #[suggestion_part]
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
@@ -587,7 +586,7 @@ struct BD {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, applicability = "machine-applicable")]
 struct BE {
     #[suggestion_part(code = "...", code = ",,,")]
     //~^ ERROR specified multiple times
@@ -596,7 +595,7 @@ struct BE {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, applicability = "machine-applicable")]
 struct BF {
     #[suggestion_part(code = "(")]
     first: Span,
@@ -605,7 +604,7 @@ struct BF {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren)]
+#[multipart_suggestion(parser_add_paren)]
 struct BG {
     #[applicability]
     appl: Applicability,
@@ -616,7 +615,7 @@ struct BG {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, applicability = "machine-applicable")]
 struct BH {
     #[applicability]
     //~^ ERROR `#[applicability]` has no effect
@@ -628,16 +627,37 @@ struct BH {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(parser_add_paren, applicability = "machine-applicable")]
 struct BI {
     #[suggestion_part(code = "")]
     spans: Vec<Span>,
 }
 
 #[derive(Subdiagnostic)]
-#[label(parser::add_paren)]
+#[label(parser_add_paren)]
 struct BJ {
     #[primary_span]
     span: Span,
     r#type: String,
 }
+
+/// with a doc comment on the type..
+#[derive(Subdiagnostic)]
+#[label(parser_add_paren)]
+struct BK {
+    /// ..and the field
+    #[primary_span]
+    span: Span,
+}
+
+/// with a doc comment on the type..
+#[derive(Subdiagnostic)]
+enum BL {
+    /// ..and the variant..
+    #[label(parser_add_paren)]
+    Foo {
+        /// ..and the field
+        #[primary_span]
+        span: Span,
+    }
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 171b89e657d..b21f9cc94a9 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,7 +1,7 @@
 error: label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:47:1
    |
-LL | / #[label(parser::add_paren)]
+LL | / #[label(parser_add_paren)]
 LL | |
 LL | | struct C {
 LL | |     var: String,
@@ -81,16 +81,16 @@ LL | #[label()]
    | ^^^^^^^^^^
 
 error: `#[label(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:141:28
+  --> $DIR/subdiagnostic-derive.rs:141:27
    |
-LL | #[label(parser::add_paren, code = "...")]
-   |                            ^^^^^^^^^^^^
+LL | #[label(parser_add_paren, code = "...")]
+   |                           ^^^^^^^^^^^^
 
 error: `#[label(applicability = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:150:28
+  --> $DIR/subdiagnostic-derive.rs:150:27
    |
-LL | #[label(parser::add_paren, applicability = "machine-applicable")]
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser_add_paren, applicability = "machine-applicable")]
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
   --> $DIR/subdiagnostic-derive.rs:159:1
@@ -134,22 +134,16 @@ error: diagnostic slug must be first argument of a `#[label(...)]` attribute
 LL |     #[label(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:239:5
-   |
-LL |     B {
-   |     ^
-
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:251:5
+  --> $DIR/subdiagnostic-derive.rs:250:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:248:1
+  --> $DIR/subdiagnostic-derive.rs:247:1
    |
-LL | / #[label(parser::add_paren)]
+LL | / #[label(parser_add_paren)]
 LL | |
 LL | | struct W {
 LL | |     #[primary_span]
@@ -159,13 +153,13 @@ LL | | }
    | |_^
 
 error: `#[applicability]` is only valid on suggestions
-  --> $DIR/subdiagnostic-derive.rs:261:5
+  --> $DIR/subdiagnostic-derive.rs:260:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:271:5
+  --> $DIR/subdiagnostic-derive.rs:270:5
    |
 LL |     #[bar]
    |     ^^^^^^
@@ -173,13 +167,13 @@ LL |     #[bar]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:282:5
+  --> $DIR/subdiagnostic-derive.rs:281:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:293:5
+  --> $DIR/subdiagnostic-derive.rs:292:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
@@ -187,7 +181,7 @@ LL |     #[bar("...")]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: unexpected unsupported untagged union
-  --> $DIR/subdiagnostic-derive.rs:309:1
+  --> $DIR/subdiagnostic-derive.rs:308:1
    |
 LL | / union AC {
 LL | |
@@ -196,78 +190,78 @@ LL | |     b: u64
 LL | | }
    | |_^
 
-error: `#[label(parser::add_paren)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:324:28
+error: `#[label(parser_add_paren)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:323:27
    |
-LL | #[label(parser::add_paren, parser::add_paren)]
-   |                            ^^^^^^^^^^^^^^^^^
+LL | #[label(parser_add_paren, parser_add_paren)]
+   |                           ^^^^^^^^^^^^^^^^
    |
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:337:5
+  --> $DIR/subdiagnostic-derive.rs:336:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:334:5
+  --> $DIR/subdiagnostic-derive.rs:333:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:343:8
+  --> $DIR/subdiagnostic-derive.rs:342:8
    |
 LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:380:47
+  --> $DIR/subdiagnostic-derive.rs:379:46
    |
-LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
-   |                                               ^^^^^^^^^^^^
+LL | #[suggestion(parser_add_paren, code = "...", code = "...")]
+   |                                              ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:380:33
+  --> $DIR/subdiagnostic-derive.rs:379:32
    |
-LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
-   |                                 ^^^^^^^^^^^^
+LL | #[suggestion(parser_add_paren, code = "...", code = "...")]
+   |                                ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:398:5
+  --> $DIR/subdiagnostic-derive.rs:397:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:395:5
+  --> $DIR/subdiagnostic-derive.rs:394:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:408:5
+  --> $DIR/subdiagnostic-derive.rs:407:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:421:1
+  --> $DIR/subdiagnostic-derive.rs:420:1
    |
-LL | #[suggestion(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(parser_add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:431:46
+  --> $DIR/subdiagnostic-derive.rs:430:45
    |
-LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
-   |                                              ^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(parser_add_paren, code ="...", applicability = "foo")]
+   |                                             ^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:449:1
+  --> $DIR/subdiagnostic-derive.rs:448:1
    |
-LL | / #[suggestion(parser::add_paren, code = "...")]
+LL | / #[suggestion(parser_add_paren, code = "...")]
 LL | |
 LL | | struct AR {
 LL | |     var: String,
@@ -275,25 +269,25 @@ LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:463:1
+  --> $DIR/subdiagnostic-derive.rs:462:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:483:39
+  --> $DIR/subdiagnostic-derive.rs:482:38
    |
-LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
-   |                                       ^^^^^^^
+LL | #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                      ^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:502:43
+  --> $DIR/subdiagnostic-derive.rs:501:42
    |
-LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
-   |                                           ^^^^^^^
+LL |     #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                          ^^^^^^^
 
 error: `#[suggestion_part]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:525:5
+  --> $DIR/subdiagnostic-derive.rs:524:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
@@ -301,7 +295,7 @@ LL |     #[suggestion_part]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
 error: `#[suggestion_part(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:528:5
+  --> $DIR/subdiagnostic-derive.rs:527:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -309,9 +303,9 @@ LL |     #[suggestion_part(code = "...")]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:522:1
+  --> $DIR/subdiagnostic-derive.rs:521:1
    |
-LL | / #[suggestion(parser::add_paren, code = "...")]
+LL | / #[suggestion(parser_add_paren, code = "...")]
 LL | |
 LL | | struct BA {
 LL | |     #[suggestion_part]
@@ -321,17 +315,17 @@ LL | | }
    | |_^
 
 error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:537:43
+  --> $DIR/subdiagnostic-derive.rs:536:42
    |
-LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
-   |                                           ^^^^^^^^^^^^
+LL | #[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
+   |                                          ^^^^^^^^^^^^
    |
    = help: only `applicability` is a valid nested attributes
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:537:1
+  --> $DIR/subdiagnostic-derive.rs:536:1
    |
-LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
+LL | / #[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
 LL | |
 LL | |
 LL | | struct BBa {
@@ -340,19 +334,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:547:5
+  --> $DIR/subdiagnostic-derive.rs:546:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:555:5
+  --> $DIR/subdiagnostic-derive.rs:554:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:564:5
+  --> $DIR/subdiagnostic-derive.rs:563:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -360,9 +354,9 @@ LL |     #[primary_span]
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:561:1
+  --> $DIR/subdiagnostic-derive.rs:560:1
    |
-LL | / #[multipart_suggestion(parser::add_paren)]
+LL | / #[multipart_suggestion(parser_add_paren)]
 LL | |
 LL | | struct BC {
 LL | |     #[primary_span]
@@ -372,19 +366,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:572:5
+  --> $DIR/subdiagnostic-derive.rs:571:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:575:5
+  --> $DIR/subdiagnostic-derive.rs:574:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(foo = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:578:23
+  --> $DIR/subdiagnostic-derive.rs:577:23
    |
 LL |     #[suggestion_part(foo = "bar")]
    |                       ^^^^^^^^^^^
@@ -392,31 +386,31 @@ LL |     #[suggestion_part(foo = "bar")]
    = help: `code` is the only valid nested attribute
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:581:5
+  --> $DIR/subdiagnostic-derive.rs:580:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:584:5
+  --> $DIR/subdiagnostic-derive.rs:583:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:592:37
+  --> $DIR/subdiagnostic-derive.rs:591:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                                     ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:592:23
+  --> $DIR/subdiagnostic-derive.rs:591:23
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                       ^^^^^^^^^^^^
 
 error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
-  --> $DIR/subdiagnostic-derive.rs:621:5
+  --> $DIR/subdiagnostic-derive.rs:620:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
@@ -458,19 +452,19 @@ LL |     #[bar("...")]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:271:7
+  --> $DIR/subdiagnostic-derive.rs:270:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:282:7
+  --> $DIR/subdiagnostic-derive.rs:281:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:293:7
+  --> $DIR/subdiagnostic-derive.rs:292:7
    |
 LL |     #[bar("...")]
    |       ^^^
@@ -481,6 +475,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
 LL | #[label(slug)]
    |         ^^^^ not found in `rustc_errors::fluent`
 
-error: aborting due to 68 previous errors
+error: aborting due to 67 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/abi/abi-sysv64-register-usage.rs b/src/test/ui/abi/abi-sysv64-register-usage.rs
index 9404e71d0fe..39330693677 100644
--- a/src/test/ui/abi/abi-sysv64-register-usage.rs
+++ b/src/test/ui/abi/abi-sysv64-register-usage.rs
@@ -6,20 +6,30 @@
 // ignore-arm
 // ignore-aarch64
 // needs-asm-support
-#![feature(asm_sym)]
 
 #[cfg(target_arch = "x86_64")]
-pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
-                                         rcx: i64, r8 : i64, r9 : i64,
-                                         xmm0: f32, xmm1: f32, xmm2: f32,
-                                         xmm3: f32, xmm4: f32, xmm5: f32,
-                                         xmm6: f32, xmm7: f32) -> i64 {
+pub extern "sysv64" fn all_the_registers(
+    rdi: i64,
+    rsi: i64,
+    rdx: i64,
+    rcx: i64,
+    r8: i64,
+    r9: i64,
+    xmm0: f32,
+    xmm1: f32,
+    xmm2: f32,
+    xmm3: f32,
+    xmm4: f32,
+    xmm5: f32,
+    xmm6: f32,
+    xmm7: f32,
+) -> i64 {
     assert_eq!(rdi, 1);
     assert_eq!(rsi, 2);
     assert_eq!(rdx, 3);
     assert_eq!(rcx, 4);
-    assert_eq!(r8,  5);
-    assert_eq!(r9,  6);
+    assert_eq!(r8, 5);
+    assert_eq!(r9, 6);
     assert_eq!(xmm0, 1.0f32);
     assert_eq!(xmm1, 2.0f32);
     assert_eq!(xmm2, 4.0f32);
diff --git a/src/test/ui/alloc-error/default-alloc-error-hook.rs b/src/test/ui/alloc-error/default-alloc-error-hook.rs
index 100e974977c..8be09500f4e 100644
--- a/src/test/ui/alloc-error/default-alloc-error-hook.rs
+++ b/src/test/ui/alloc-error/default-alloc-error-hook.rs
@@ -15,5 +15,14 @@ fn main() {
     let me = env::current_exe().unwrap();
     let output = Command::new(&me).arg("next").output().unwrap();
     assert!(!output.status.success(), "{:?} is a success", output.status);
-    assert_eq!(str::from_utf8(&output.stderr).unwrap(), "memory allocation of 42 bytes failed\n");
+
+    let mut stderr = str::from_utf8(&output.stderr).unwrap();
+
+    // When running inside QEMU user-mode emulation, there will be an extra message printed by QEMU
+    // in the stderr whenever a core dump happens. Remove it before the check.
+    stderr = stderr
+        .strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n")
+        .unwrap_or(stderr);
+
+    assert_eq!(stderr, "memory allocation of 42 bytes failed\n");
 }
diff --git a/src/test/ui/asm/aarch64/bad-reg.rs b/src/test/ui/asm/aarch64/bad-reg.rs
index 2b6a9b71cd5..9ccb8ed6762 100644
--- a/src/test/ui/asm/aarch64/bad-reg.rs
+++ b/src/test/ui/asm/aarch64/bad-reg.rs
@@ -1,7 +1,7 @@
 // only-aarch64
 // compile-flags: -C target-feature=+neon
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/asm/aarch64/may_unwind.rs b/src/test/ui/asm/aarch64/may_unwind.rs
index dfd891b4212..6af8728bbaa 100644
--- a/src/test/ui/asm/aarch64/may_unwind.rs
+++ b/src/test/ui/asm/aarch64/may_unwind.rs
@@ -2,7 +2,7 @@
 // run-pass
 // needs-asm-support
 
-#![feature(asm_sym, asm_unwind)]
+#![feature(asm_unwind)]
 
 use std::arch::asm;
 use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
diff --git a/src/test/ui/asm/aarch64/sym.rs b/src/test/ui/asm/aarch64/sym.rs
index 3f659363cc8..6a6cdb00d51 100644
--- a/src/test/ui/asm/aarch64/sym.rs
+++ b/src/test/ui/asm/aarch64/sym.rs
@@ -3,7 +3,7 @@
 // needs-asm-support
 // run-pass
 
-#![feature(thread_local, asm_sym)]
+#![feature(thread_local)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/asm/aarch64/type-check-2-2.rs b/src/test/ui/asm/aarch64/type-check-2-2.rs
index aa12d4aa4b4..0ce1f1d8f7f 100644
--- a/src/test/ui/asm/aarch64/type-check-2-2.rs
+++ b/src/test/ui/asm/aarch64/type-check-2-2.rs
@@ -1,6 +1,6 @@
 // only-aarch64
 
-#![feature(repr_simd, never_type, asm_sym)]
+#![feature(repr_simd, never_type)]
 
 use std::arch::{asm, global_asm};
 
diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs
index fdafe63c7b0..1c71c1185d4 100644
--- a/src/test/ui/asm/aarch64/type-check-2.rs
+++ b/src/test/ui/asm/aarch64/type-check-2.rs
@@ -1,6 +1,6 @@
 // only-aarch64
 
-#![feature(repr_simd, never_type, asm_sym)]
+#![feature(repr_simd, never_type)]
 
 use std::arch::{asm, global_asm};
 
diff --git a/src/test/ui/asm/generic-const.rs b/src/test/ui/asm/generic-const.rs
index 55c5587804b..caa9b7dbce6 100644
--- a/src/test/ui/asm/generic-const.rs
+++ b/src/test/ui/asm/generic-const.rs
@@ -1,7 +1,7 @@
 // needs-asm-support
 // build-pass
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs
index 9e626f5711d..2f3716ca77f 100644
--- a/src/test/ui/asm/naked-functions.rs
+++ b/src/test/ui/asm/naked-functions.rs
@@ -4,7 +4,7 @@
 // ignore-wasm32
 
 #![feature(naked_functions)]
-#![feature(asm_const, asm_sym, asm_unwind)]
+#![feature(asm_const, asm_unwind)]
 #![crate_type = "lib"]
 
 use std::arch::asm;
diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs
index 50b369ae045..59f7b36afcd 100644
--- a/src/test/ui/asm/type-check-1.rs
+++ b/src/test/ui/asm/type-check-1.rs
@@ -3,7 +3,7 @@
 // ignore-spirv
 // ignore-wasm32
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::{asm, global_asm};
 
diff --git a/src/test/ui/asm/unpretty-expanded.rs b/src/test/ui/asm/unpretty-expanded.rs
index 6128f49b89a..25cf1c3d730 100644
--- a/src/test/ui/asm/unpretty-expanded.rs
+++ b/src/test/ui/asm/unpretty-expanded.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // check-pass
 // compile-flags: -Zunpretty=expanded
 core::arch::global_asm!("x: .byte 42");
diff --git a/src/test/ui/asm/unpretty-expanded.stdout b/src/test/ui/asm/unpretty-expanded.stdout
index 15b60d1559c..ab1b5f45e5c 100644
--- a/src/test/ui/asm/unpretty-expanded.stdout
+++ b/src/test/ui/asm/unpretty-expanded.stdout
@@ -4,6 +4,7 @@
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
+// needs-asm-support
 // check-pass
 // compile-flags: -Zunpretty=expanded
 global_asm! ("x: .byte 42");
diff --git a/src/test/ui/asm/x86_64/bad-reg.rs b/src/test/ui/asm/x86_64/bad-reg.rs
index a4f50a534a1..f5728079a6a 100644
--- a/src/test/ui/asm/x86_64/bad-reg.rs
+++ b/src/test/ui/asm/x86_64/bad-reg.rs
@@ -1,7 +1,7 @@
 // only-x86_64
 // compile-flags: -C target-feature=+avx2
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/asm/x86_64/issue-96797.rs b/src/test/ui/asm/x86_64/issue-96797.rs
index d3e0906f37a..954f8c5ccc3 100644
--- a/src/test/ui/asm/x86_64/issue-96797.rs
+++ b/src/test/ui/asm/x86_64/issue-96797.rs
@@ -7,8 +7,6 @@
 
 // regression test for #96797
 
-#![feature(asm_sym)]
-
 use std::arch::global_asm;
 
 #[no_mangle]
diff --git a/src/test/ui/asm/x86_64/may_unwind.rs b/src/test/ui/asm/x86_64/may_unwind.rs
index 2f5d1a36024..c11f0938d0b 100644
--- a/src/test/ui/asm/x86_64/may_unwind.rs
+++ b/src/test/ui/asm/x86_64/may_unwind.rs
@@ -3,7 +3,7 @@
 // needs-asm-support
 // needs-unwind
 
-#![feature(asm_sym, asm_unwind)]
+#![feature(asm_unwind)]
 
 use std::arch::asm;
 use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
diff --git a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
index 513eb270e4f..06589431a44 100644
--- a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
+++ b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
@@ -4,8 +4,6 @@
 
 // Checks that multiple clobber_abi options can be used
 
-#![feature(asm_sym)]
-
 use std::arch::asm;
 
 extern "sysv64" fn foo(x: i32) -> i32 {
diff --git a/src/test/ui/asm/x86_64/sym.rs b/src/test/ui/asm/x86_64/sym.rs
index 447e11e6eab..93ef4f09062 100644
--- a/src/test/ui/asm/x86_64/sym.rs
+++ b/src/test/ui/asm/x86_64/sym.rs
@@ -3,7 +3,7 @@
 // needs-asm-support
 // run-pass
 
-#![feature(thread_local, asm_sym)]
+#![feature(thread_local)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs
index 59d8cde3fb6..80b29ec870f 100644
--- a/src/test/ui/asm/x86_64/type-check-2.rs
+++ b/src/test/ui/asm/x86_64/type-check-2.rs
@@ -1,6 +1,6 @@
 // only-x86_64
 
-#![feature(repr_simd, never_type, asm_sym)]
+#![feature(repr_simd, never_type)]
 
 use std::arch::{asm, global_asm};
 
diff --git a/src/test/ui/asm/x86_64/type-check-4.rs b/src/test/ui/asm/x86_64/type-check-4.rs
index da3b76c3d23..3d5d3807c53 100644
--- a/src/test/ui/asm/x86_64/type-check-4.rs
+++ b/src/test/ui/asm/x86_64/type-check-4.rs
@@ -1,14 +1,13 @@
 // only-x86_64
 // compile-flags: -C target-feature=+avx512f
 
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
 
 use std::arch::{asm, global_asm};
 
 use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
 
-fn main() {
-}
+fn main() {}
 
 // Constants must be... constant
 
diff --git a/src/test/ui/asm/x86_64/type-check-4.stderr b/src/test/ui/asm/x86_64/type-check-4.stderr
index 33f4638fb4b..3875bcc2112 100644
--- a/src/test/ui/asm/x86_64/type-check-4.stderr
+++ b/src/test/ui/asm/x86_64/type-check-4.stderr
@@ -1,5 +1,5 @@
 error[E0013]: constants cannot refer to statics
-  --> $DIR/type-check-4.rs:22:25
+  --> $DIR/type-check-4.rs:21:25
    |
 LL | global_asm!("{}", const S);
    |                         ^
@@ -7,7 +7,7 @@ LL | global_asm!("{}", const S);
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0013]: constants cannot refer to statics
-  --> $DIR/type-check-4.rs:25:35
+  --> $DIR/type-check-4.rs:24:35
    |
 LL | global_asm!("{}", const const_foo(S));
    |                                   ^
@@ -15,7 +15,7 @@ LL | global_asm!("{}", const const_foo(S));
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0013]: constants cannot refer to statics
-  --> $DIR/type-check-4.rs:28:35
+  --> $DIR/type-check-4.rs:27:35
    |
 LL | global_asm!("{}", const const_bar(S));
    |                                   ^
diff --git a/src/test/ui/asm/x86_64/type-check-5.rs b/src/test/ui/asm/x86_64/type-check-5.rs
index 6190e0b52f4..8198df91095 100644
--- a/src/test/ui/asm/x86_64/type-check-5.rs
+++ b/src/test/ui/asm/x86_64/type-check-5.rs
@@ -1,6 +1,6 @@
 // only-x86_64
 
-#![feature(repr_simd, never_type, asm_sym)]
+#![feature(repr_simd, never_type)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
index f26037f0707..8eb8c44bb42 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.rs
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -16,7 +16,7 @@ enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 enum E3 { V(dyn Iterator<Item: 'static>) }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)`
+//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
 
 union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
@@ -25,6 +25,6 @@ union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)`
+//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
 
 fn main() {}
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
index 978390fa712..dbfcfa58063 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.stderr
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -70,13 +70,13 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL | enum E1 { V(Box<dyn Iterator<Item: Copy>>) }
    |             ++++                        +
 
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time
+error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)` cannot be known at compilation time
   --> $DIR/inside-adt.rs:17:13
    |
 LL | enum E3 { V(dyn Iterator<Item: 'static>) }
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)`
+   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -107,14 +107,14 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL | union U1 { f: Box<ManuallyDrop<dyn Iterator<Item: Copy>>> }
    |               ++++                                      +
 
-error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time
+error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized + 'static> + 'static)` cannot be known at compilation time
   --> $DIR/inside-adt.rs:26:15
    |
 LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)`
-   = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>`
+   = help: within `ManuallyDrop<(dyn Iterator<Item = impl Sized + 'static> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized + 'static> + 'static)`
+   = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Sized + 'static> + 'static)>`
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs
index 384561f8ccd..e8548d402fa 100644
--- a/src/test/ui/associated-types/issue-87261.rs
+++ b/src/test/ui/associated-types/issue-87261.rs
@@ -77,10 +77,10 @@ where
 
 fn main() {
     accepts_trait(returns_opaque());
-    //~^ ERROR type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl Trait + 'static as Trait>::Associated == ()`
 
     accepts_trait(returns_opaque_derived());
-    //~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait + 'static as Trait>::Associated == ()`
 
     accepts_trait(returns_opaque_foo());
     //~^ ERROR type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
@@ -89,7 +89,7 @@ fn main() {
     //~^ ERROR type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic());
-    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + 'static as GenericTrait<()>>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic_foo());
     //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr
index f24423dd106..2cce6b94702 100644
--- a/src/test/ui/associated-types/issue-87261.stderr
+++ b/src/test/ui/associated-types/issue-87261.stderr
@@ -132,7 +132,7 @@ note: required by a bound in `accepts_generic_trait`
 LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
    |                                              ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
 
-error[E0271]: type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Trait + 'static as Trait>::Associated == ()`
   --> $DIR/issue-87261.rs:79:19
    |
 LL | fn returns_opaque() -> impl Trait + 'static {
@@ -144,18 +144,18 @@ LL |     accepts_trait(returns_opaque());
    |     required by a bound introduced by this call
    |
    = note:    expected unit type `()`
-           found associated type `<impl Trait as Trait>::Associated`
+           found associated type `<impl Trait + 'static as Trait>::Associated`
 note: required by a bound in `accepts_trait`
   --> $DIR/issue-87261.rs:43:27
    |
 LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
    |                           ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
-help: consider constraining the associated type `<impl Trait as Trait>::Associated` to `()`
+help: consider constraining the associated type `<impl Trait + 'static as Trait>::Associated` to `()`
    |
 LL | fn returns_opaque() -> impl Trait<Associated = ()> + 'static {
    |                                  +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl DerivedTrait + 'static as Trait>::Associated == ()`
   --> $DIR/issue-87261.rs:82:19
    |
 LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static {
@@ -167,13 +167,13 @@ LL |     accepts_trait(returns_opaque_derived());
    |     required by a bound introduced by this call
    |
    = note:    expected unit type `()`
-           found associated type `<impl DerivedTrait as Trait>::Associated`
+           found associated type `<impl DerivedTrait + 'static as Trait>::Associated`
 note: required by a bound in `accepts_trait`
   --> $DIR/issue-87261.rs:43:27
    |
 LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
    |                           ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
-help: consider constraining the associated type `<impl DerivedTrait as Trait>::Associated` to `()`
+help: consider constraining the associated type `<impl DerivedTrait + 'static as Trait>::Associated` to `()`
    |
 LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
    |                                                 +++++++++++++++++
@@ -222,7 +222,7 @@ note: required by a bound in `accepts_trait`
 LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
    |                           ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
 
-error[E0271]: type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> + 'static as GenericTrait<()>>::Associated == ()`
   --> $DIR/issue-87261.rs:91:27
    |
 LL | fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
@@ -234,13 +234,13 @@ LL |     accepts_generic_trait(returns_opaque_generic());
    |     required by a bound introduced by this call
    |
    = note:    expected unit type `()`
-           found associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated`
+           found associated type `<impl GenericTrait<()> + 'static as GenericTrait<()>>::Associated`
 note: required by a bound in `accepts_generic_trait`
   --> $DIR/issue-87261.rs:44:46
    |
 LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
    |                                              ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
-help: consider constraining the associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
+help: consider constraining the associated type `<impl GenericTrait<()> + 'static as GenericTrait<()>>::Associated` to `()`
    |
 LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
    |                                                    +++++++++++++++++
diff --git a/src/test/ui/async-await/in-trait/issue-102310.rs b/src/test/ui/async-await/in-trait/issue-102310.rs
new file mode 100644
index 00000000000..49c3e9feeb4
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/issue-102310.rs
@@ -0,0 +1,15 @@
+// check-pass
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+pub trait SpiDevice {
+    async fn transaction<F, R>(&mut self);
+}
+
+impl SpiDevice for () {
+    async fn transaction<F, R>(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr
index aa947b69003..5e5a980adb9 100644
--- a/src/test/ui/async-await/issues/issue-72312.stderr
+++ b/src/test/ui/async-await/issues/issue-72312.stderr
@@ -1,5 +1,5 @@
 error[E0521]: borrowed data escapes outside of associated function
-  --> $DIR/issue-72312.rs:12:9
+  --> $DIR/issue-72312.rs:12:24
    |
 LL |       pub async fn start(&self) {
    |                          -----
@@ -7,16 +7,17 @@ LL |       pub async fn start(&self) {
    |                          `self` is a reference that is only valid in the associated function body
    |                          let's call the lifetime of this reference `'1`
 ...
-LL | /         require_static(async move {
+LL |           require_static(async move {
+   |  ________________________^
 LL | |
 LL | |
 LL | |
 LL | |             &self;
 LL | |         });
-   | |          ^
-   | |          |
-   | |__________`self` escapes the associated function body here
-   |            argument requires that `'1` must outlive `'static`
+   | |         ^
+   | |         |
+   | |_________`self` escapes the associated function body here
+   |           argument requires that `'1` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr
index e6f6e9e9f65..c5bd520aaea 100644
--- a/src/test/ui/async-await/no-const-async.stderr
+++ b/src/test/ui/async-await/no-const-async.stderr
@@ -18,7 +18,7 @@ note: ...which requires borrow-checking `x`...
    |
 LL | pub const async fn x() {}
    | ^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `x`...
+note: ...which requires processing MIR for `x`...
   --> $DIR/no-const-async.rs:4:1
    |
 LL | pub const async fn x() {}
diff --git a/src/test/ui/attr-from-macro.rs b/src/test/ui/attr-from-macro.rs
new file mode 100644
index 00000000000..bb3a5c94d41
--- /dev/null
+++ b/src/test/ui/attr-from-macro.rs
@@ -0,0 +1,20 @@
+// aux-build:attr-from-macro.rs
+// run-pass
+
+extern crate attr_from_macro;
+
+attr_from_macro::creator! {
+    struct Foo;
+    enum Bar;
+    enum FooBar;
+}
+
+fn main() {
+    // Checking the `repr(u32)` on the enum.
+    assert_eq!(4, std::mem::size_of::<Bar>());
+    // Checking the `repr(u16)` on the enum.
+    assert_eq!(2, std::mem::size_of::<FooBar>());
+
+    // Checking the Debug impl on the types.
+    eprintln!("{:?} {:?} {:?}", Foo, Bar::A, FooBar::A);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs b/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs
index e8b4fe7ae52..74fbae0350e 100644
--- a/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs
+++ b/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs
@@ -23,9 +23,11 @@ pub fn assert_sigpipe_handler(expected_handler: SignalHandler) {
             SignalHandler::Ignore => libc::SIG_IGN,
             SignalHandler::Default => libc::SIG_DFL,
         };
-        assert_eq!(prev, expected);
+        assert_eq!(prev, expected, "expected sigpipe value matches actual value");
 
         // Unlikely to matter, but restore the old value anyway
-        unsafe { libc::signal(libc::SIGPIPE, prev); };
+        unsafe {
+            libc::signal(libc::SIGPIPE, prev);
+        };
     }
 }
diff --git a/src/test/ui/auxiliary/attr-from-macro.rs b/src/test/ui/auxiliary/attr-from-macro.rs
new file mode 100644
index 00000000000..9b388675c80
--- /dev/null
+++ b/src/test/ui/auxiliary/attr-from-macro.rs
@@ -0,0 +1,15 @@
+#[macro_export]
+macro_rules! creator {
+    (struct $name1:ident; enum $name2:ident; enum $name3:ident;) => {
+        #[derive(Debug)]
+        pub struct $name1;
+
+        #[derive(Debug)]
+        #[repr(u32)]
+        pub enum $name2 { A }
+
+        #[derive(Debug)]
+        #[repr(u16)]
+        pub enum $name3 { A }
+    }
+}
diff --git a/src/test/ui/binop/issue-77910-1.stderr b/src/test/ui/binop/issue-77910-1.stderr
index 9c7bf6228be..263a35d9829 100644
--- a/src/test/ui/binop/issue-77910-1.stderr
+++ b/src/test/ui/binop/issue-77910-1.stderr
@@ -19,7 +19,7 @@ LL |     assert_eq!(foo, y);
    |     ^^^^^^^^^^^^^^^^^^ `for<'a> fn(&'a i32) -> &'a i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = help: the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}`
-   = help: use parentheses to call the function: `foo(s)`
+   = help: use parentheses to call this function: `foo(/* &i32 */)`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
index 15ac737606d..d2b845619c7 100644
--- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
+++ b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr
@@ -25,7 +25,10 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30
    |
 LL |             _ => { addr.push(&mut x); }
-   |                              ^^^^^^ `x` was mutably borrowed here in the previous iteration of the loop
+   |                    ----------^^^^^^-
+   |                    |         |
+   |                    |         `x` was mutably borrowed here in the previous iteration of the loop
+   |                    first borrow used here, in later iteration of loop
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/borrowck/issue-103250.rs b/src/test/ui/borrowck/issue-103250.rs
new file mode 100644
index 00000000000..46565f61ca9
--- /dev/null
+++ b/src/test/ui/borrowck/issue-103250.rs
@@ -0,0 +1,37 @@
+// edition:2021
+
+type TranslateFn = Box<dyn Fn(String, String) -> String>;
+
+pub struct DeviceCluster {
+    devices: Vec<Device>,
+}
+
+impl DeviceCluster {
+    pub async fn do_something(&mut self) -> Result<String, Box<dyn std::error::Error>> {
+        let mut last_error: Box<dyn std::error::Error>;
+
+        for device in &mut self.devices {
+            match device.do_something().await {
+                Ok(info) => {
+                    return Ok(info);
+                }
+                Err(e) => {}
+            }
+        }
+
+        Err(last_error)
+        //~^ ERROR used binding `last_error` isn't initialized
+    }
+}
+
+pub struct Device {
+    translate_fn: Option<TranslateFn>,
+}
+
+impl Device {
+    pub async fn do_something(&mut self) -> Result<String, Box<dyn std::error::Error>> {
+        Ok(String::from(""))
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/issue-103250.stderr b/src/test/ui/borrowck/issue-103250.stderr
new file mode 100644
index 00000000000..4a237835222
--- /dev/null
+++ b/src/test/ui/borrowck/issue-103250.stderr
@@ -0,0 +1,17 @@
+error[E0381]: used binding `last_error` isn't initialized
+  --> $DIR/issue-103250.rs:22:13
+   |
+LL |         let mut last_error: Box<dyn std::error::Error>;
+   |             -------------- binding declared here but left uninitialized
+...
+LL |         Err(last_error)
+   |             ^^^^^^^^^^ `last_error` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |         let mut last_error: Box<dyn std::error::Error> = todo!();
+   |                                                        +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/issues/issue-23338-params-outlive-temps-of-body.rs b/src/test/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs
index d45aaa843fb..d45aaa843fb 100644
--- a/src/test/ui/issues/issue-23338-params-outlive-temps-of-body.rs
+++ b/src/test/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs
diff --git a/src/test/ui/borrowck/two-phase-across-loop.stderr b/src/test/ui/borrowck/two-phase-across-loop.stderr
index 95896c6bbf9..22f9b39dfee 100644
--- a/src/test/ui/borrowck/two-phase-across-loop.stderr
+++ b/src/test/ui/borrowck/two-phase-across-loop.stderr
@@ -2,7 +2,10 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time
   --> $DIR/two-phase-across-loop.rs:17:22
    |
 LL |         strings.push(foo.get_string());
-   |                      ^^^^^^^^^^^^^^^^ `foo` was mutably borrowed here in the previous iteration of the loop
+   |         -------------^^^^^^^^^^^^^^^^-
+   |         |            |
+   |         |            `foo` was mutably borrowed here in the previous iteration of the loop
+   |         first borrow used here, in later iteration of loop
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr
index 1a40326d986..8ad8273fc2b 100644
--- a/src/test/ui/closures/closure-bounds-subtype.stderr
+++ b/src/test/ui/closures/closure-bounds-subtype.stderr
@@ -11,6 +11,10 @@ note: required by a bound in `take_const_owned`
    |
 LL | fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
    |                                                  ^^^^ required by this bound in `take_const_owned`
+help: use parentheses to call this type parameter
+   |
+LL |     take_const_owned(f());
+   |                       ++
 help: consider further restricting this bound
    |
 LL | fn give_owned<F>(f: F) where F: FnOnce() + Send + std::marker::Sync {
diff --git a/src/test/ui/closures/issue-97607.rs b/src/test/ui/closures/issue-97607.rs
new file mode 100644
index 00000000000..74c910ad0bb
--- /dev/null
+++ b/src/test/ui/closures/issue-97607.rs
@@ -0,0 +1,12 @@
+// check-pass
+#[allow(unused)]
+
+fn test<T, F, U>(f: F) -> Box<dyn Fn(T) -> U + 'static>
+where
+    F: 'static + Fn(T) -> U,
+    for<'a> U: 'a, // < This is the problematic line, see #97607
+{
+    Box::new(move |t| f(t))
+}
+
+fn main() {}
diff --git a/src/test/ui/command/command-current-dir.rs b/src/test/ui/command/command-current-dir.rs
index 69a0b486d68..5d06fcdebc6 100644
--- a/src/test/ui/command/command-current-dir.rs
+++ b/src/test/ui/command/command-current-dir.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-emscripten no processes
 // ignore-sgx no processes
+// ignore-fuchsia Needs directory creation privilege
 
 use std::env;
 use std::fs;
diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
index a15dd2016e9..a7d891d7790 100644
--- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
@@ -1,4 +1,4 @@
-error[E0391]: cycle detected when building an abstract representation for test::{constant#0}
+error[E0391]: cycle detected when building an abstract representation for `test::{constant#0}`
   --> $DIR/closures.rs:3:35
    |
 LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
@@ -14,7 +14,7 @@ note: ...which requires type-checking `test::{constant#0}`...
    |
 LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
    |                                   ^^^^^^^^^^^^^
-   = note: ...which again requires building an abstract representation for test::{constant#0}, completing the cycle
+   = note: ...which again requires building an abstract representation for `test::{constant#0}`, completing the cycle
 note: cycle used when checking that `test` is well-formed
   --> $DIR/closures.rs:3:1
    |
diff --git a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
index 828f0988a03..d674e3acdff 100644
--- a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/dependence_lint.rs:13:32
+  --> $DIR/dependence_lint.rs:14:32
    |
 LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    |                                ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/dependence_lint.rs:20:37
+  --> $DIR/dependence_lint.rs:21:37
    |
 LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
    |                                     ^ cannot perform const operation using `T`
@@ -17,7 +17,7 @@ LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable,
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/dependence_lint.rs:9:9
+  --> $DIR/dependence_lint.rs:10:9
    |
 LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
    |         ^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_
    = note: `#[warn(const_evaluatable_unchecked)]` on by default
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/dependence_lint.rs:16:9
+  --> $DIR/dependence_lint.rs:17:9
    |
 LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
index b13bcdb2c47..74111ef1d38 100644
--- a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
@@ -1,5 +1,5 @@
 error: overly complex generic constant
-  --> $DIR/dependence_lint.rs:16:9
+  --> $DIR/dependence_lint.rs:17:9
    |
 LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
@@ -7,7 +7,7 @@ LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error w
    = help: consider moving this anonymous constant into a `const` function
 
 error: overly complex generic constant
-  --> $DIR/dependence_lint.rs:20:17
+  --> $DIR/dependence_lint.rs:21:17
    |
 LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
@@ -15,7 +15,7 @@ LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable,
    = help: consider moving this anonymous constant into a `const` function
 
 error: unconstrained generic constant
-  --> $DIR/dependence_lint.rs:13:12
+  --> $DIR/dependence_lint.rs:14:12
    |
 LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    = help: try adding a `where` bound using this expression: `where [(); size_of::<*mut T>()]:`
 
 error: unconstrained generic constant
-  --> $DIR/dependence_lint.rs:9:9
+  --> $DIR/dependence_lint.rs:10:9
    |
 LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
    |         ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs
index dcdfd75def9..b715e07f8fa 100644
--- a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs
@@ -1,4 +1,5 @@
 // revisions: full gce
+// compile-flags: -Zdeduplicate-diagnostics=yes
 
 #![cfg_attr(gce, feature(generic_const_exprs))]
 #![allow(incomplete_features)]
diff --git a/src/test/ui/const-generics/generic_const_exprs/function-call.rs b/src/test/ui/const-generics/generic_const_exprs/function-call.rs
index b5de66621c5..3c866333d60 100644
--- a/src/test/ui/const-generics/generic_const_exprs/function-call.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/function-call.rs
@@ -1,4 +1,5 @@
 // check-pass
+// compile-flags: -Zdeduplicate-diagnostics=yes
 
 const fn foo<T>() -> usize {
     // We might instead branch on `std::mem::size_of::<*mut T>() < 8` here,
diff --git a/src/test/ui/const-generics/generic_const_exprs/function-call.stderr b/src/test/ui/const-generics/generic_const_exprs/function-call.stderr
index 796dc01043c..84abfe57876 100644
--- a/src/test/ui/const-generics/generic_const_exprs/function-call.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/function-call.stderr
@@ -1,5 +1,5 @@
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/function-call.rs:14:17
+  --> $DIR/function-call.rs:15:17
    |
 LL |     let _ = [0; foo::<T>()];
    |                 ^^^^^^^^^^
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
index 7840989cb08..8e667aebaad 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.rs
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
@@ -1,3 +1,4 @@
+// compile-flags: -Zdeduplicate-diagnostics=yes
 use std::mem::size_of;
 
 fn test<const N: usize>() {}
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
index 0b051c6131b..deabd05a6d5 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:9:38
+  --> $DIR/complex-expression.rs:10:38
    |
 LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    |                                      ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:12:40
+  --> $DIR/complex-expression.rs:13:40
    |
 LL | struct Break1<const N: usize>([u8; { { N } }]);
    |                                        ^ cannot perform const operation using `N`
@@ -17,7 +17,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]);
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:16:17
+  --> $DIR/complex-expression.rs:17:17
    |
 LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
@@ -26,7 +26,7 @@ LL |     let _: [u8; N + 1];
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:21:17
+  --> $DIR/complex-expression.rs:22:17
    |
 LL |     let _ = [0; N + 1];
    |                 ^ cannot perform const operation using `N`
@@ -35,7 +35,7 @@ LL |     let _ = [0; N + 1];
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:25:45
+  --> $DIR/complex-expression.rs:26:45
    |
 LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
    |                                             ^ cannot perform const operation using `T`
@@ -44,7 +44,7 @@ LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:28:47
+  --> $DIR/complex-expression.rs:29:47
    |
 LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
    |                                               ^ cannot perform const operation using `T`
@@ -53,7 +53,7 @@ LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/complex-expression.rs:32:32
+  --> $DIR/complex-expression.rs:33:32
    |
 LL |     let _: [u8; size_of::<*mut T>() + 1];
    |                                ^ cannot perform const operation using `T`
@@ -62,7 +62,7 @@ LL |     let _: [u8; size_of::<*mut T>() + 1];
    = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/complex-expression.rs:37:17
+  --> $DIR/complex-expression.rs:38:17
    |
 LL |     let _ = [0; size_of::<*mut T>() + 1];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs
index 71d13ca61c9..e9d868093e7 100644
--- a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs
+++ b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs
@@ -1,4 +1,5 @@
 // check-pass
+// compile-flags: -Zdeduplicate-diagnostics=yes
 #![allow(dead_code)]
 
 fn foo<T>() {
diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
index f0ba7a39d1e..8003dfa4071 100644
--- a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
+++ b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr
@@ -1,5 +1,5 @@
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/const-evaluatable-unchecked.rs:5:9
+  --> $DIR/const-evaluatable-unchecked.rs:6:9
    |
 LL |     [0; std::mem::size_of::<*mut T>()];
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     [0; std::mem::size_of::<*mut T>()];
    = note: `#[warn(const_evaluatable_unchecked)]` on by default
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/const-evaluatable-unchecked.rs:16:21
+  --> $DIR/const-evaluatable-unchecked.rs:17:21
    |
 LL |         let _ = [0; Self::ASSOC];
    |                     ^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |         let _ = [0; Self::ASSOC];
    = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/const-evaluatable-unchecked.rs:28:21
+  --> $DIR/const-evaluatable-unchecked.rs:29:21
    |
 LL |         let _ = [0; Self::ASSOC];
    |                     ^^^^^^^^^^^
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
index 168fa0ad0f0..12244450e7f 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
@@ -10,16 +10,6 @@ note: the trait `PartialEq<_>` is implemented for `*const i32`, but that impleme
    |
 LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
    |                                           ^^
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
 
 error[E0277]: can't compare `*const i32` with `_` in const contexts
   --> $DIR/const_raw_ptr_ops.rs:6:44
@@ -33,16 +23,6 @@ note: the trait `PartialEq<_>` is implemented for `*const i32`, but that impleme
    |
 LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
    |                                            ^^
-   = help: the following other types implement trait `PartialEq<Rhs>`:
-             f32
-             f64
-             i128
-             i16
-             i32
-             i64
-             i8
-             isize
-           and 6 others
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/issue-25826.stderr b/src/test/ui/consts/issue-25826.stderr
index b80befa26f6..905c5ee6eb4 100644
--- a/src/test/ui/consts/issue-25826.stderr
+++ b/src/test/ui/consts/issue-25826.stderr
@@ -10,10 +10,6 @@ note: the trait `PartialOrd` is implemented for `*const ()`, but that implementa
    |
 LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
    |                                                    ^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | fn main() where *const (): ~const PartialOrd {
-   |           ++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/issue-94675.stderr b/src/test/ui/consts/issue-94675.stderr
index 7ae293ffbf8..f4683f7f536 100644
--- a/src/test/ui/consts/issue-94675.stderr
+++ b/src/test/ui/consts/issue-94675.stderr
@@ -23,10 +23,6 @@ note: the trait `IndexMut<usize>` is implemented for `Vec<usize>`, but that impl
    |
 LL |         self.bar[0] = baz.len();
    |         ^^^^^^^^^^^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | impl<'a> Foo<'a> where Vec<usize>: ~const IndexMut<usize> {
-   |                  ++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/deriving/deriving-all-codegen.rs b/src/test/ui/deriving/deriving-all-codegen.rs
index aef79ae8a5b..ba7809413bd 100644
--- a/src/test/ui/deriving/deriving-all-codegen.rs
+++ b/src/test/ui/deriving/deriving-all-codegen.rs
@@ -85,7 +85,7 @@ enum Mixed {
     P,
     Q,
     R(u32),
-    S { d1: u32, d2: u32 },
+    S { d1: Option<u32>, d2: Option<i32> },
 }
 
 // An enum with no fieldless variants. Note that `Default` cannot be derived
diff --git a/src/test/ui/deriving/deriving-all-codegen.stdout b/src/test/ui/deriving/deriving-all-codegen.stdout
index 65f7dec8408..92fce6888c0 100644
--- a/src/test/ui/deriving/deriving-all-codegen.stdout
+++ b/src/test/ui/deriving/deriving-all-codegen.stdout
@@ -46,13 +46,15 @@ impl ::core::default::Default for Empty {
 impl ::core::hash::Hash for Empty {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
 }
-impl ::core::marker::StructuralPartialEq for Empty {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Empty { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Empty {
     #[inline]
     fn eq(&self, other: &Empty) -> bool { true }
 }
-impl ::core::marker::StructuralEq for Empty {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Empty { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Empty {
     #[inline]
@@ -115,7 +117,8 @@ impl ::core::hash::Hash for Point {
         ::core::hash::Hash::hash(&self.y, state)
     }
 }
-impl ::core::marker::StructuralPartialEq for Point {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Point { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Point {
     #[inline]
@@ -123,7 +126,8 @@ impl ::core::cmp::PartialEq for Point {
         self.x == other.x && self.y == other.y
     }
 }
-impl ::core::marker::StructuralEq for Point {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Point { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Point {
     #[inline]
@@ -225,7 +229,8 @@ impl ::core::hash::Hash for Big {
         ::core::hash::Hash::hash(&self.b8, state)
     }
 }
-impl ::core::marker::StructuralPartialEq for Big {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Big { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Big {
     #[inline]
@@ -236,7 +241,8 @@ impl ::core::cmp::PartialEq for Big {
             self.b8 == other.b8
     }
 }
-impl ::core::marker::StructuralEq for Big {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Big { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Big {
     #[inline]
@@ -345,13 +351,15 @@ impl ::core::hash::Hash for Unsized {
         ::core::hash::Hash::hash(&self.0, state)
     }
 }
-impl ::core::marker::StructuralPartialEq for Unsized {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Unsized { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Unsized {
     #[inline]
     fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
 }
-impl ::core::marker::StructuralEq for Unsized {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Unsized { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Unsized {
     #[inline]
@@ -410,13 +418,15 @@ impl ::core::hash::Hash for PackedCopy {
         ::core::hash::Hash::hash(&{ self.0 }, state)
     }
 }
-impl ::core::marker::StructuralPartialEq for PackedCopy {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for PackedCopy { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for PackedCopy {
     #[inline]
     fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
 }
-impl ::core::marker::StructuralEq for PackedCopy {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for PackedCopy { }
 #[automatically_derived]
 impl ::core::cmp::Eq for PackedCopy {
     #[inline]
@@ -479,7 +489,8 @@ impl ::core::hash::Hash for PackedNonCopy {
         ::core::hash::Hash::hash(__self_0_0, state)
     }
 }
-impl ::core::marker::StructuralPartialEq for PackedNonCopy {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for PackedNonCopy { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for PackedNonCopy {
     #[inline]
@@ -489,7 +500,8 @@ impl ::core::cmp::PartialEq for PackedNonCopy {
         *__self_0_0 == *__self_1_0
     }
 }
-impl ::core::marker::StructuralEq for PackedNonCopy {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for PackedNonCopy { }
 #[automatically_derived]
 impl ::core::cmp::Eq for PackedNonCopy {
     #[inline]
@@ -540,7 +552,8 @@ impl ::core::hash::Hash for Enum0 {
         unsafe { ::core::intrinsics::unreachable() }
     }
 }
-impl ::core::marker::StructuralPartialEq for Enum0 {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Enum0 { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Enum0 {
     #[inline]
@@ -548,7 +561,8 @@ impl ::core::cmp::PartialEq for Enum0 {
         unsafe { ::core::intrinsics::unreachable() }
     }
 }
-impl ::core::marker::StructuralEq for Enum0 {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Enum0 { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Enum0 {
     #[inline]
@@ -607,7 +621,8 @@ impl ::core::hash::Hash for Enum1 {
         }
     }
 }
-impl ::core::marker::StructuralPartialEq for Enum1 {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Enum1 { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Enum1 {
     #[inline]
@@ -618,7 +633,8 @@ impl ::core::cmp::PartialEq for Enum1 {
         }
     }
 }
-impl ::core::marker::StructuralEq for Enum1 {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Enum1 { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Enum1 {
     #[inline]
@@ -676,13 +692,15 @@ impl ::core::default::Default for Fieldless1 {
 impl ::core::hash::Hash for Fieldless1 {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
 }
-impl ::core::marker::StructuralPartialEq for Fieldless1 {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Fieldless1 { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Fieldless1 {
     #[inline]
     fn eq(&self, other: &Fieldless1) -> bool { true }
 }
-impl ::core::marker::StructuralEq for Fieldless1 {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Fieldless1 { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Fieldless1 {
     #[inline]
@@ -743,7 +761,8 @@ impl ::core::hash::Hash for Fieldless {
         ::core::hash::Hash::hash(&__self_tag, state)
     }
 }
-impl ::core::marker::StructuralPartialEq for Fieldless {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Fieldless { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Fieldless {
     #[inline]
@@ -753,7 +772,8 @@ impl ::core::cmp::PartialEq for Fieldless {
         __self_tag == __arg1_tag
     }
 }
-impl ::core::marker::StructuralEq for Fieldless {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Fieldless { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Fieldless {
     #[inline]
@@ -789,8 +809,8 @@ enum Mixed {
     Q,
     R(u32),
     S {
-        d1: u32,
-        d2: u32,
+        d1: Option<u32>,
+        d2: Option<i32>,
     },
 }
 #[automatically_derived]
@@ -798,6 +818,8 @@ impl ::core::clone::Clone for Mixed {
     #[inline]
     fn clone(&self) -> Mixed {
         let _: ::core::clone::AssertParamIsClone<u32>;
+        let _: ::core::clone::AssertParamIsClone<Option<u32>>;
+        let _: ::core::clone::AssertParamIsClone<Option<i32>>;
         *self
     }
 }
@@ -838,7 +860,8 @@ impl ::core::hash::Hash for Mixed {
         }
     }
 }
-impl ::core::marker::StructuralPartialEq for Mixed {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Mixed { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Mixed {
     #[inline]
@@ -856,7 +879,8 @@ impl ::core::cmp::PartialEq for Mixed {
             }
     }
 }
-impl ::core::marker::StructuralEq for Mixed {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Mixed { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Mixed {
     #[inline]
@@ -864,6 +888,8 @@ impl ::core::cmp::Eq for Mixed {
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
+        let _: ::core::cmp::AssertParamIsEq<Option<u32>>;
+        let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
     }
 }
 #[automatically_derived]
@@ -963,7 +989,8 @@ impl ::core::hash::Hash for Fielded {
         }
     }
 }
-impl ::core::marker::StructuralPartialEq for Fielded {}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for Fielded { }
 #[automatically_derived]
 impl ::core::cmp::PartialEq for Fielded {
     #[inline]
@@ -982,7 +1009,8 @@ impl ::core::cmp::PartialEq for Fielded {
             }
     }
 }
-impl ::core::marker::StructuralEq for Fielded {}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for Fielded { }
 #[automatically_derived]
 impl ::core::cmp::Eq for Fielded {
     #[inline]
diff --git a/src/test/ui/deriving/deriving-hash.rs b/src/test/ui/deriving/deriving-hash.rs
index 8b51370bca5..16738ec4ae4 100644
--- a/src/test/ui/deriving/deriving-hash.rs
+++ b/src/test/ui/deriving/deriving-hash.rs
@@ -44,6 +44,17 @@ fn fake_hash<A: Hash>(v: &mut Vec<u8>, a: A) {
     a.hash(&mut FakeHasher(v));
 }
 
+struct OnlyOneByteHasher;
+impl Hasher for OnlyOneByteHasher {
+    fn finish(&self) -> u64 {
+        unreachable!()
+    }
+
+    fn write(&mut self, bytes: &[u8]) {
+        assert_eq!(bytes.len(), 1);
+    }
+}
+
 fn main() {
     let person1 = Person {
         id: 5,
@@ -73,4 +84,13 @@ fn main() {
     let mut v = vec![];
     fake_hash(&mut v, SingleVariantEnum::A(17));
     assert_eq!(vec![17], v);
+
+    // issue #39137
+    #[repr(u8)]
+    #[derive(Hash)]
+    enum E {
+        A,
+        B,
+    }
+    E::A.hash(&mut OnlyOneByteHasher);
 }
diff --git a/src/test/ui/deriving/issue-103157.rs b/src/test/ui/deriving/issue-103157.rs
new file mode 100644
index 00000000000..52b4c7898d8
--- /dev/null
+++ b/src/test/ui/deriving/issue-103157.rs
@@ -0,0 +1,12 @@
+// check-fail
+
+#[derive(PartialEq, Eq)]
+pub enum Value {
+    Boolean(Option<bool>),
+    Float(Option<f64>), //~ ERROR the trait bound `f64: Eq` is not satisfied
+}
+
+fn main() {
+    let a = Value::Float(Some(f64::NAN));
+    assert!(a == a);
+}
diff --git a/src/test/ui/deriving/issue-103157.stderr b/src/test/ui/deriving/issue-103157.stderr
new file mode 100644
index 00000000000..ee3528fe106
--- /dev/null
+++ b/src/test/ui/deriving/issue-103157.stderr
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `f64: Eq` is not satisfied
+  --> $DIR/issue-103157.rs:6:11
+   |
+LL | #[derive(PartialEq, Eq)]
+   |                     -- in this derive macro expansion
+...
+LL |     Float(Option<f64>),
+   |           ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64`
+   |
+   = help: the following other types implement trait `Eq`:
+             i128
+             i16
+             i32
+             i64
+             i8
+             isize
+             u128
+             u16
+           and 4 others
+   = note: required for `Option<f64>` to implement `Eq`
+note: required by a bound in `AssertParamIsEq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
+   |                               ^^ required by this bound in `AssertParamIsEq`
+   = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/drop/drop_order.rs b/src/test/ui/drop/drop_order.rs
index ba1ac53aa7c..42385216ae7 100644
--- a/src/test/ui/drop/drop_order.rs
+++ b/src/test/ui/drop/drop_order.rs
@@ -129,10 +129,10 @@ impl DropOrderCollector {
         // take the "else" branch
         if self.option_loud_drop(6).is_some() // 2
             && self.option_loud_drop(5).is_some() // 1
-            && let None = self.option_loud_drop(7) { // 3
+            && let None = self.option_loud_drop(8) { // 4
             unreachable!();
         } else {
-            self.print(8); // 4
+            self.print(7); // 3
         }
 
         // let exprs interspersed
diff --git a/src/test/ui/drop/issue-100276.rs b/src/test/ui/drop/issue-100276.rs
new file mode 100644
index 00000000000..6401a8d1481
--- /dev/null
+++ b/src/test/ui/drop/issue-100276.rs
@@ -0,0 +1,12 @@
+// check-pass
+// compile-flags: -Z validate-mir
+#![feature(let_chains)]
+
+fn let_chains(entry: std::io::Result<std::fs::DirEntry>) {
+    if let Ok(entry) = entry
+        && let Some(s) = entry.file_name().to_str()
+        && s.contains("")
+    {}
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-23338-ensure-param-drop-order.rs b/src/test/ui/drop/issue-23338-ensure-param-drop-order.rs
index a99f260dde3..a99f260dde3 100644
--- a/src/test/ui/issues/issue-23338-ensure-param-drop-order.rs
+++ b/src/test/ui/drop/issue-23338-ensure-param-drop-order.rs
diff --git a/src/test/ui/issues/issue-24805-dropck-itemless.rs b/src/test/ui/dropck/issue-24805-dropck-itemless.rs
index 45761b61c3e..45761b61c3e 100644
--- a/src/test/ui/issues/issue-24805-dropck-itemless.rs
+++ b/src/test/ui/dropck/issue-24805-dropck-itemless.rs
diff --git a/src/test/ui/empty_global_asm.rs b/src/test/ui/empty_global_asm.rs
index dbcc7be0578..af13762d118 100644
--- a/src/test/ui/empty_global_asm.rs
+++ b/src/test/ui/empty_global_asm.rs
@@ -1,21 +1,8 @@
+// needs-asm-support
 // run-pass
 
-#[allow(unused_imports)]
 use std::arch::global_asm;
 
-#[cfg(target_arch = "x86")]
-global_asm!("");
-
-#[cfg(target_arch = "x86_64")]
-global_asm!("");
-
-#[cfg(target_arch = "arm")]
-global_asm!("");
-
-#[cfg(target_arch = "aarch64")]
-global_asm!("");
-
-#[cfg(target_arch = "mips")]
 global_asm!("");
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-asm_sym.rs b/src/test/ui/feature-gates/feature-gate-asm_sym.rs
deleted file mode 100644
index 0de6b3abb18..00000000000
--- a/src/test/ui/feature-gates/feature-gate-asm_sym.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// only-x86_64
-
-use std::arch::asm;
-
-fn bar<const N: usize>() {}
-
-fn foo<const N: usize>() {
-    unsafe {
-        asm!("mov eax, {}", sym bar::<N>);
-        //~^ ERROR sym operands for inline assembly are unstable
-    }
-}
-
-fn main() {
-    unsafe {
-        asm!("mov eax, {}", sym foo::<0>);
-        //~^ ERROR sym operands for inline assembly are unstable
-    }
-}
diff --git a/src/test/ui/feature-gates/feature-gate-asm_sym.stderr b/src/test/ui/feature-gates/feature-gate-asm_sym.stderr
deleted file mode 100644
index d4b16f60b0b..00000000000
--- a/src/test/ui/feature-gates/feature-gate-asm_sym.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: sym operands for inline assembly are unstable
-  --> $DIR/feature-gate-asm_sym.rs:9:29
-   |
-LL |         asm!("mov eax, {}", sym bar::<N>);
-   |                             ^^^^^^^^^^^^
-   |
-   = note: see issue #93333 <https://github.com/rust-lang/rust/issues/93333> for more information
-   = help: add `#![feature(asm_sym)]` to the crate attributes to enable
-
-error[E0658]: sym operands for inline assembly are unstable
-  --> $DIR/feature-gate-asm_sym.rs:16:29
-   |
-LL |         asm!("mov eax, {}", sym foo::<0>);
-   |                             ^^^^^^^^^^^^
-   |
-   = note: see issue #93333 <https://github.com/rust-lang/rust/issues/93333> for more information
-   = help: add `#![feature(asm_sym)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
deleted file mode 100644
index 3f72734efa1..00000000000
--- a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0271]: type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
-  --> $DIR/issue-89008.rs:38:43
-   |
-LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
-   |                        ----               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr`
-   |                        |
-   |                        this type parameter
-   |
-note: expected this to be `()`
-  --> $DIR/issue-89008.rs:17:17
-   |
-LL |     type Item = ();
-   |                 ^^
-   = note:   expected unit type `()`
-           found type parameter `Repr`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-91762.rs b/src/test/ui/generic-associated-types/bugs/issue-91762.rs
index 796935cc06f..dec668bec10 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-91762.rs
+++ b/src/test/ui/generic-associated-types/bugs/issue-91762.rs
@@ -1,7 +1,7 @@
 // check-fail
 // known-bug
 
-// We almost certaintly want this to pass, but
+// We almost certainly want this to pass, but
 // it's particularly difficult currently, because we need a way of specifying
 // that `<Self::Base as Functor>::With<T> = Self` without using that when we have
 // a `U`. See `https://github.com/rust-lang/rust/pull/92728` for a (hacky)
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/issue-89008.rs
index 012aa8df2fc..669dbafb5d5 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-89008.rs
+++ b/src/test/ui/generic-associated-types/issue-89008.rs
@@ -1,42 +1,36 @@
-// check-fail
+// check-pass
 // edition:2021
-// known-bug: #88908
-
-// This should pass, but seems to run into a TAIT bug.
 
 #![feature(type_alias_impl_trait)]
 
 use std::future::Future;
+use std::marker::PhantomData;
 
 trait Stream {
     type Item;
 }
 
-struct Empty<T>(T);
-impl<T> Stream for Empty<T> {
-    type Item = ();
+struct Empty<T> {
+    _phantom: PhantomData<T>,
 }
-fn empty<T>() -> Empty<T> {
-    todo!()
+
+impl<T> Stream for Empty<T> {
+    type Item = T;
 }
 
 trait X {
     type LineStream<'a, Repr>: Stream<Item = Repr> where Self: 'a;
-
-    type LineStreamFut<'a,Repr>: Future<Output = Self::LineStream<'a, Repr>> where Self: 'a;
-
-    fn line_stream<'a,Repr>(&'a self) -> Self::LineStreamFut<'a,Repr>;
+    type LineStreamFut<'a, Repr>: Future<Output = Self::LineStream<'a, Repr>> where Self: 'a;
+    fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr>;
 }
 
 struct Y;
 
 impl X for Y {
     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
-
-    type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>> ;
-
+    type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>;
     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
-        async {empty()}
+        async { Empty { _phantom: PhantomData } }
     }
 }
 
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-100689.rs b/src/test/ui/higher-rank-trait-bounds/issue-100689.rs
new file mode 100644
index 00000000000..2db7f8a354c
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-100689.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+struct Foo<'a> {
+    foo: &'a mut usize,
+}
+
+trait Bar<'a> {
+    type FooRef<'b>
+    where
+        'a: 'b;
+    fn uwu(foo: Foo<'a>, f: impl for<'b> FnMut(Self::FooRef<'b>));
+}
+impl<'a> Bar<'a> for () {
+    type FooRef<'b>
+    =
+        &'b Foo<'a>
+    where
+        'a : 'b,
+    ;
+
+    fn uwu(
+        foo: Foo<'a>,
+        mut f: impl for<'b> FnMut(&'b Foo<'a>), //relevant part
+    ) {
+        f(&foo);
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-102899.rs b/src/test/ui/higher-rank-trait-bounds/issue-102899.rs
new file mode 100644
index 00000000000..952b81584f3
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-102899.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+pub trait BufferTrait<'buffer> {
+    type Subset<'channel>
+    where
+        'buffer: 'channel;
+
+    fn for_each_subset<F>(&self, f: F)
+    where
+        F: for<'channel> Fn(Self::Subset<'channel>);
+}
+
+pub struct SomeBuffer<'buffer> {
+    samples: &'buffer [()],
+}
+
+impl<'buffer> BufferTrait<'buffer> for SomeBuffer<'buffer> {
+    type Subset<'subset> = Subset<'subset> where 'buffer: 'subset;
+
+    fn for_each_subset<F>(&self, _f: F)
+    where
+        F: for<'subset> Fn(Subset<'subset>),
+    {
+        todo!()
+    }
+}
+
+pub struct Subset<'subset> {
+    buffer: &'subset [()],
+}
+
+fn main() {}
diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr
index bcfcc28adf7..1f2a96a4c41 100644
--- a/src/test/ui/hygiene/globs.stderr
+++ b/src/test/ui/hygiene/globs.stderr
@@ -1,9 +1,16 @@
 error[E0425]: cannot find function `f` in this scope
   --> $DIR/globs.rs:22:9
    |
+LL |     pub fn g() {}
+   |     ---------- similarly named function `g` defined here
+...
 LL |         f();
-   |         ^ not found in this scope
+   |         ^
+   |
+help: a function with a similar name exists
    |
+LL |         g();
+   |         ~
 help: consider importing this function
    |
 LL | use foo::f;
@@ -12,8 +19,11 @@ LL | use foo::f;
 error[E0425]: cannot find function `g` in this scope
   --> $DIR/globs.rs:15:5
    |
+LL |       pub fn f() {}
+   |       ---------- similarly named function `f` defined here
+...
 LL |       g();
-   |       ^ not found in this scope
+   |       ^
 ...
 LL | /     m! {
 LL | |         use bar::*;
@@ -23,6 +33,10 @@ LL | |     }
    | |_____- in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: a function with a similar name exists
+   |
+LL |     f();
+   |     ~
 help: consider importing this function
    |
 LL | use bar::g;
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index 17d05dd0963..1d2a1e12498 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -19,14 +19,8 @@ LL |     semitransparent;
 error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
    |
-LL |     struct Opaque;
-   |     -------------- similarly named unit struct `Opaque` defined here
-...
 LL |     opaque;
-   |     ^^^^^^
-   |     |
-   |     not a value
-   |     help: a unit struct with a similar name exists (notice the capitalization): `Opaque`
+   |     ^^^^^^ not a value
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr
index b6e28364768..feedfc40aaf 100644
--- a/src/test/ui/impl-trait/auto-trait-leak.stderr
+++ b/src/test/ui/impl-trait/auto-trait-leak.stderr
@@ -9,12 +9,12 @@ note: ...which requires borrow-checking `cycle1`...
    |
 LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `cycle1`...
+note: ...which requires processing MIR for `cycle1`...
   --> $DIR/auto-trait-leak.rs:12:1
    |
 LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `cycle1`...
+note: ...which requires preparing `cycle1` for borrow checking...
   --> $DIR/auto-trait-leak.rs:12:1
    |
 LL | fn cycle1() -> impl Clone {
@@ -50,12 +50,12 @@ note: ...which requires borrow-checking `cycle2`...
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `cycle2`...
+note: ...which requires processing MIR for `cycle2`...
   --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `cycle2`...
+note: ...which requires preparing `cycle2` for borrow checking...
   --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr
index efc228de58b..de06ded7acd 100644
--- a/src/test/ui/impl-trait/hidden-lifetimes.stderr
+++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
   --> $DIR/hidden-lifetimes.rs:29:5
    |
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
@@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
    |                                                                     ++++
 
-error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
   --> $DIR/hidden-lifetimes.rs:46:5
    |
 LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
diff --git a/src/test/ui/impl-trait/in-trait/default-body-type-err-2.rs b/src/test/ui/impl-trait/in-trait/default-body-type-err-2.rs
new file mode 100644
index 00000000000..45ae2b8ad3a
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/default-body-type-err-2.rs
@@ -0,0 +1,13 @@
+// edition:2021
+
+#![allow(incomplete_features)]
+#![feature(async_fn_in_trait)]
+
+pub trait Foo {
+    async fn woopsie_async(&self) -> String {
+        42
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/src/test/ui/impl-trait/in-trait/default-body-type-err-2.stderr
new file mode 100644
index 00000000000..142b1bff1a4
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/default-body-type-err-2.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/default-body-type-err-2.rs:8:9
+   |
+LL |         42
+   |         ^^- help: try using a conversion method: `.to_string()`
+   |         |
+   |         expected struct `String`, found integer
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/in-trait/default-body-type-err.rs b/src/test/ui/impl-trait/in-trait/default-body-type-err.rs
new file mode 100644
index 00000000000..ac9baf91cae
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/default-body-type-err.rs
@@ -0,0 +1,13 @@
+#![allow(incomplete_features)]
+#![feature(return_position_impl_trait_in_trait)]
+
+use std::ops::Deref;
+
+pub trait Foo {
+    fn lol(&self) -> impl Deref<Target = String> {
+        //~^ type mismatch resolving `<&i32 as Deref>::Target == String`
+        &1i32
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/default-body-type-err.stderr b/src/test/ui/impl-trait/in-trait/default-body-type-err.stderr
new file mode 100644
index 00000000000..461247a3e3f
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/default-body-type-err.stderr
@@ -0,0 +1,12 @@
+error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String`
+  --> $DIR/default-body-type-err.rs:7:22
+   |
+LL |     fn lol(&self) -> impl Deref<Target = String> {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `String`
+LL |
+LL |         &1i32
+   |         ----- return type was inferred to be `&i32` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/impl-trait/in-trait/default-body-with-rpit.rs b/src/test/ui/impl-trait/in-trait/default-body-with-rpit.rs
index f0d407cd527..ad3cc7c2524 100644
--- a/src/test/ui/impl-trait/in-trait/default-body-with-rpit.rs
+++ b/src/test/ui/impl-trait/in-trait/default-body-with-rpit.rs
@@ -1,4 +1,4 @@
-// known-bug: #102688
+// check-pass
 // edition:2021
 
 #![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
diff --git a/src/test/ui/impl-trait/in-trait/default-body-with-rpit.stderr b/src/test/ui/impl-trait/in-trait/default-body-with-rpit.stderr
deleted file mode 100644
index 4529d301f9e..00000000000
--- a/src/test/ui/impl-trait/in-trait/default-body-with-rpit.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0720]: cannot resolve opaque type
-  --> $DIR/default-body-with-rpit.rs:10:28
-   |
-LL |     async fn baz(&self) -> impl Debug {
-   |                            ^^^^^^^^^^ cannot resolve opaque type
-   |
-   = note: these returned values have a concrete "never" type
-   = help: this error will resolve once the item's body returns a concrete type
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/in-trait/issue-102301.rs b/src/test/ui/impl-trait/in-trait/issue-102301.rs
new file mode 100644
index 00000000000..a93714a658e
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/issue-102301.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo<T> {
+    fn foo<F2: Foo<T>>(self) -> impl Foo<T>;
+}
+
+struct Bar;
+
+impl Foo<u8> for Bar {
+    fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103181-1.rs b/src/test/ui/impl-trait/issue-103181-1.rs
new file mode 100644
index 00000000000..197aedf9d98
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-1.rs
@@ -0,0 +1,85 @@
+// edition:2021
+
+mod hyper {
+    use std::{fmt::Debug, future::Future, marker::PhantomData, pin::Pin, task::Poll};
+
+    pub trait HttpBody {
+        type Error;
+    }
+    impl HttpBody for () {
+        //~^ ERROR not all trait items implemented, missing: `Error`
+        // don't implement `Error` here for the ICE
+    }
+
+    pub struct Server<I, S>(I, S);
+
+    pub fn serve<I, S>(_: S) -> Server<I, S> {
+        todo!()
+    }
+
+    impl<S, B> Future for Server<(), S>
+    where
+        S: MakeServiceRef<(), (), ResBody = B>,
+        B: HttpBody,
+        B::Error: Debug,
+    {
+        type Output = ();
+
+        fn poll(self: Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+            todo!()
+        }
+    }
+
+    pub trait MakeServiceRef<Target, ReqBody> {
+        type ResBody;
+    }
+
+    impl<T, S> MakeServiceRef<(), ()> for T
+    where
+        T: for<'a> Service<&'a (), Response = S>,
+        S: Service<()>,
+    {
+        type ResBody = ();
+    }
+
+    pub struct MakeServiceFn<F>(pub F);
+    pub struct ServiceFn<F, R>(pub PhantomData<(F, R)>);
+
+    pub trait Service<Request> {
+        type Response;
+    }
+
+    impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F>
+    where
+        F: Fn() -> Ret,
+        Ret: Future<Output = Result<Svc, ()>>,
+    {
+        type Response = Svc;
+    }
+
+    impl<F, ReqBody, Ret, ResBody, E> Service<ReqBody> for ServiceFn<F, ReqBody>
+    where
+        F: Fn() -> Ret,
+        Ret: Future<Output = Result<ResBody, E>>,
+    {
+        type Response = ResBody;
+    }
+}
+
+async fn smarvice() -> Result<(), ()> {
+    Ok(())
+}
+
+fn service_fn<F, R, S>(f: F) -> hyper::ServiceFn<F, R>
+where
+    F: Fn() -> S,
+{
+    hyper::ServiceFn(std::marker::PhantomData)
+}
+
+async fn iceice() {
+    let service = hyper::MakeServiceFn(|| async { Ok::<_, ()>(service_fn(|| smarvice())) });
+    hyper::serve::<(), _>(service).await;
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103181-1.stderr b/src/test/ui/impl-trait/issue-103181-1.stderr
new file mode 100644
index 00000000000..cd026607d52
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-1.stderr
@@ -0,0 +1,12 @@
+error[E0046]: not all trait items implemented, missing: `Error`
+  --> $DIR/issue-103181-1.rs:9:5
+   |
+LL |         type Error;
+   |         ---------- `Error` from trait
+LL |     }
+LL |     impl HttpBody for () {
+   |     ^^^^^^^^^^^^^^^^^^^^ missing `Error` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/impl-trait/issue-103181-2.rs b/src/test/ui/impl-trait/issue-103181-2.rs
new file mode 100644
index 00000000000..b43ac45075e
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-2.rs
@@ -0,0 +1,29 @@
+// edition:2021
+
+trait SendFuture: Send {
+    type Output;
+}
+
+impl<Fut: Send> SendFuture for Fut {
+    type Output = ();
+}
+
+async fn broken_fut() {
+    ident_error;
+    //~^ ERROR cannot find value `ident_error` in this scope
+}
+
+// triggers normalization of `<Fut as SendFuture>::Output`,
+// which requires `Fut: Send`.
+fn normalize<Fut: SendFuture>(_: Fut, _: Fut::Output) {}
+
+async fn iceice<A, B>()
+// <- async fn is necessary
+where
+    A: Send,
+    B: Send, // <- a second bound
+{
+    normalize(broken_fut(), ());
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103181-2.stderr b/src/test/ui/impl-trait/issue-103181-2.stderr
new file mode 100644
index 00000000000..5eb2dd9184b
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103181-2.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `ident_error` in this scope
+  --> $DIR/issue-103181-2.rs:12:5
+   |
+LL |     ident_error;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/impl-trait/issue-86465.rs b/src/test/ui/impl-trait/issue-86465.rs
index a79bb6474d8..8c7b41d73b7 100644
--- a/src/test/ui/impl-trait/issue-86465.rs
+++ b/src/test/ui/impl-trait/issue-86465.rs
@@ -1,6 +1,10 @@
 #![feature(type_alias_impl_trait)]
 
-type X<'a, 'b> = impl std::fmt::Debug;
+pub trait Captures<'a> {}
+
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+type X<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
 
 fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
     (a, a)
diff --git a/src/test/ui/impl-trait/issue-86465.stderr b/src/test/ui/impl-trait/issue-86465.stderr
index 90d6904ed61..b949b2b4245 100644
--- a/src/test/ui/impl-trait/issue-86465.stderr
+++ b/src/test/ui/impl-trait/issue-86465.stderr
@@ -1,5 +1,5 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/issue-86465.rs:6:5
+  --> $DIR/issue-86465.rs:10:5
    |
 LL |     (a, a)
    |     ^^^^^^
diff --git a/src/test/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs b/src/test/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs
new file mode 100644
index 00000000000..287a030cf87
--- /dev/null
+++ b/src/test/ui/impl-trait/nested-rpit-with-anonymous-lifetimes.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+pub struct VecNumber<'s> {
+    pub vec_number: Vec<Number<'s>>,
+    pub auxiliary_object: &'s Vec<usize>,
+}
+
+pub struct Number<'s> {
+    pub number: &'s usize,
+}
+
+impl<'s> VecNumber<'s> {
+    pub fn vec_number_iterable_per_item_in_auxiliary_object(
+        &self,
+    ) -> impl Iterator<Item = (&'s usize, impl Iterator<Item = &Number<'s>>)> {
+        self.auxiliary_object.iter().map(move |n| {
+            let iter_number = self.vec_number.iter();
+            (n, iter_number)
+        })
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed
index e401492a830..bab1854dc51 100644
--- a/src/test/ui/inference/char-as-str-single.fixed
+++ b/src/test/ui/inference/char-as-str-single.fixed
@@ -8,4 +8,5 @@
 fn main() {
     let _: char = 'a'; //~ ERROR mismatched types
     let _: char = '人'; //~ ERROR mismatched types
+    let _: char = '\''; //~ ERROR mismatched types
 }
diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs
index 4f23cea5354..736920643b2 100644
--- a/src/test/ui/inference/char-as-str-single.rs
+++ b/src/test/ui/inference/char-as-str-single.rs
@@ -8,4 +8,5 @@
 fn main() {
     let _: char = "a"; //~ ERROR mismatched types
     let _: char = "人"; //~ ERROR mismatched types
+    let _: char = "'"; //~ ERROR mismatched types
 }
diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr
index 29075c15414..3375ec6ac32 100644
--- a/src/test/ui/inference/char-as-str-single.stderr
+++ b/src/test/ui/inference/char-as-str-single.stderr
@@ -24,6 +24,19 @@ help: if you meant to write a `char` literal, use single quotes
 LL |     let _: char = '人';
    |                   ~~~~
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:11:19
+   |
+LL |     let _: char = "'";
+   |            ----   ^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |     let _: char = '\'';
+   |                   ~~~~
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-36053.rs b/src/test/ui/inference/issue-36053.rs
index 5c6d0780416..5c6d0780416 100644
--- a/src/test/ui/issues/issue-36053.rs
+++ b/src/test/ui/inference/issue-36053.rs
diff --git a/src/test/ui/inference/need_type_info/issue-103053.rs b/src/test/ui/inference/need_type_info/issue-103053.rs
new file mode 100644
index 00000000000..05169666f83
--- /dev/null
+++ b/src/test/ui/inference/need_type_info/issue-103053.rs
@@ -0,0 +1,18 @@
+trait TypeMapper {
+    type MapType;
+}
+
+type Mapped<T> = <T as TypeMapper>::MapType;
+
+struct Test {}
+
+impl TypeMapper for () {
+    type MapType = Test;
+}
+
+fn test() {
+    Mapped::<()> {};
+    None; //~ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/src/test/ui/inference/need_type_info/issue-103053.stderr b/src/test/ui/inference/need_type_info/issue-103053.stderr
new file mode 100644
index 00000000000..84f0475d8cd
--- /dev/null
+++ b/src/test/ui/inference/need_type_info/issue-103053.stderr
@@ -0,0 +1,14 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-103053.rs:15:5
+   |
+LL |     None;
+   |     ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+   |
+help: consider specifying the generic argument
+   |
+LL |     None::<T>;
+   |         +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed
index 09f3dec5a17..6aea809cbdb 100644
--- a/src/test/ui/inference/str-as-char.fixed
+++ b/src/test/ui/inference/str-as-char.fixed
@@ -4,5 +4,7 @@
 // run-rustfix
 
 fn main() {
-    let _: &str = "a"; //~ ERROR mismatched types
+    let _: &str = "a";   //~ ERROR mismatched types
+    let _: &str = "\"\"\""; //~ ERROR character literal may only contain one codepoint
+    let _: &str = "\"\"\""; //~ ERROR character literal may only contain one codepoint
 }
diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs
index 7092a612442..eaa8d788c34 100644
--- a/src/test/ui/inference/str-as-char.rs
+++ b/src/test/ui/inference/str-as-char.rs
@@ -4,5 +4,7 @@
 // run-rustfix
 
 fn main() {
-    let _: &str = 'a'; //~ ERROR mismatched types
+    let _: &str = 'a';   //~ ERROR mismatched types
+    let _: &str = '"""'; //~ ERROR character literal may only contain one codepoint
+    let _: &str = '\"\"\"'; //~ ERROR character literal may only contain one codepoint
 }
diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr
index ebbe7c80f77..2c84dac8e0c 100644
--- a/src/test/ui/inference/str-as-char.stderr
+++ b/src/test/ui/inference/str-as-char.stderr
@@ -1,3 +1,25 @@
+error: character literal may only contain one codepoint
+  --> $DIR/str-as-char.rs:8:19
+   |
+LL |     let _: &str = '"""';
+   |                   ^^^^^
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let _: &str = "\"\"\"";
+   |                   ~~~~~~~~
+
+error: character literal may only contain one codepoint
+  --> $DIR/str-as-char.rs:9:19
+   |
+LL |     let _: &str = '\"\"\"';
+   |                   ^^^^^^^^
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let _: &str = "\"\"\"";
+   |                   ~~~~~~~~
+
 error[E0308]: mismatched types
   --> $DIR/str-as-char.rs:7:19
    |
@@ -11,6 +33,6 @@ help: if you meant to write a `str` literal, use double quotes
 LL |     let _: &str = "a";
    |                   ~~~
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-30490.rs b/src/test/ui/issues/issue-30490.rs
index 47c17e362ae..68d9c4de4d1 100644
--- a/src/test/ui/issues/issue-30490.rs
+++ b/src/test/ui/issues/issue-30490.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-emscripten no processes
 // ignore-sgx no processes
+// ignore-fuchsia Child I/O swaps not privileged
 
 // Previously libstd would set stdio descriptors of a child process
 // by `dup`ing the requested descriptors to inherit directly into the
diff --git a/src/test/ui/issues/issue-35241.stderr b/src/test/ui/issues/issue-35241.stderr
index 9ee7654a088..42a78ed97e0 100644
--- a/src/test/ui/issues/issue-35241.stderr
+++ b/src/test/ui/issues/issue-35241.stderr
@@ -11,7 +11,7 @@ LL | fn test() -> Foo { Foo }
    |
    = note: expected struct `Foo`
              found fn item `fn(u32) -> Foo {Foo}`
-help: use parentheses to instantiate this tuple struct
+help: use parentheses to construct this tuple struct
    |
 LL | fn test() -> Foo { Foo(/* u32 */) }
    |                       +++++++++++
diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr
index 08fe0b35eb7..f9846b62a72 100644
--- a/src/test/ui/issues/issue-59488.stderr
+++ b/src/test/ui/issues/issue-59488.stderr
@@ -99,7 +99,7 @@ LL |     assert_eq!(Foo::Bar, i);
              extern "C" fn(A, B, C, D) -> Ret
              extern "C" fn(A, B, C, D, ...) -> Ret
              extern "C" fn(A, B, C, D, E) -> Ret
-           and 68 others
+           and 118 others
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug`
@@ -118,7 +118,7 @@ LL |     assert_eq!(Foo::Bar, i);
              extern "C" fn(A, B, C, D) -> Ret
              extern "C" fn(A, B, C, D, ...) -> Ret
              extern "C" fn(A, B, C, D, E) -> Ret
-           and 68 others
+           and 118 others
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 10 previous errors
diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr
index 2c3ec1a331f..520efccae51 100644
--- a/src/test/ui/issues/issue-6458-3.stderr
+++ b/src/test/ui/issues/issue-6458-3.stderr
@@ -2,12 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-3.rs:4:5
    |
 LL |     mem::transmute(0);
-   |     ^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `transmute`
+   |     ^^^^^^^^^^^^^^ cannot infer type of the type parameter `Dst` declared on the function `transmute`
    |
 help: consider specifying the generic arguments
    |
-LL |     mem::transmute::<i32, U>(0);
-   |                   ++++++++++
+LL |     mem::transmute::<i32, Dst>(0);
+   |                   ++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
index 7f29709ce50..b30bcfb776c 100644
--- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
+++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
@@ -29,7 +29,7 @@ LL |     assert_eq!(a, 0);
    |     ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = help: the trait `Debug` is not implemented for fn item `fn() -> i32 {a}`
-   = help: use parentheses to call the function: `a()`
+   = help: use parentheses to call this function: `a()`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/let-else/let-else-non-diverging.rs b/src/test/ui/let-else/let-else-non-diverging.rs
index 58d2c09776f..a5442dd82f0 100644
--- a/src/test/ui/let-else/let-else-non-diverging.rs
+++ b/src/test/ui/let-else/let-else-non-diverging.rs
@@ -11,7 +11,7 @@ fn main() {
 
     // Ensure that uninhabited types do not "diverge".
     // This might be relaxed in the future, but when it is,
-    // it should be an explicitly wanted descision.
+    // it should be an explicitly wanted decision.
     let Some(x) = Some(1) else { foo::<Uninhabited>() }; //~ ERROR does not diverge
 }
 
diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr
index 08e4be2c0c3..53598545223 100644
--- a/src/test/ui/lexical-scopes.stderr
+++ b/src/test/ui/lexical-scopes.stderr
@@ -1,6 +1,8 @@
 error[E0574]: expected struct, variant or union type, found type parameter `T`
   --> $DIR/lexical-scopes.rs:3:13
    |
+LL | struct T { i: i32 }
+   | ------------------- you might have meant to refer to this struct
 LL | fn f<T>() {
    |      - found this type parameter
 LL |     let t = T { i: 0 };
diff --git a/src/test/ui/lifetimes/elided-lifetime-in-param-pat.rs b/src/test/ui/lifetimes/elided-lifetime-in-param-pat.rs
new file mode 100644
index 00000000000..c1425fa4243
--- /dev/null
+++ b/src/test/ui/lifetimes/elided-lifetime-in-param-pat.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+struct S<T> {
+    _t: T,
+}
+
+fn f(S::<&i8> { .. }: S<&i8>) {}
+
+fn main() {
+    f(S { _t: &42_i8 });
+}
diff --git a/src/test/ui/lint/invalid_value.rs b/src/test/ui/lint/invalid_value.rs
index 946a0e38861..57d8cbe7c93 100644
--- a/src/test/ui/lint/invalid_value.rs
+++ b/src/test/ui/lint/invalid_value.rs
@@ -44,6 +44,10 @@ enum TwoUninhabited {
     B(Void),
 }
 
+#[rustc_layout_scalar_valid_range_start(254)]
+#[rustc_layout_scalar_valid_range_end(1)]
+pub(crate) struct WrapAroundRange(u8);
+
 #[allow(unused)]
 fn generic<T: 'static>() {
     unsafe {
@@ -131,6 +135,9 @@ fn main() {
         let _val: *const [()] = mem::zeroed();
         let _val: *const [()] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: WrapAroundRange = mem::zeroed();
+        let _val: WrapAroundRange = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Things where 0 is okay due to rustc implementation details,
         // but that are not guaranteed to keep working.
         let _val: Result<i32, i32> = mem::zeroed();
diff --git a/src/test/ui/lint/invalid_value.stderr b/src/test/ui/lint/invalid_value.stderr
index 3901692001a..76afb765f0f 100644
--- a/src/test/ui/lint/invalid_value.stderr
+++ b/src/test/ui/lint/invalid_value.stderr
@@ -1,5 +1,5 @@
 error: the type `&T` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:50:32
+  --> $DIR/invalid_value.rs:54:32
    |
 LL |         let _val: &'static T = mem::zeroed();
    |                                ^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | #![deny(invalid_value)]
    |         ^^^^^^^^^^^^^
 
 error: the type `&T` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:51:32
+  --> $DIR/invalid_value.rs:55:32
    |
 LL |         let _val: &'static T = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |         let _val: &'static T = mem::uninitialized();
    = note: references must be non-null
 
 error: the type `Wrap<&T>` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:53:38
+  --> $DIR/invalid_value.rs:57:38
    |
 LL |         let _val: Wrap<&'static T> = mem::zeroed();
    |                                      ^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `Wrap<&T>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:54:38
+  --> $DIR/invalid_value.rs:58:38
    |
 LL |         let _val: Wrap<&'static T> = mem::uninitialized();
    |                                      ^^^^^^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `!` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:61:23
+  --> $DIR/invalid_value.rs:65:23
    |
 LL |         let _val: ! = mem::zeroed();
    |                       ^^^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL |         let _val: ! = mem::zeroed();
    = note: the `!` type has no valid value
 
 error: the type `!` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:62:23
+  --> $DIR/invalid_value.rs:66:23
    |
 LL |         let _val: ! = mem::uninitialized();
    |                       ^^^^^^^^^^^^^^^^^^^^
@@ -78,7 +78,7 @@ LL |         let _val: ! = mem::uninitialized();
    = note: the `!` type has no valid value
 
 error: the type `(i32, !)` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:64:30
+  --> $DIR/invalid_value.rs:68:30
    |
 LL |         let _val: (i32, !) = mem::zeroed();
    |                              ^^^^^^^^^^^^^
@@ -89,7 +89,7 @@ LL |         let _val: (i32, !) = mem::zeroed();
    = note: the `!` type has no valid value
 
 error: the type `(i32, !)` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:65:30
+  --> $DIR/invalid_value.rs:69:30
    |
 LL |         let _val: (i32, !) = mem::uninitialized();
    |                              ^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |         let _val: (i32, !) = mem::uninitialized();
    = note: integers must not be uninitialized
 
 error: the type `Void` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:67:26
+  --> $DIR/invalid_value.rs:71:26
    |
 LL |         let _val: Void = mem::zeroed();
    |                          ^^^^^^^^^^^^^
@@ -115,7 +115,7 @@ LL | enum Void {}
    | ^^^^^^^^^
 
 error: the type `Void` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:68:26
+  --> $DIR/invalid_value.rs:72:26
    |
 LL |         let _val: Void = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -130,7 +130,7 @@ LL | enum Void {}
    | ^^^^^^^^^
 
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:70:34
+  --> $DIR/invalid_value.rs:74:34
    |
 LL |         let _val: &'static i32 = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
@@ -141,7 +141,7 @@ LL |         let _val: &'static i32 = mem::zeroed();
    = note: references must be non-null
 
 error: the type `&i32` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:71:34
+  --> $DIR/invalid_value.rs:75:34
    |
 LL |         let _val: &'static i32 = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -152,7 +152,7 @@ LL |         let _val: &'static i32 = mem::uninitialized();
    = note: references must be non-null
 
 error: the type `Ref` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:73:25
+  --> $DIR/invalid_value.rs:77:25
    |
 LL |         let _val: Ref = mem::zeroed();
    |                         ^^^^^^^^^^^^^
@@ -167,7 +167,7 @@ LL | struct Ref(&'static i32);
    |            ^^^^^^^^^^^^
 
 error: the type `Ref` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:74:25
+  --> $DIR/invalid_value.rs:78:25
    |
 LL |         let _val: Ref = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -182,7 +182,7 @@ LL | struct Ref(&'static i32);
    |            ^^^^^^^^^^^^
 
 error: the type `fn()` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:76:26
+  --> $DIR/invalid_value.rs:80:26
    |
 LL |         let _val: fn() = mem::zeroed();
    |                          ^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL |         let _val: fn() = mem::zeroed();
    = note: function pointers must be non-null
 
 error: the type `fn()` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:77:26
+  --> $DIR/invalid_value.rs:81:26
    |
 LL |         let _val: fn() = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -204,7 +204,7 @@ LL |         let _val: fn() = mem::uninitialized();
    = note: function pointers must be non-null
 
 error: the type `Wrap<fn()>` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:79:32
+  --> $DIR/invalid_value.rs:83:32
    |
 LL |         let _val: Wrap<fn()> = mem::zeroed();
    |                                ^^^^^^^^^^^^^
@@ -219,7 +219,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `Wrap<fn()>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:80:32
+  --> $DIR/invalid_value.rs:84:32
    |
 LL |         let _val: Wrap<fn()> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +234,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `WrapEnum<fn()>` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:82:36
+  --> $DIR/invalid_value.rs:86:36
    |
 LL |         let _val: WrapEnum<fn()> = mem::zeroed();
    |                                    ^^^^^^^^^^^^^
@@ -249,7 +249,7 @@ LL | enum WrapEnum<T> { Wrapped(T) }
    |                            ^
 
 error: the type `WrapEnum<fn()>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:83:36
+  --> $DIR/invalid_value.rs:87:36
    |
 LL |         let _val: WrapEnum<fn()> = mem::uninitialized();
    |                                    ^^^^^^^^^^^^^^^^^^^^
@@ -264,7 +264,7 @@ LL | enum WrapEnum<T> { Wrapped(T) }
    |                            ^
 
 error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:85:42
+  --> $DIR/invalid_value.rs:89:42
    |
 LL |         let _val: Wrap<(RefPair, i32)> = mem::zeroed();
    |                                          ^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL | struct RefPair((&'static i32, i32));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:86:42
+  --> $DIR/invalid_value.rs:90:42
    |
 LL |         let _val: Wrap<(RefPair, i32)> = mem::uninitialized();
    |                                          ^^^^^^^^^^^^^^^^^^^^
@@ -294,7 +294,7 @@ LL | struct RefPair((&'static i32, i32));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: the type `NonNull<i32>` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:88:34
+  --> $DIR/invalid_value.rs:92:34
    |
 LL |         let _val: NonNull<i32> = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
@@ -305,7 +305,7 @@ LL |         let _val: NonNull<i32> = mem::zeroed();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:89:34
+  --> $DIR/invalid_value.rs:93:34
    |
 LL |         let _val: NonNull<i32> = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -316,7 +316,7 @@ LL |         let _val: NonNull<i32> = mem::uninitialized();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `(NonZeroU32, i32)` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:91:39
+  --> $DIR/invalid_value.rs:95:39
    |
 LL |         let _val: (NonZeroU32, i32) = mem::zeroed();
    |                                       ^^^^^^^^^^^^^
@@ -327,7 +327,7 @@ LL |         let _val: (NonZeroU32, i32) = mem::zeroed();
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `(NonZeroU32, i32)` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:92:39
+  --> $DIR/invalid_value.rs:96:39
    |
 LL |         let _val: (NonZeroU32, i32) = mem::uninitialized();
    |                                       ^^^^^^^^^^^^^^^^^^^^
@@ -338,7 +338,7 @@ LL |         let _val: (NonZeroU32, i32) = mem::uninitialized();
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `*const dyn Send` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:94:37
+  --> $DIR/invalid_value.rs:98:37
    |
 LL |         let _val: *const dyn Send = mem::zeroed();
    |                                     ^^^^^^^^^^^^^
@@ -349,7 +349,7 @@ LL |         let _val: *const dyn Send = mem::zeroed();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `*const dyn Send` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:95:37
+  --> $DIR/invalid_value.rs:99:37
    |
 LL |         let _val: *const dyn Send = mem::uninitialized();
    |                                     ^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +360,7 @@ LL |         let _val: *const dyn Send = mem::uninitialized();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `[fn(); 2]` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:97:31
+  --> $DIR/invalid_value.rs:101:31
    |
 LL |         let _val: [fn(); 2] = mem::zeroed();
    |                               ^^^^^^^^^^^^^
@@ -371,7 +371,7 @@ LL |         let _val: [fn(); 2] = mem::zeroed();
    = note: function pointers must be non-null
 
 error: the type `[fn(); 2]` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:98:31
+  --> $DIR/invalid_value.rs:102:31
    |
 LL |         let _val: [fn(); 2] = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -382,7 +382,7 @@ LL |         let _val: [fn(); 2] = mem::uninitialized();
    = note: function pointers must be non-null
 
 error: the type `TwoUninhabited` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:100:36
+  --> $DIR/invalid_value.rs:104:36
    |
 LL |         let _val: TwoUninhabited = mem::zeroed();
    |                                    ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@ LL | enum TwoUninhabited {
    | ^^^^^^^^^^^^^^^^^^^
 
 error: the type `TwoUninhabited` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:101:36
+  --> $DIR/invalid_value.rs:105:36
    |
 LL |         let _val: TwoUninhabited = mem::uninitialized();
    |                                    ^^^^^^^^^^^^^^^^^^^^
@@ -412,7 +412,7 @@ LL | enum TwoUninhabited {
    | ^^^^^^^^^^^^^^^^^^^
 
 error: the type `OneFruitNonZero` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:103:37
+  --> $DIR/invalid_value.rs:107:37
    |
 LL |         let _val: OneFruitNonZero = mem::zeroed();
    |                                     ^^^^^^^^^^^^^
@@ -427,7 +427,7 @@ LL |     Banana(NonZeroU32),
    |            ^^^^^^^^^^
 
 error: the type `OneFruitNonZero` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:104:37
+  --> $DIR/invalid_value.rs:108:37
    |
 LL |         let _val: OneFruitNonZero = mem::uninitialized();
    |                                     ^^^^^^^^^^^^^^^^^^^^
@@ -442,7 +442,7 @@ LL |     Banana(NonZeroU32),
    |            ^^^^^^^^^^
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:108:26
+  --> $DIR/invalid_value.rs:112:26
    |
 LL |         let _val: bool = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -453,7 +453,7 @@ LL |         let _val: bool = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `Wrap<char>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:111:32
+  --> $DIR/invalid_value.rs:115:32
    |
 LL |         let _val: Wrap<char> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -468,7 +468,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `NonBig` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:114:28
+  --> $DIR/invalid_value.rs:118:28
    |
 LL |         let _val: NonBig = mem::uninitialized();
    |                            ^^^^^^^^^^^^^^^^^^^^
@@ -479,7 +479,7 @@ LL |         let _val: NonBig = mem::uninitialized();
    = note: `NonBig` must be initialized inside its custom valid range
 
 error: the type `Fruit` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:117:27
+  --> $DIR/invalid_value.rs:121:27
    |
 LL |         let _val: Fruit = mem::uninitialized();
    |                           ^^^^^^^^^^^^^^^^^^^^
@@ -494,7 +494,7 @@ LL | enum Fruit {
    | ^^^^^^^^^^
 
 error: the type `[bool; 2]` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:120:31
+  --> $DIR/invalid_value.rs:124:31
    |
 LL |         let _val: [bool; 2] = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -505,7 +505,7 @@ LL |         let _val: [bool; 2] = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `i32` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:123:25
+  --> $DIR/invalid_value.rs:127:25
    |
 LL |         let _val: i32 = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -516,7 +516,7 @@ LL |         let _val: i32 = mem::uninitialized();
    = note: integers must not be uninitialized
 
 error: the type `f32` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:126:25
+  --> $DIR/invalid_value.rs:130:25
    |
 LL |         let _val: f32 = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -527,7 +527,7 @@ LL |         let _val: f32 = mem::uninitialized();
    = note: floats must not be uninitialized
 
 error: the type `*const ()` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:129:31
+  --> $DIR/invalid_value.rs:133:31
    |
 LL |         let _val: *const () = mem::uninitialized();
    |                               ^^^^^^^^^^^^^^^^^^^^
@@ -538,7 +538,7 @@ LL |         let _val: *const () = mem::uninitialized();
    = note: raw pointers must not be uninitialized
 
 error: the type `*const [()]` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:132:33
+  --> $DIR/invalid_value.rs:136:33
    |
 LL |         let _val: *const [()] = mem::uninitialized();
    |                                 ^^^^^^^^^^^^^^^^^^^^
@@ -548,8 +548,19 @@ LL |         let _val: *const [()] = mem::uninitialized();
    |
    = note: raw pointers must not be uninitialized
 
+error: the type `WrapAroundRange` does not permit being left uninitialized
+  --> $DIR/invalid_value.rs:139:37
+   |
+LL |         let _val: WrapAroundRange = mem::uninitialized();
+   |                                     ^^^^^^^^^^^^^^^^^^^^
+   |                                     |
+   |                                     this code causes undefined behavior when executed
+   |                                     help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: `WrapAroundRange` must be initialized inside its custom valid range
+
 error: the type `Result<i32, i32>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:137:38
+  --> $DIR/invalid_value.rs:144:38
    |
 LL |         let _val: Result<i32, i32> = mem::uninitialized();
    |                                      ^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +575,7 @@ LL | pub enum Result<T, E> {
    | ^^^^^^^^^^^^^^^^^^^^^
 
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:145:34
+  --> $DIR/invalid_value.rs:152:34
    |
 LL |         let _val: &'static i32 = mem::transmute(0usize);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
@@ -575,7 +586,7 @@ LL |         let _val: &'static i32 = mem::transmute(0usize);
    = note: references must be non-null
 
 error: the type `&[i32]` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:146:36
+  --> $DIR/invalid_value.rs:153:36
    |
 LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -586,7 +597,7 @@ LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    = note: references must be non-null
 
 error: the type `NonZeroU32` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:147:32
+  --> $DIR/invalid_value.rs:154:32
    |
 LL |         let _val: NonZeroU32 = mem::transmute(0);
    |                                ^^^^^^^^^^^^^^^^^
@@ -597,7 +608,7 @@ LL |         let _val: NonZeroU32 = mem::transmute(0);
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `NonNull<i32>` does not permit zero-initialization
-  --> $DIR/invalid_value.rs:150:34
+  --> $DIR/invalid_value.rs:157:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -608,7 +619,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:151:34
+  --> $DIR/invalid_value.rs:158:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -619,7 +630,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/invalid_value.rs:152:26
+  --> $DIR/invalid_value.rs:159:26
    |
 LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -629,5 +640,5 @@ LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |
    = note: booleans must be either `true` or `false`
 
-error: aborting due to 50 previous errors
+error: aborting due to 51 previous errors
 
diff --git a/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr b/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr
index 3f366bedbf3..2cc4d382d9d 100644
--- a/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr
+++ b/src/test/ui/lint/lint-incoherent-auto-trait-objects.stderr
@@ -37,3 +37,45 @@ LL | impl Foo for dyn Send + Sync + Send {}
 
 error: aborting due to 3 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + 'static)`: (E0119)
+  --> $DIR/lint-incoherent-auto-trait-objects.rs:5:1
+   |
+LL | impl Foo for dyn Send {}
+   | --------------------- first implementation here
+LL |
+LL | impl Foo for dyn Send + Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+   = note: `#[deny(order_dependent_trait_objects)]` on by default
+
+Future breakage diagnostic:
+error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/lint-incoherent-auto-trait-objects.rs:11:1
+   |
+LL | impl Foo for dyn Send + Sync {}
+   | ---------------------------- first implementation here
+LL |
+LL | impl Foo for dyn Sync + Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+   = note: `#[deny(order_dependent_trait_objects)]` on by default
+
+Future breakage diagnostic:
+error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/lint-incoherent-auto-trait-objects.rs:15:1
+   |
+LL | impl Foo for dyn Sync + Send {}
+   | ---------------------------- first implementation here
+...
+LL | impl Foo for dyn Send + Sync + Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+   = note: `#[deny(order_dependent_trait_objects)]` on by default
+
diff --git a/src/test/ui/lint/unused/unused-supertrait.rs b/src/test/ui/lint/unused/unused-supertrait.rs
new file mode 100644
index 00000000000..64a8e520457
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-supertrait.rs
@@ -0,0 +1,11 @@
+#![deny(unused_must_use)]
+
+fn it() -> impl ExactSizeIterator<Item = ()> {
+    let x: Box<dyn ExactSizeIterator<Item = ()>> = todo!();
+    x
+}
+
+fn main() {
+    it();
+    //~^ ERROR unused implementer of `Iterator` that must be used
+}
diff --git a/src/test/ui/lint/unused/unused-supertrait.stderr b/src/test/ui/lint/unused/unused-supertrait.stderr
new file mode 100644
index 00000000000..d2f8c007848
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-supertrait.stderr
@@ -0,0 +1,15 @@
+error: unused implementer of `Iterator` that must be used
+  --> $DIR/unused-supertrait.rs:9:5
+   |
+LL |     it();
+   |     ^^^^^
+   |
+   = note: iterators are lazy and do nothing unless consumed
+note: the lint level is defined here
+  --> $DIR/unused-supertrait.rs:1:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/macro-context.stderr b/src/test/ui/macros/macro-context.stderr
index 2a2e0c6c66a..f597c398b7c 100644
--- a/src/test/ui/macros/macro-context.stderr
+++ b/src/test/ui/macros/macro-context.stderr
@@ -57,7 +57,7 @@ error[E0425]: cannot find value `i` in this scope
   --> $DIR/macro-context.rs:3:13
    |
 LL |     () => ( i ; typeof );
-   |             ^ help: a local variable with a similar name exists: `a`
+   |             ^ not found in this scope
 ...
 LL |     let i = m!();
    |             ---- in this macro invocation
diff --git a/src/test/ui/methods/issues/issue-90315.rs b/src/test/ui/methods/issues/issue-90315.rs
index 01bf9f48402..79cdc41959a 100644
--- a/src/test/ui/methods/issues/issue-90315.rs
+++ b/src/test/ui/methods/issues/issue-90315.rs
@@ -1,7 +1,76 @@
+#![allow(unused)]
 fn main() {
-  let arr = &[0,1,2,3];
-  for _i in 0..arr.len().rev() { //~ERROR not an iterator
-     // The above error used to say “the method `rev` exists for type `usize`”.
-     // This regression test ensures it doesn't say that any more.
-  }
+    let arr = &[0, 1, 2, 3];
+    for _i in 0..arr.len().rev() {
+        //~^ ERROR can't call method
+        //~| surround the range in parentheses
+        // The above error used to say “the method `rev` exists for type `usize`”.
+        // This regression test ensures it doesn't say that any more.
+    }
+
+    // Test for #102396
+    for i in 1..11.rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    let end: usize = 10;
+    for i in 1..end.rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    for i in 1..(end + 1).rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    if 1..(end + 1).is_empty() {
+        //~^ ERROR can't call method
+        //~| ERROR mismatched types [E0308]
+        //~| HELP surround the range in parentheses
+    }
+
+    if 1..(end + 1).is_sorted() {
+        //~^ ERROR mismatched types [E0308]
+        //~| ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    let _res: i32 = 3..6.take(2).sum();
+    //~^ ERROR can't call method
+    //~| ERROR mismatched types [E0308]
+    //~| HELP surround the range in parentheses
+
+    let _sum: i32 = 3..6.sum();
+    //~^ ERROR can't call method
+    //~| ERROR mismatched types [E0308]
+    //~| HELP surround the range in parentheses
+
+    let a = 1 as usize;
+    let b = 10 as usize;
+
+    for _a in a..=b.rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    let _res = ..10.contains(3);
+    //~^ ERROR can't call method
+    //~| HELP surround the range in parentheses
+
+    if 1..end.error_method() {
+        //~^ ERROR no method named `error_method`
+        //~| ERROR mismatched types [E0308]
+        // Won't suggest
+    }
+
+    let _res = b.take(1)..a;
+    //~^ ERROR `usize` is not an iterator
+
+    let _res: i32 = ..6.take(2).sum();
+    //~^ can't call method `take` on ambiguous numeric type
+    //~| ERROR mismatched types [E0308]
+    //~| HELP you must specify a concrete type for this numeric value
+    // Won't suggest because `RangeTo` dest not implemented `take`
 }
diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr
index c6a76c9e790..070cd305436 100644
--- a/src/test/ui/methods/issues/issue-90315.stderr
+++ b/src/test/ui/methods/issues/issue-90315.stderr
@@ -1,13 +1,201 @@
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:4:28
+   |
+LL |     for _i in 0..arr.len().rev() {
+   |                            ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for _i in (0..arr.len()).rev() {
+   |               +            +
+
+error[E0689]: can't call method `rev` on type `{integer}`
+  --> $DIR/issue-90315.rs:12:20
+   |
+LL |     for i in 1..11.rev() {
+   |                    ^^^ can't call method `rev` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for i in (1..11).rev() {
+   |              +     +
+
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:18:21
+   |
+LL |     for i in 1..end.rev() {
+   |                     ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for i in (1..end).rev() {
+   |              +      +
+
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:23:27
+   |
+LL |     for i in 1..(end + 1).rev() {
+   |                           ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for i in (1..(end + 1)).rev() {
+   |              +            +
+
+error[E0689]: can't call method `is_empty` on type `usize`
+  --> $DIR/issue-90315.rs:28:21
+   |
+LL |     if 1..(end + 1).is_empty() {
+   |                     ^^^^^^^^ can't call method `is_empty` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `is_empty` function
+   |
+LL |     if (1..(end + 1)).is_empty() {
+   |        +            +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:28:8
+   |
+LL |     if 1..(end + 1).is_empty() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `is_sorted` on type `usize`
+  --> $DIR/issue-90315.rs:34:21
+   |
+LL |     if 1..(end + 1).is_sorted() {
+   |                     ^^^^^^^^^ can't call method `is_sorted` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `is_sorted` function
+   |
+LL |     if (1..(end + 1)).is_sorted() {
+   |        +            +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:34:8
+   |
+LL |     if 1..(end + 1).is_sorted() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `take` on type `{integer}`
+  --> $DIR/issue-90315.rs:40:26
+   |
+LL |     let _res: i32 = 3..6.take(2).sum();
+   |                          ^^^^ can't call method `take` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `take` function
+   |
+LL |     let _res: i32 = (3..6).take(2).sum();
+   |                     +    +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:40:21
+   |
+LL |     let _res: i32 = 3..6.take(2).sum();
+   |               ---   ^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `std::ops::Range`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `sum` on type `{integer}`
+  --> $DIR/issue-90315.rs:45:26
+   |
+LL |     let _sum: i32 = 3..6.sum();
+   |                          ^^^ can't call method `sum` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `sum` function
+   |
+LL |     let _sum: i32 = (3..6).sum();
+   |                     +    +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:45:21
+   |
+LL |     let _sum: i32 = 3..6.sum();
+   |               ---   ^^^^^^^^^^ expected `i32`, found struct `std::ops::Range`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:53:21
+   |
+LL |     for _a in a..=b.rev() {
+   |                     ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for _a in (a..=b).rev() {
+   |               +     +
+
+error[E0689]: can't call method `contains` on type `{integer}`
+  --> $DIR/issue-90315.rs:58:21
+   |
+LL |     let _res = ..10.contains(3);
+   |                     ^^^^^^^^ can't call method `contains` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `contains` function
+   |
+LL |     let _res = (..10).contains(3);
+   |                +    +
+
+error[E0599]: no method named `error_method` found for type `usize` in the current scope
+  --> $DIR/issue-90315.rs:62:15
+   |
+LL |     if 1..end.error_method() {
+   |               ^^^^^^^^^^^^ method not found in `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:62:8
+   |
+LL |     if 1..end.error_method() {
+   |        ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<{integer}>`
+
 error[E0599]: `usize` is not an iterator
-  --> $DIR/issue-90315.rs:3:26
+  --> $DIR/issue-90315.rs:68:18
    |
-LL |   for _i in 0..arr.len().rev() {
-   |                          ^^^ `usize` is not an iterator
+LL |     let _res = b.take(1)..a;
+   |                  ^^^^ `usize` is not an iterator
    |
    = note: the following trait bounds were not satisfied:
            `usize: Iterator`
            which is required by `&mut usize: Iterator`
 
-error: aborting due to previous error
+error[E0689]: can't call method `take` on ambiguous numeric type `{integer}`
+  --> $DIR/issue-90315.rs:71:25
+   |
+LL |     let _res: i32 = ..6.take(2).sum();
+   |                         ^^^^
+   |
+help: you must specify a concrete type for this numeric value, like `i32`
+   |
+LL |     let _res: i32 = ..6_i32.take(2).sum();
+   |                       ~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:71:21
+   |
+LL |     let _res: i32 = ..6.take(2).sum();
+   |               ---   ^^^^^^^^^^^^^^^^^ expected `i32`, found struct `RangeTo`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `RangeTo<_>`
+
+error: aborting due to 19 previous errors
 
-For more information about this error, try `rustc --explain E0599`.
+Some errors have detailed explanations: E0308, E0599, E0689.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mir/mir_let_chains_drop_order.rs b/src/test/ui/mir/mir_let_chains_drop_order.rs
index 536a84a352a..6471553e93f 100644
--- a/src/test/ui/mir/mir_let_chains_drop_order.rs
+++ b/src/test/ui/mir/mir_let_chains_drop_order.rs
@@ -12,7 +12,7 @@ use std::panic;
 pub struct DropLogger<'a, T> {
     extra: T,
     id: usize,
-    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>,
 }
 
 impl<'a, T> Drop for DropLogger<'a, T> {
@@ -55,9 +55,9 @@ fn main() {
             else {
                 // 10 is not constructed
                 d(10, None)
-            }
+            },
         );
-        assert_eq!(get(), vec![3, 8, 7, 1, 2]);
+        assert_eq!(get(), vec![8, 7, 1, 3, 2]);
     }
     assert_eq!(get(), vec![0, 4, 6, 9, 5]);
 
@@ -89,5 +89,5 @@ fn main() {
             panic::panic_any(InjectedFailure)
         );
     });
-    assert_eq!(get(), vec![14, 19, 20, 17, 15, 11, 18, 16, 12, 13]);
+    assert_eq!(get(), vec![20, 17, 15, 11, 19, 18, 16, 12, 14, 13]);
 }
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 01293379700..da4bc499c7e 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -53,15 +53,14 @@ LL | fn case2() {
 error[E0597]: `a` does not live long enough
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
    |
-LL |       let cell = Cell::new(&a);
-   |                            ^^ borrowed value does not live long enough
+LL |     let cell = Cell::new(&a);
+   |                ----------^^-
+   |                |         |
+   |                |         borrowed value does not live long enough
+   |                argument requires that `a` is borrowed for `'static`
 ...
-LL | /     foo(cell, |cell_a, cell_x| {
-LL | |         cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
-LL | |     })
-   | |______- argument requires that `a` is borrowed for `'static`
-LL |   }
-   |   - `a` dropped here while still borrowed
+LL | }
+   | - `a` dropped here while still borrowed
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr
index 2be0460df1f..1c1a31d356d 100644
--- a/src/test/ui/nll/closures-in-loops.stderr
+++ b/src/test/ui/nll/closures-in-loops.stderr
@@ -13,17 +13,21 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/closures-in-loops.rs:13:16
    |
 LL |         v.push(|| x = String::new());
-   |                ^^ - borrows occur due to use of `x` in closure
-   |                |
-   |                `x` was mutably borrowed here in the previous iteration of the loop
+   |         -------^^-------------------
+   |         |      |  |
+   |         |      |  borrows occur due to use of `x` in closure
+   |         |      `x` was mutably borrowed here in the previous iteration of the loop
+   |         first borrow used here, in later iteration of loop
 
 error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/closures-in-loops.rs:20:16
    |
 LL |         v.push(|| *x = String::new());
-   |                ^^ -- borrows occur due to use of `x` in closure
-   |                |
-   |                closures are constructed here in different iterations of loop
+   |         -------^^--------------------
+   |         |      |  |
+   |         |      |  borrows occur due to use of `x` in closure
+   |         |      closures are constructed here in different iterations of loop
+   |         first borrow used here, in later iteration of loop
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
index 3326fa521fc..bb703412228 100644
--- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -1,14 +1,14 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:33:41
    |
-LL | /     combine(
-LL | |         SomeEnum::SomeVariant(Cell::new(&c)),
-   | |                                         ^^ borrowed value does not live long enough
-LL | |         SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
-LL | |     );
-   | |_____- argument requires that `c` is borrowed for `'static`
-LL |   }
-   |   - `c` dropped here while still borrowed
+LL |         SomeEnum::SomeVariant(Cell::new(&c)),
+   |                               ----------^^-
+   |                               |         |
+   |                               |         borrowed value does not live long enough
+   |                               argument requires that `c` is borrowed for `'static`
+...
+LL | }
+   | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:41:41
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 800b5a43a00..038fdfb2d51 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -199,7 +199,7 @@ note: ...which requires borrow-checking `main::ff5`...
    |
 LL |     const async unsafe extern "C" fn ff5() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `main::ff5`...
+note: ...which requires processing MIR for `main::ff5`...
   --> $DIR/fn-header-semantic-fail.rs:12:5
    |
 LL |     const async unsafe extern "C" fn ff5() {}
@@ -235,7 +235,7 @@ note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
+note: ...which requires processing MIR for `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
   --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
@@ -271,7 +271,7 @@ note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
+note: ...which requires processing MIR for `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
   --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
diff --git a/src/test/ui/parser/issues/issue-93282.rs b/src/test/ui/parser/issues/issue-93282.rs
index 261fcb5f918..274245f1a46 100644
--- a/src/test/ui/parser/issues/issue-93282.rs
+++ b/src/test/ui/parser/issues/issue-93282.rs
@@ -12,4 +12,5 @@ fn foo() {
     let x = 1;
     bar('y, x);
     //~^ ERROR expected
+    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/parser/issues/issue-93282.stderr b/src/test/ui/parser/issues/issue-93282.stderr
index ee554784b3a..c6140bb821e 100644
--- a/src/test/ui/parser/issues/issue-93282.stderr
+++ b/src/test/ui/parser/issues/issue-93282.stderr
@@ -3,6 +3,11 @@ error: expected `while`, `for`, `loop` or `{` after a label
    |
 LL |     f<'a,>
    |         ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     f<'a',>
+   |         +
 
 error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `}`, or an operator, found `,`
   --> $DIR/issue-93282.rs:2:9
@@ -20,6 +25,26 @@ error: expected `while`, `for`, `loop` or `{` after a label
    |
 LL |     bar('y, x);
    |           ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     bar('y', x);
+   |           +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-93282.rs:13:9
+   |
+LL |     bar('y, x);
+   |     --- ^^ expected `usize`, found `char`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/issue-93282.rs:7:4
+   |
+LL | fn bar(a: usize, b: usize) -> usize {
+   |    ^^^ --------
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/label-is-actually-char.rs b/src/test/ui/parser/label-is-actually-char.rs
new file mode 100644
index 00000000000..183da603da4
--- /dev/null
+++ b/src/test/ui/parser/label-is-actually-char.rs
@@ -0,0 +1,16 @@
+fn main() {
+    let c = 'a;
+    //~^ ERROR expected `while`, `for`, `loop` or `{` after a label
+    //~| HELP add `'` to close the char literal
+    match c {
+        'a'..='b => {}
+        //~^ ERROR unexpected token: `'b`
+        //~| HELP add `'` to close the char literal
+        _ => {}
+    }
+    let x = ['a, 'b];
+    //~^ ERROR expected `while`, `for`, `loop` or `{` after a label
+    //~| ERROR expected `while`, `for`, `loop` or `{` after a label
+    //~| HELP add `'` to close the char literal
+    //~| HELP add `'` to close the char literal
+}
diff --git a/src/test/ui/parser/label-is-actually-char.stderr b/src/test/ui/parser/label-is-actually-char.stderr
new file mode 100644
index 00000000000..28c8d2ada3a
--- /dev/null
+++ b/src/test/ui/parser/label-is-actually-char.stderr
@@ -0,0 +1,46 @@
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/label-is-actually-char.rs:2:15
+   |
+LL |     let c = 'a;
+   |               ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     let c = 'a';
+   |               +
+
+error: unexpected token: `'b`
+  --> $DIR/label-is-actually-char.rs:6:15
+   |
+LL |         'a'..='b => {}
+   |               ^^
+   |
+help: add `'` to close the char literal
+   |
+LL |         'a'..='b' => {}
+   |                 +
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/label-is-actually-char.rs:11:16
+   |
+LL |     let x = ['a, 'b];
+   |                ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     let x = ['a', 'b];
+   |                +
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/label-is-actually-char.rs:11:20
+   |
+LL |     let x = ['a, 'b];
+   |                    ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     let x = ['a, 'b'];
+   |                    +
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/parser/numeric-lifetime.stderr b/src/test/ui/parser/numeric-lifetime.stderr
index 73a828952b2..7c1bcb72631 100644
--- a/src/test/ui/parser/numeric-lifetime.stderr
+++ b/src/test/ui/parser/numeric-lifetime.stderr
@@ -1,3 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/numeric-lifetime.rs:6:20
+   |
+LL |     let x: usize = "";
+   |            -----   ^^ expected `usize`, found `&str`
+   |            |
+   |            expected due to this
+
 error: lifetimes cannot start with a number
   --> $DIR/numeric-lifetime.rs:1:10
    |
@@ -10,14 +18,6 @@ error: lifetimes cannot start with a number
 LL | struct S<'1> { s: &'1 usize }
    |                    ^^
 
-error[E0308]: mismatched types
-  --> $DIR/numeric-lifetime.rs:6:20
-   |
-LL |     let x: usize = "";
-   |            -----   ^^ expected `usize`, found `&str`
-   |            |
-   |            expected due to this
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs
index f29fd7a5472..5b90e905a64 100644
--- a/src/test/ui/parser/require-parens-for-chained-comparison.rs
+++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs
@@ -23,11 +23,13 @@ fn main() {
     //~^ ERROR expected one of
     //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
     //~| ERROR expected
+    //~| HELP add `'` to close the char literal
 
     f<'_>();
     //~^ comparison operators cannot be chained
     //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
     //~| ERROR expected
+    //~| HELP add `'` to close the char literal
 
     let _ = f<u8>;
     //~^ ERROR comparison operators cannot be chained
diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr
index 0bf52854ec2..52e201c435c 100644
--- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr
+++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr
@@ -58,6 +58,11 @@ error: expected `while`, `for`, `loop` or `{` after a label
    |
 LL |     let _ = f<'_, i8>();
    |                 ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     let _ = f<'_', i8>();
+   |                 +
 
 error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, or an operator, found `,`
   --> $DIR/require-parens-for-chained-comparison.rs:22:17
@@ -71,13 +76,18 @@ LL |     let _ = f::<'_, i8>();
    |              ++
 
 error: expected `while`, `for`, `loop` or `{` after a label
-  --> $DIR/require-parens-for-chained-comparison.rs:27:9
+  --> $DIR/require-parens-for-chained-comparison.rs:28:9
    |
 LL |     f<'_>();
    |         ^ expected `while`, `for`, `loop` or `{` after a label
+   |
+help: add `'` to close the char literal
+   |
+LL |     f<'_'>();
+   |         +
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:27:6
+  --> $DIR/require-parens-for-chained-comparison.rs:28:6
    |
 LL |     f<'_>();
    |      ^  ^
@@ -88,7 +98,7 @@ LL |     f::<'_>();
    |      ++
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:32:14
+  --> $DIR/require-parens-for-chained-comparison.rs:34:14
    |
 LL |     let _ = f<u8>;
    |              ^  ^
diff --git a/src/test/ui/parser/semi-after-closure-in-macro.rs b/src/test/ui/parser/semi-after-closure-in-macro.rs
new file mode 100644
index 00000000000..14efb6100b0
--- /dev/null
+++ b/src/test/ui/parser/semi-after-closure-in-macro.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+// Checks that the fix in #103222 doesn't also disqualify semicolons after
+// closures within parentheses *in macros*, where they're totally allowed.
+
+macro_rules! m {
+    (($expr:expr ; )) => {
+        $expr
+    };
+}
+
+fn main() {
+    let x = m!(( ||() ; ));
+}
diff --git a/src/test/ui/privacy/access_levels.rs b/src/test/ui/privacy/access_levels.rs
index bf94d980678..42c9975bedb 100644
--- a/src/test/ui/privacy/access_levels.rs
+++ b/src/test/ui/privacy/access_levels.rs
@@ -1,44 +1,44 @@
 #![feature(rustc_attrs)]
 
 #[rustc_effective_visibility]
-mod outer { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+mod outer { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
     #[rustc_effective_visibility]
-    pub mod inner1 { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+    pub mod inner1 { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
 
         #[rustc_effective_visibility]
-        extern "C" {} //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+        extern "C" {} //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
 
         #[rustc_effective_visibility]
-        pub trait PubTrait { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+        pub trait PubTrait { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
             #[rustc_effective_visibility]
-            const A: i32; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            const A: i32; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
             #[rustc_effective_visibility]
-            type B; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            type B; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
         }
 
         #[rustc_effective_visibility]
         struct PrivStruct; //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
 
         #[rustc_effective_visibility]
-        pub union PubUnion { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+        pub union PubUnion { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
             #[rustc_effective_visibility]
             a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
             #[rustc_effective_visibility]
-            pub b: u8, //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            pub b: u8, //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
         }
 
         #[rustc_effective_visibility]
-        pub enum Enum { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+        pub enum Enum { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
             #[rustc_effective_visibility]
-            A( //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            A( //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
                 #[rustc_effective_visibility]
-                PubUnion,  //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+                PubUnion,  //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
             ),
         }
     }
 
     #[rustc_effective_visibility]
-    macro_rules! none_macro { //~ Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+    macro_rules! none_macro { //~ Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
         () => {};
     }
 
@@ -49,9 +49,9 @@ mod outer { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(sel
     }
 
     #[rustc_effective_visibility]
-    pub struct ReachableStruct { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+    pub struct ReachableStruct { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
         #[rustc_effective_visibility]
-        pub a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+        pub a: u8, //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
     }
 }
 
@@ -62,14 +62,14 @@ pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} }
 
 mod half_public_import {
     #[rustc_effective_visibility]
-    pub type HalfPublicImport = u8; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+    pub type HalfPublicImport = u8; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
     #[rustc_effective_visibility]
     #[allow(non_upper_case_globals)]
-    pub(crate) const HalfPublicImport: u8 = 0; //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+    pub(crate) const HalfPublicImport: u8 = 0; //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
 }
 
 #[rustc_effective_visibility]
 pub use half_public_import::HalfPublicImport; //~ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-                                              //~^ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+                                              //~^ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
 
 fn main() {}
diff --git a/src/test/ui/privacy/access_levels.stderr b/src/test/ui/privacy/access_levels.stderr
index 81514d1fbab..111e02bc329 100644
--- a/src/test/ui/privacy/access_levels.stderr
+++ b/src/test/ui/privacy/access_levels.stderr
@@ -1,22 +1,22 @@
-error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
   --> $DIR/access_levels.rs:4:1
    |
 LL | mod outer {
    | ^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:6:5
    |
 LL |     pub mod inner1 {
    |     ^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:9:9
    |
 LL |         extern "C" {}
    |         ^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:12:9
    |
 LL |         pub trait PubTrait {
@@ -28,7 +28,7 @@ error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFr
 LL |         struct PrivStruct;
    |         ^^^^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:23:9
    |
 LL |         pub union PubUnion {
@@ -40,31 +40,31 @@ error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFr
 LL |             a: u8,
    |             ^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:27:13
    |
 LL |             pub b: u8,
    |             ^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:31:9
    |
 LL |         pub enum Enum {
    |         ^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:33:13
    |
 LL |             A(
    |             ^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:35:17
    |
 LL |                 PubUnion,
    |                 ^^^^^^^^
 
-error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
   --> $DIR/access_levels.rs:41:5
    |
 LL |     macro_rules! none_macro {
@@ -76,13 +76,13 @@ error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
 LL |     macro_rules! public_macro {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:52:5
    |
 LL |     pub struct ReachableStruct {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:54:9
    |
 LL |         pub a: u8,
@@ -94,13 +94,13 @@ error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
 LL | pub use outer::inner1;
    |         ^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:65:5
    |
 LL |     pub type HalfPublicImport = u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
   --> $DIR/access_levels.rs:68:5
    |
 LL |     pub(crate) const HalfPublicImport: u8 = 0;
@@ -112,19 +112,19 @@ error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
 LL | pub use half_public_import::HalfPublicImport;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:72:9
    |
 LL | pub use half_public_import::HalfPublicImport;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:14:13
    |
 LL |             const A: i32;
    |             ^^^^^^^^^^^^
 
-error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:16:13
    |
 LL |             type B;
diff --git a/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr b/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
index 6060f872f22..df7c4f72eb0 100644
--- a/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
+++ b/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
@@ -13,7 +13,7 @@ error[E0425]: cannot find value `local_use` in this scope
   --> $DIR/gen-macro-rules-hygiene.rs:12:1
    |
 LL | gen_macro_rules!();
-   | ^^^^^^^^^^^^^^^^^^ not found in this scope
+   | ^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
 ...
 LL |         generated!();
    |         ------------ in this macro invocation
@@ -24,7 +24,7 @@ error[E0425]: cannot find value `local_def` in this scope
   --> $DIR/gen-macro-rules-hygiene.rs:21:9
    |
 LL |         local_def;
-   |         ^^^^^^^^^ not found in this scope
+   |         ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/proc-macro/mixed-site-span.stderr b/src/test/ui/proc-macro/mixed-site-span.stderr
index eab4317ded8..13786080124 100644
--- a/src/test/ui/proc-macro/mixed-site-span.stderr
+++ b/src/test/ui/proc-macro/mixed-site-span.stderr
@@ -10,7 +10,7 @@ error[E0425]: cannot find value `local_use` in this scope
   --> $DIR/mixed-site-span.rs:13:9
    |
 LL |         proc_macro_rules!();
-   |         ^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |         ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
    |
    = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -18,7 +18,7 @@ error[E0425]: cannot find value `local_def` in this scope
   --> $DIR/mixed-site-span.rs:17:9
    |
 LL |         local_def;
-   |         ^^^^^^^^^ not found in this scope
+   |         ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
 
 error[E0412]: cannot find type `ItemUse` in crate `$crate`
   --> $DIR/mixed-site-span.rs:24:1
diff --git a/src/test/ui/process/process-spawn-with-unicode-params.rs b/src/test/ui/process/process-spawn-with-unicode-params.rs
index 6e9229b6293..16dba6292db 100644
--- a/src/test/ui/process/process-spawn-with-unicode-params.rs
+++ b/src/test/ui/process/process-spawn-with-unicode-params.rs
@@ -9,6 +9,7 @@
 
 // ignore-emscripten no processes
 // ignore-sgx no processes
+// ignore-fuchsia Filesystem manipulation privileged
 
 use std::io::prelude::*;
 use std::io;
diff --git a/src/test/ui/query-visibility.rs b/src/test/ui/query-visibility.rs
new file mode 100644
index 00000000000..09a289d85da
--- /dev/null
+++ b/src/test/ui/query-visibility.rs
@@ -0,0 +1,9 @@
+// check-pass
+// Check that it doesn't panic when `Input` gets its visibility checked.
+
+#![crate_type = "lib"]
+
+pub trait Layer<
+    /// Hello.
+    Input,
+> {}
diff --git a/src/test/ui/resolve/issue-103202.rs b/src/test/ui/resolve/issue-103202.rs
new file mode 100644
index 00000000000..469d9d7c860
--- /dev/null
+++ b/src/test/ui/resolve/issue-103202.rs
@@ -0,0 +1,7 @@
+struct S {}
+
+impl S {
+    fn f(self: &S::x) {} //~ ERROR ambiguous associated type
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-103202.stderr b/src/test/ui/resolve/issue-103202.stderr
new file mode 100644
index 00000000000..880389371ef
--- /dev/null
+++ b/src/test/ui/resolve/issue-103202.stderr
@@ -0,0 +1,9 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/issue-103202.rs:4:17
+   |
+LL |     fn f(self: &S::x) {}
+   |                 ^^^^ help: use fully-qualified syntax: `<S as Trait>::x`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr b/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr
index af9f4612ab3..eb26cd9cabb 100644
--- a/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr
+++ b/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr
@@ -1,11 +1,16 @@
 error[E0574]: expected struct, variant or union type, found type parameter `Baz`
   --> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
    |
-LL | impl<Baz> Foo<Baz> for Bar {
-   |      --- found this type parameter
+LL | / struct Baz {
+LL | |     num: usize,
+LL | | }
+   | |_- you might have meant to refer to this struct
+LL |
+LL |   impl<Baz> Foo<Baz> for Bar {
+   |        --- found this type parameter
 ...
-LL |             Baz { num } => num,
-   |             ^^^ not a struct, variant or union type
+LL |               Baz { num } => num,
+   |               ^^^ not a struct, variant or union type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index a369dc6db52..82a4211f08a 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -327,7 +327,7 @@ LL |         let _: Z = Z::Fn;
    |
    = note: expected enum `Z`
            found fn item `fn(u8) -> Z {Z::Fn}`
-help: use parentheses to instantiate this tuple variant
+help: use parentheses to construct this tuple variant
    |
 LL |         let _: Z = Z::Fn(/* u8 */);
    |                         ++++++++++
@@ -362,7 +362,7 @@ LL |     let _: E = m::E::Fn;
    |
    = note: expected enum `E`
            found fn item `fn(u8) -> E {E::Fn}`
-help: use parentheses to instantiate this tuple variant
+help: use parentheses to construct this tuple variant
    |
 LL |     let _: E = m::E::Fn(/* u8 */);
    |                        ++++++++++
@@ -397,7 +397,7 @@ LL |     let _: E = E::Fn;
    |
    = note: expected enum `E`
            found fn item `fn(u8) -> E {E::Fn}`
-help: use parentheses to instantiate this tuple variant
+help: use parentheses to construct this tuple variant
    |
 LL |     let _: E = E::Fn(/* u8 */);
    |                     ++++++++++
diff --git a/src/test/ui/issues/issue-64620.rs b/src/test/ui/return/issue-64620.rs
index a62e5bf8d3c..a62e5bf8d3c 100644
--- a/src/test/ui/issues/issue-64620.rs
+++ b/src/test/ui/return/issue-64620.rs
diff --git a/src/test/ui/issues/issue-64620.stderr b/src/test/ui/return/issue-64620.stderr
index f40ac4de32d..f40ac4de32d 100644
--- a/src/test/ui/issues/issue-64620.stderr
+++ b/src/test/ui/return/issue-64620.stderr
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs
new file mode 100644
index 00000000000..a75c91cc90d
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.rs
@@ -0,0 +1,11 @@
+// Check that we don't blindly emit a diagnostic claiming that "`main` has an invalid return type"
+// if we encounter a type that doesn't implement `std::process::Termination` and is not actually
+// the return type of the program entry `main`.
+
+fn receive(_: impl std::process::Termination) {}
+
+struct Something;
+
+fn main() {
+    receive(Something); //~ ERROR the trait bound `Something: Termination` is not satisfied
+}
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr
new file mode 100644
index 00000000000..409dede1a90
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-1.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `Something: Termination` is not satisfied
+  --> $DIR/issue-103052-1.rs:10:13
+   |
+LL |     receive(Something);
+   |     ------- ^^^^^^^^^ the trait `Termination` is not implemented for `Something`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `receive`
+  --> $DIR/issue-103052-1.rs:5:20
+   |
+LL | fn receive(_: impl std::process::Termination) {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `receive`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs
new file mode 100644
index 00000000000..fa9182b6dee
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.rs
@@ -0,0 +1,18 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+mod child {
+    trait Main {
+        fn main() -> impl std::process::Termination;
+    }
+
+    struct Something;
+
+    impl Main for () {
+        fn main() -> Something { //~ ERROR the trait bound `Something: Termination` is not satisfied
+            Something
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr
new file mode 100644
index 00000000000..a700c72ea68
--- /dev/null
+++ b/src/test/ui/rfc-1937-termination-trait/issue-103052-2.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `Something: Termination` is not satisfied
+  --> $DIR/issue-103052-2.rs:12:22
+   |
+LL |         fn main() -> Something {
+   |                      ^^^^^^^^^ the trait `Termination` is not implemented for `Something`
+   |
+note: required by a bound in `Main::main::{opaque#0}`
+  --> $DIR/issue-103052-2.rs:6:27
+   |
+LL |         fn main() -> impl std::process::Termination;
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::main::{opaque#0}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
index 7c1390cdc64..6ee32314607 100644
--- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
@@ -1,4 +1,4 @@
-error[E0277]: `main` has invalid return type `f32`
+error[E0277]: the trait bound `f32: Termination` is not satisfied
   --> $DIR/termination-trait-test-wrong-type.rs:6:1
    |
 LL |   #[test]
@@ -6,9 +6,8 @@ LL |   #[test]
 LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> {
 LL | |     "0".parse()
 LL | | }
-   | |_^ `main` can only return types that implement `Termination`
+   | |_^ the trait `Termination` is not implemented for `f32`
    |
-   = help: the trait `Termination` is not implemented for `f32`
    = note: required for `Result<f32, ParseFloatError>` to implement `Termination`
 note: required by a bound in `assert_test_result`
   --> $SRC_DIR/test/src/lib.rs:LL:COL
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
index ce2425010ad..89177b0f1ac 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -15,10 +15,6 @@ note: required by a bound in `Foo::Bar`
    |
 LL |     type Bar: ~const std::ops::Add;
    |               ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | impl const Foo for NonConstAdd where NonConstAdd: ~const Add {
-   |                                +++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
index d9ad8043153..7350909ba8e 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
@@ -9,10 +9,6 @@ note: the trait `Plus` is implemented for `u32`, but that implementation is not
    |
 LL |     a.plus(b)
    |       ^^^^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub const fn add_u32(a: u32, b: u32) -> u32 where u32: ~const Plus {
-   |                                             ++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
index 83d395dda19..31e6dbdab22 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
@@ -9,7 +9,6 @@ note: the trait `PartialEq<_>` is implemented for `T`, but that implementation i
    |
 LL |     *t == *t
    |        ^^
-   = help: the trait `PartialEq<&B>` is implemented for `&A`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
index fddc8d37f2f..c64930db9be 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
@@ -11,10 +11,6 @@ note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that imp
    |
 LL |     NonConstImpl.a();
    |     ^^^^^^^^^^^^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | const fn test() where NonConstImpl: ~const ConstDefaultFn {
-   |                 +++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
index ddf0e2d91c0..796c0d388ea 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
@@ -45,34 +45,55 @@ note: required by a bound in `check`
 LL | const fn check<T: ~const Destruct>(_: T) {}
    |                   ^^^^^^^^^^^^^^^ required by this bound in `check`
 
-error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Destruct` is not satisfied
+error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
+  --> $DIR/const-drop-fail.rs:48:47
+   |
+LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     ----------------------------------------- ^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
+  --> $DIR/const-drop-fail.rs:48:47
+   |
+LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |                                               ^^^^^^^^^^^
+note: required by a bound in `ConstDropImplWithBounds`
+  --> $DIR/const-drop-fail.rs:27:35
+   |
+LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
+   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
+
+error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
+  --> $DIR/const-drop-fail.rs:48:5
+   |
+LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
+   |
+note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
   --> $DIR/const-drop-fail.rs:48:5
    |
-LL |         const _: () = check($exp);
-   |                       ----- required by a bound introduced by this call
-...
 LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `ConstDropImplWithBounds<NonTrivialDrop>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `ConstDropImplWithBounds`
+  --> $DIR/const-drop-fail.rs:27:35
    |
-note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
-  --> $DIR/const-drop-fail.rs:29:25
+LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
+   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
+
+error[E0367]: `Drop` impl requires `T: ~const A` but the struct it is implemented for does not
+  --> $DIR/const-drop-fail.rs:55:9
    |
-LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
-   |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: 1 redundant requirement hidden
-   = note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
-note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
+   |         ^^^^^^^^
    |
-LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                   ^^^^^^^^^^^^^^^ required by this bound in `check`
-help: consider borrowing here
+note: the implementor must specify the same requirement
+  --> $DIR/const-drop-fail.rs:53:1
    |
-LL |     &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     +
-LL |     &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ++++
+LL | struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0367.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
index 565e2c77ac5..d36c7f81ced 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
@@ -24,7 +24,7 @@ trait A { fn a() { } }
 
 impl A for NonTrivialDrop {}
 
-struct ConstDropImplWithBounds<T: A>(PhantomData<T>);
+struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
 
 impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
     fn drop(&mut self) {
@@ -47,6 +47,16 @@ check_all! {
     //~^ ERROR can't drop
     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
     //~^ ERROR the trait bound
+    //~| ERROR the trait bound
+}
+
+struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);
+
+impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
+//~^ ERROR `Drop` impl requires `T: ~const A` but the struct it is implemented for does not
+    fn drop(&mut self) {
+        T::a();
+    }
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
index ddf0e2d91c0..796c0d388ea 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
@@ -45,34 +45,55 @@ note: required by a bound in `check`
 LL | const fn check<T: ~const Destruct>(_: T) {}
    |                   ^^^^^^^^^^^^^^^ required by this bound in `check`
 
-error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Destruct` is not satisfied
+error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
+  --> $DIR/const-drop-fail.rs:48:47
+   |
+LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     ----------------------------------------- ^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
+  --> $DIR/const-drop-fail.rs:48:47
+   |
+LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |                                               ^^^^^^^^^^^
+note: required by a bound in `ConstDropImplWithBounds`
+  --> $DIR/const-drop-fail.rs:27:35
+   |
+LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
+   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
+
+error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
+  --> $DIR/const-drop-fail.rs:48:5
+   |
+LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
+   |
+note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
   --> $DIR/const-drop-fail.rs:48:5
    |
-LL |         const _: () = check($exp);
-   |                       ----- required by a bound introduced by this call
-...
 LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `ConstDropImplWithBounds<NonTrivialDrop>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `ConstDropImplWithBounds`
+  --> $DIR/const-drop-fail.rs:27:35
    |
-note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
-  --> $DIR/const-drop-fail.rs:29:25
+LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
+   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
+
+error[E0367]: `Drop` impl requires `T: ~const A` but the struct it is implemented for does not
+  --> $DIR/const-drop-fail.rs:55:9
    |
-LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
-   |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: 1 redundant requirement hidden
-   = note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
-note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
+   |         ^^^^^^^^
    |
-LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                   ^^^^^^^^^^^^^^^ required by this bound in `check`
-help: consider borrowing here
+note: the implementor must specify the same requirement
+  --> $DIR/const-drop-fail.rs:53:1
    |
-LL |     &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     +
-LL |     &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ++++
+LL | struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0367.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
index 8b4c4065815..b0fc3adf984 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
@@ -60,7 +60,7 @@ mod t {
         fn foo() {}
     }
 
-    pub struct ConstDropWithBound<T: SomeTrait>(pub core::marker::PhantomData<T>);
+    pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);
 
     impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
         fn drop(&mut self) {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
index d4fa44b4bfc..925ae53e324 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
@@ -11,10 +11,6 @@ note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst
    |
 LL |     NonConst.func();
    |     ^^^^^^^^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait {
-   |                          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr
index 71ecd9b0694..11db0c2b8f2 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr
@@ -11,10 +11,6 @@ note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst
    |
 LL |     NonConst.func();
    |     ^^^^^^^^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait {
-   |                          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
index d102956cd2e..a244ab10cab 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
@@ -14,10 +14,6 @@ note: required by a bound in `foo`
    |
 LL | const fn foo<T>() where T: ~const Tr {}
    |                            ^^^^^^^^^ required by this bound in `foo`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub trait Foo where (): ~const Tr {
-   |               +++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
index 85285ba8497..c2c16921c2e 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
@@ -11,10 +11,6 @@ note: the trait `Tr` is implemented for `()`, but that implementation is not `co
    |
 LL |         ().a()
    |         ^^
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | pub trait Tr where (): ~const Tr {
-   |              +++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-90052.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-90052.rs
new file mode 100644
index 00000000000..21ddf4ab4e5
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-90052.rs
@@ -0,0 +1,9 @@
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Bar {}
+
+fn foo<T>() where T: ~const Bar {}
+//~^ ERROR `~const` is not allowed
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-90052.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-90052.stderr
new file mode 100644
index 00000000000..b2a9365378b
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-90052.stderr
@@ -0,0 +1,14 @@
+error: `~const` is not allowed here
+  --> $DIR/issue-90052.rs:6:22
+   |
+LL | fn foo<T>() where T: ~const Bar {}
+   |                      ^^^^^^^^^^
+   |
+note: this function is not `const`, so it cannot have `~const` trait bounds
+  --> $DIR/issue-90052.rs:6:4
+   |
+LL | fn foo<T>() where T: ~const Bar {}
+   |    ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
index 9787792ab13..1f8f312df01 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr
@@ -14,10 +14,6 @@ note: required by a bound in `Bar`
    |
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^^^^^ required by this bound in `Bar`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | impl const Bar for S where S: ~const Foo {}
-   |                      +++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
index b29b633cff6..78a64b9018a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.rs
@@ -1,4 +1,3 @@
-// check-pass
 #![feature(const_trait_impl)]
 #![feature(generic_arg_infer)]
 #![feature(generic_const_exprs)]
@@ -24,6 +23,7 @@ impl const Add42 for () {
 }
 
 fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+    //~^ ERROR `~const` is not allowed here
     Foo
 }
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
new file mode 100644
index 00000000000..aae72f36e57
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-and-const-params.stderr
@@ -0,0 +1,14 @@
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-and-const-params.rs:25:11
+   |
+LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+   |           ^^^^^^^^^^^^
+   |
+note: this function is not `const`, so it cannot have `~const` trait bounds
+  --> $DIR/tilde-const-and-const-params.rs:25:4
+   |
+LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+   |    ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
index 5d213315634..84867cb4a53 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
@@ -4,7 +4,7 @@ error: `~const` is not allowed here
 LL | fn rpit() -> impl ~const T { S }
    |                   ^^^^^^^^
    |
-   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
+   = note: `impl Trait`s cannot have `~const` trait bounds
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:12:17
@@ -12,7 +12,7 @@ error: `~const` is not allowed here
 LL | fn apit(_: impl ~const T) {}
    |                 ^^^^^^^^
    |
-   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
+   = note: `impl Trait`s cannot have `~const` trait bounds
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:15:50
@@ -20,7 +20,7 @@ error: `~const` is not allowed here
 LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
    |                                                  ^^^^^^^^
    |
-   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
+   = note: `impl Trait`s cannot have `~const` trait bounds
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:18:48
@@ -28,7 +28,7 @@ error: `~const` is not allowed here
 LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
    |                                                ^^^^^^^^
    |
-   = note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions
+   = note: `impl Trait`s cannot have `~const` trait bounds
 
 error: `~const` and `?` are mutually exclusive
   --> $DIR/tilde-const-invalid-places.rs:21:25
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs
new file mode 100644
index 00000000000..285cef571f3
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs
@@ -0,0 +1,17 @@
+// check-pass
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Foo {
+    fn foo(&self) {}
+}
+
+struct Bar<T>(T);
+
+impl<T: ~const Foo> Bar<T> {
+    const fn foo(&self) {
+        self.0.foo()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/runtime/rt-explody-panic-payloads.rs b/src/test/ui/runtime/rt-explody-panic-payloads.rs
index e2221e5df8e..755d3df42de 100644
--- a/src/test/ui/runtime/rt-explody-panic-payloads.rs
+++ b/src/test/ui/runtime/rt-explody-panic-payloads.rs
@@ -22,7 +22,12 @@ fn main() {
     }.expect("running the command should have succeeded");
     println!("{:#?}", output);
     let stderr = std::str::from_utf8(&output.stderr);
-    assert!(stderr.map(|v| {
-        v.ends_with("fatal runtime error: drop of the panic payload panicked\n")
-    }).unwrap_or(false));
+    assert!(stderr
+        .map(|v| {
+            // When running inside QEMU user-mode emulation, there will be an extra message printed
+            // by QEMU in the stderr whenever a core dump happens. Remove it before the check.
+            v.strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n").unwrap_or(v)
+        })
+        .map(|v| { v.ends_with("fatal runtime error: drop of the panic payload panicked\n") })
+        .unwrap_or(false));
 }
diff --git a/src/test/ui/single-use-lifetime/derive-eq.rs b/src/test/ui/single-use-lifetime/derive-eq.rs
new file mode 100644
index 00000000000..e5bdfc55dd6
--- /dev/null
+++ b/src/test/ui/single-use-lifetime/derive-eq.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![deny(single_use_lifetimes)]
+
+#[derive(PartialEq, Eq)]
+struct Foo<'a, T> {
+    /// a reference to the underlying secret data that will be derefed
+    pub data: &'a mut T,
+}
+
+fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
index ce2726ffde4..0c771ae8795 100644
--- a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs
@@ -1,4 +1,4 @@
-#![feature(staged_api)]
+#![feature(staged_api, never_type, c_unwind)]
 //~^ ERROR module has missing stability attribute
 
 #[stable(feature = "a", since = "1")]
@@ -23,7 +23,21 @@ impl StableTrait for UnstableType {}
 impl UnstableTrait for StableType {}
 
 #[unstable(feature = "h", issue = "none")]
+impl StableTrait for ! {}
+
+// Note: If C-unwind is stabilized, switch this to another (unstable) ABI.
+#[unstable(feature = "i", issue = "none")]
+impl StableTrait for extern "C-unwind" fn() {}
+
+#[unstable(feature = "j", issue = "none")]
 //~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
 impl StableTrait for StableType {}
 
+#[unstable(feature = "k", issue = "none")]
+//~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
+impl StableTrait for fn() -> ! {}
+
+#[unstable(feature = "l", issue = "none")]
+impl StableTrait for fn() -> UnstableType {}
+
 fn main() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr
index 7645f3c7ef5..b91a1d2e11a 100644
--- a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr
@@ -1,16 +1,24 @@
 error: an `#[unstable]` annotation here has no effect
-  --> $DIR/stability-attribute-trait-impl.rs:25:1
+  --> $DIR/stability-attribute-trait-impl.rs:32:1
    |
-LL | #[unstable(feature = "h", issue = "none")]
+LL | #[unstable(feature = "j", issue = "none")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
    = note: `#[deny(ineffective_unstable_trait_impl)]` on by default
 
+error: an `#[unstable]` annotation here has no effect
+  --> $DIR/stability-attribute-trait-impl.rs:36:1
+   |
+LL | #[unstable(feature = "k", issue = "none")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
+
 error: module has missing stability attribute
   --> $DIR/stability-attribute-trait-impl.rs:1:1
    |
-LL | / #![feature(staged_api)]
+LL | / #![feature(staged_api, never_type, c_unwind)]
 LL | |
 LL | |
 LL | | #[stable(feature = "a", since = "1")]
@@ -19,5 +27,5 @@ LL | |
 LL | | fn main() {}
    | |____________^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-2718-a.rs b/src/test/ui/structs-enums/issue-2718-a.rs
index 6c491584540..6c491584540 100644
--- a/src/test/ui/issues/issue-2718-a.rs
+++ b/src/test/ui/structs-enums/issue-2718-a.rs
diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/structs-enums/issue-2718-a.stderr
index 7ea620f386a..7ea620f386a 100644
--- a/src/test/ui/issues/issue-2718-a.stderr
+++ b/src/test/ui/structs-enums/issue-2718-a.stderr
diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index bfd506c9f6e..8ed62f854f0 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -1,9 +1,6 @@
 error[E0277]: `fn() -> impl Future<Output = ()> {foo}` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9
    |
-LL | async fn foo() {}
-   |          --- consider calling this function
-...
 LL |     bar(foo);
    |     --- ^^^ `fn() -> impl Future<Output = ()> {foo}` is not a future
    |     |
@@ -16,7 +13,7 @@ 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 the function
+help: use parentheses to call this function
    |
 LL |     bar(foo());
    |            ++
@@ -24,8 +21,6 @@ LL |     bar(foo());
 error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
    |
-LL |     let async_closure = async || ();
-   |                         -------- consider calling this closure
 LL |     bar(async_closure);
    |     --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future
    |     |
@@ -38,7 +33,7 @@ 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 the closure
+help: use parentheses to call this closure
    |
 LL |     bar(async_closure());
    |                      ++
diff --git a/src/test/ui/suggestions/call-on-unimplemented-ctor.rs b/src/test/ui/suggestions/call-on-unimplemented-ctor.rs
new file mode 100644
index 00000000000..5f811044eb3
--- /dev/null
+++ b/src/test/ui/suggestions/call-on-unimplemented-ctor.rs
@@ -0,0 +1,17 @@
+fn main() {
+    insert_resource(Marker);
+    insert_resource(Time);
+    //~^ ERROR the trait bound `fn(u32) -> Time {Time}: Resource` is not satisfied
+    //~| HELP use parentheses to construct this tuple struct
+}
+
+trait Resource {}
+
+fn insert_resource<R: Resource>(resource: R) {}
+
+struct Marker;
+impl Resource for Marker {}
+
+struct Time(u32);
+
+impl Resource for Time {}
diff --git a/src/test/ui/suggestions/call-on-unimplemented-ctor.stderr b/src/test/ui/suggestions/call-on-unimplemented-ctor.stderr
new file mode 100644
index 00000000000..58612cbfb23
--- /dev/null
+++ b/src/test/ui/suggestions/call-on-unimplemented-ctor.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `fn(u32) -> Time {Time}: Resource` is not satisfied
+  --> $DIR/call-on-unimplemented-ctor.rs:3:21
+   |
+LL |     insert_resource(Time);
+   |     --------------- ^^^^ the trait `Resource` is not implemented for fn item `fn(u32) -> Time {Time}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `insert_resource`
+  --> $DIR/call-on-unimplemented-ctor.rs:10:23
+   |
+LL | fn insert_resource<R: Resource>(resource: R) {}
+   |                       ^^^^^^^^ required by this bound in `insert_resource`
+help: use parentheses to construct this tuple struct
+   |
+LL |     insert_resource(Time(/* u32 */));
+   |                         +++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/call-on-unimplemented-fn-ptr.rs b/src/test/ui/suggestions/call-on-unimplemented-fn-ptr.rs
new file mode 100644
index 00000000000..86490c724e0
--- /dev/null
+++ b/src/test/ui/suggestions/call-on-unimplemented-fn-ptr.rs
@@ -0,0 +1,15 @@
+struct Foo;
+
+trait Bar {}
+
+impl Bar for Foo {}
+
+fn needs_bar<T: Bar>(_: T) {}
+
+fn blah(f: fn() -> Foo) {
+    needs_bar(f);
+    //~^ ERROR the trait bound `fn() -> Foo: Bar` is not satisfied
+    //~| HELP use parentheses to call this function pointer
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/call-on-unimplemented-fn-ptr.stderr b/src/test/ui/suggestions/call-on-unimplemented-fn-ptr.stderr
new file mode 100644
index 00000000000..167f7e592a9
--- /dev/null
+++ b/src/test/ui/suggestions/call-on-unimplemented-fn-ptr.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `fn() -> Foo: Bar` is not satisfied
+  --> $DIR/call-on-unimplemented-fn-ptr.rs:10:15
+   |
+LL |     needs_bar(f);
+   |     --------- ^ the trait `Bar` is not implemented for `fn() -> Foo`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_bar`
+  --> $DIR/call-on-unimplemented-fn-ptr.rs:7:17
+   |
+LL | fn needs_bar<T: Bar>(_: T) {}
+   |                 ^^^ required by this bound in `needs_bar`
+help: use parentheses to call this function pointer
+   |
+LL |     needs_bar(f());
+   |                ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index fe603b67575..955148315ba 100644
--- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -1,9 +1,6 @@
 error[E0277]: the trait bound `fn() -> impl T<O = ()> {foo}: T` is not satisfied
   --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:9
    |
-LL | fn foo() -> impl T<O=()> { S }
-   |    --- consider calling this function
-...
 LL |     bar(foo);
    |     --- ^^^ the trait `T` is not implemented for fn item `fn() -> impl T<O = ()> {foo}`
    |     |
@@ -14,7 +11,7 @@ note: required by a bound in `bar`
    |
 LL | fn bar(f: impl T<O=()>) {}
    |                ^^^^^^^ required by this bound in `bar`
-help: use parentheses to call the function
+help: use parentheses to call this function
    |
 LL |     bar(foo());
    |            ++
@@ -22,8 +19,6 @@ LL |     bar(foo());
 error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]: T` is not satisfied
   --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:19:9
    |
-LL |     let closure = || S;
-   |                   -- consider calling this closure
 LL |     bar(closure);
    |     --- ^^^^^^^ the trait `T` is not implemented for closure `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]`
    |     |
@@ -34,7 +29,7 @@ note: required by a bound in `bar`
    |
 LL | fn bar(f: impl T<O=()>) {}
    |                ^^^^^^^ required by this bound in `bar`
-help: use parentheses to call the closure
+help: use parentheses to call this closure
    |
 LL |     bar(closure());
    |                ++
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index f05dba1d4ca..597dc61c3f7 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -49,7 +49,7 @@ LL |     let _: S = S;
    |
    = note: expected struct `S`
              found fn item `fn(usize, usize) -> S {S}`
-help: use parentheses to instantiate this tuple struct
+help: use parentheses to construct this tuple struct
    |
 LL |     let _: S = S(/* usize */, /* usize */);
    |                 ++++++++++++++++++++++++++
@@ -85,7 +85,7 @@ LL |     let _: V = V;
    |
    = note: expected struct `V`
              found fn item `fn() -> V {V}`
-help: use parentheses to instantiate this tuple struct
+help: use parentheses to construct this tuple struct
    |
 LL |     let _: V = V();
    |                 ++
@@ -139,7 +139,7 @@ LL |     let _: E = E::A;
    |
    = note: expected enum `E`
            found fn item `fn(usize) -> E {E::A}`
-help: use parentheses to instantiate this tuple variant
+help: use parentheses to construct this tuple variant
    |
 LL |     let _: E = E::A(/* usize */);
    |                    +++++++++++++
diff --git a/src/test/ui/suggestions/issue-103112.rs b/src/test/ui/suggestions/issue-103112.rs
new file mode 100644
index 00000000000..111ae7c7308
--- /dev/null
+++ b/src/test/ui/suggestions/issue-103112.rs
@@ -0,0 +1,4 @@
+fn main() {
+    std::process::abort!();
+    //~^ ERROR: failed to resolve
+}
diff --git a/src/test/ui/suggestions/issue-103112.stderr b/src/test/ui/suggestions/issue-103112.stderr
new file mode 100644
index 00000000000..4ca7fdf9b5a
--- /dev/null
+++ b/src/test/ui/suggestions/issue-103112.stderr
@@ -0,0 +1,15 @@
+error[E0433]: failed to resolve: could not find `abort` in `process`
+  --> $DIR/issue-103112.rs:2:19
+   |
+LL |     std::process::abort!();
+   |                   ^^^^^ could not find `abort` in `process`
+   |
+help: std::process::abort is not a macro, but a function, try to remove `!`
+   |
+LL -     std::process::abort!();
+LL +     std::process::abort();
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/suggestions/suggest-let-for-assignment.fixed b/src/test/ui/suggestions/suggest-let-for-assignment.fixed
new file mode 100644
index 00000000000..3a25e25eede
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-let-for-assignment.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+
+fn main() {
+    let demo = 1; //~ ERROR cannot find value `demo` in this scope
+    dbg!(demo); //~ ERROR cannot find value `demo` in this scope
+
+    let x = "x"; //~ ERROR cannot find value `x` in this scope
+    println!("x: {}", x); //~ ERROR cannot find value `x` in this scope
+
+    if x == "x" {
+        //~^ ERROR cannot find value `x` in this scope
+        println!("x is 1");
+    }
+
+    let y = 1 + 2; //~ ERROR cannot find value `y` in this scope
+    println!("y: {}", y); //~ ERROR cannot find value `y` in this scope
+}
diff --git a/src/test/ui/suggestions/suggest-let-for-assignment.rs b/src/test/ui/suggestions/suggest-let-for-assignment.rs
new file mode 100644
index 00000000000..67705fe063a
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-let-for-assignment.rs
@@ -0,0 +1,17 @@
+// run-rustfix
+
+fn main() {
+    demo = 1; //~ ERROR cannot find value `demo` in this scope
+    dbg!(demo); //~ ERROR cannot find value `demo` in this scope
+
+    x = "x"; //~ ERROR cannot find value `x` in this scope
+    println!("x: {}", x); //~ ERROR cannot find value `x` in this scope
+
+    if x == "x" {
+        //~^ ERROR cannot find value `x` in this scope
+        println!("x is 1");
+    }
+
+    y = 1 + 2; //~ ERROR cannot find value `y` in this scope
+    println!("y: {}", y); //~ ERROR cannot find value `y` in this scope
+}
diff --git a/src/test/ui/suggestions/suggest-let-for-assignment.stderr b/src/test/ui/suggestions/suggest-let-for-assignment.stderr
new file mode 100644
index 00000000000..3f6a3da4be2
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-let-for-assignment.stderr
@@ -0,0 +1,60 @@
+error[E0425]: cannot find value `demo` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:4:5
+   |
+LL |     demo = 1;
+   |     ^^^^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let demo = 1;
+   |     +++
+
+error[E0425]: cannot find value `demo` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:5:10
+   |
+LL |     dbg!(demo);
+   |          ^^^^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:7:5
+   |
+LL |     x = "x";
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let x = "x";
+   |     +++
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:8:23
+   |
+LL |     println!("x: {}", x);
+   |                       ^ not found in this scope
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:10:8
+   |
+LL |     if x == "x" {
+   |        ^ not found in this scope
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:15:5
+   |
+LL |     y = 1 + 2;
+   |     ^
+   |
+help: you might have meant to introduce a new binding
+   |
+LL |     let y = 1 + 2;
+   |     +++
+
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/suggest-let-for-assignment.rs:16:23
+   |
+LL |     println!("y: {}", y);
+   |                       ^ not found in this scope
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs b/src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs
index ff62d84925f..585874e273d 100644
--- a/src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs
+++ b/src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs
@@ -1,4 +1,5 @@
 // run-pass
+// needs-unwind (#73509)
 
 #![feature(test)]
 
diff --git a/src/test/ui/test-attrs/test-thread-capture.rs b/src/test/ui/test-attrs/test-thread-capture.rs
index edc972837a3..53acca34133 100644
--- a/src/test/ui/test-attrs/test-thread-capture.rs
+++ b/src/test/ui/test-attrs/test-thread-capture.rs
@@ -5,6 +5,7 @@
 // exec-env:RUST_BACKTRACE=0
 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // ignore-emscripten no threads support
+// needs-unwind
 
 #[test]
 fn thready_pass() {
diff --git a/src/test/ui/test-attrs/test-thread-capture.run.stdout b/src/test/ui/test-attrs/test-thread-capture.run.stdout
index 487cfb55eb4..c712a78afb0 100644
--- a/src/test/ui/test-attrs/test-thread-capture.run.stdout
+++ b/src/test/ui/test-attrs/test-thread-capture.run.stdout
@@ -10,7 +10,7 @@ fee
 fie
 foe
 fum
-thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:31:5
+thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:32:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
diff --git a/src/test/ui/test-attrs/test-thread-nocapture.rs b/src/test/ui/test-attrs/test-thread-nocapture.rs
index 8e8e9bbfdf0..2b57eb8aae1 100644
--- a/src/test/ui/test-attrs/test-thread-nocapture.rs
+++ b/src/test/ui/test-attrs/test-thread-nocapture.rs
@@ -5,6 +5,7 @@
 // exec-env:RUST_BACKTRACE=0
 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // ignore-emscripten no threads support
+// needs-unwind
 
 #[test]
 fn thready_pass() {
diff --git a/src/test/ui/test-attrs/test-thread-nocapture.run.stderr b/src/test/ui/test-attrs/test-thread-nocapture.run.stderr
index 06495681b3e..0a12a052819 100644
--- a/src/test/ui/test-attrs/test-thread-nocapture.run.stderr
+++ b/src/test/ui/test-attrs/test-thread-nocapture.run.stderr
@@ -1,2 +1,2 @@
-thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:31:5
+thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:32:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/threads-sendsync/sync-send-in-std.rs b/src/test/ui/threads-sendsync/sync-send-in-std.rs
index b8ae214dc09..6d1fba64e42 100644
--- a/src/test/ui/threads-sendsync/sync-send-in-std.rs
+++ b/src/test/ui/threads-sendsync/sync-send-in-std.rs
@@ -2,6 +2,7 @@
 
 // ignore-wasm32-bare networking not available
 // ignore-sgx ToSocketAddrs cannot be used for DNS Resolution
+// ignore-fuchsia Req. test-harness networking privileges
 
 use std::net::ToSocketAddrs;
 
diff --git a/src/test/ui/traits/issue-33140-hack-boundaries.stderr b/src/test/ui/traits/issue-33140-hack-boundaries.stderr
index 62cfca545b2..58286648d4f 100644
--- a/src/test/ui/traits/issue-33140-hack-boundaries.stderr
+++ b/src/test/ui/traits/issue-33140-hack-boundaries.stderr
@@ -66,3 +66,20 @@ error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0119, E0751.
 For more information about an error, try `rustc --explain E0119`.
+Future incompatibility report: Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait0` for type `(dyn std::marker::Send + 'static)`: (E0119)
+  --> $DIR/issue-33140-hack-boundaries.rs:10:1
+   |
+LL | impl Trait0 for dyn Send {}
+   | ------------------------ first implementation here
+LL | impl Trait0 for dyn Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+  --> $DIR/issue-33140-hack-boundaries.rs:2:10
+   |
+LL | #![allow(order_dependent_trait_objects)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr b/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr
index 4ab777bd4df..0af4df2aecb 100644
--- a/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr
+++ b/src/test/ui/traits/object/issue-33140-traitobject-crate.stderr
@@ -40,3 +40,56 @@ LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
 
 warning: 3 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/issue-33140-traitobject-crate.rs:86:1
+   |
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { }
+   | ------------------------------------------------------ first implementation here
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+  --> $DIR/issue-33140-traitobject-crate.rs:3:9
+   |
+LL | #![warn(order_dependent_trait_objects)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/issue-33140-traitobject-crate.rs:89:1
+   |
+LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { }
+   | ------------------------------------------------------------- first implementation here
+...
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+  --> $DIR/issue-33140-traitobject-crate.rs:3:9
+   |
+LL | #![warn(order_dependent_trait_objects)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/issue-33140-traitobject-crate.rs:93:1
+   |
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { }
+   | ------------------------------------------------------ first implementation here
+...
+LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+note: the lint level is defined here
+  --> $DIR/issue-33140-traitobject-crate.rs:3:9
+   |
+LL | #![warn(order_dependent_trait_objects)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
index 6986ad62172..6986ad62172 100644
--- a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs
+++ b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs
diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
index e9670ad7def..9564813512c 100644
--- a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr
+++ b/src/test/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/multiple-occurence-ambiguousity.rs:21:26
+  --> $DIR/multiple-occurrence-ambiguousity.rs:21:26
    |
 LL |     let t: &dyn Bar<_> = s;
    |            -----------   ^ expected trait `Bar`, found trait `Foo`
diff --git a/src/test/ui/treat-err-as-bug/delay_span_bug.rs b/src/test/ui/treat-err-as-bug/delay_span_bug.rs
index d4d44049c91..832afddf891 100644
--- a/src/test/ui/treat-err-as-bug/delay_span_bug.rs
+++ b/src/test/ui/treat-err-as-bug/delay_span_bug.rs
@@ -1,7 +1,7 @@
 // compile-flags: -Ztreat-err-as-bug
 // failure-status: 101
 // error-pattern: aborting due to `-Z treat-err-as-bug=1`
-// error-pattern: [trigger_delay_span_bug] trigger a delay span bug
+// error-pattern: [trigger_delay_span_bug] triggering a delay span bug
 // normalize-stderr-test "note: .*\n\n" -> ""
 // normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
 // rustc-env:RUST_BACKTRACE=0
diff --git a/src/test/ui/treat-err-as-bug/delay_span_bug.stderr b/src/test/ui/treat-err-as-bug/delay_span_bug.stderr
index c23c2b81b97..e9457c8faff 100644
--- a/src/test/ui/treat-err-as-bug/delay_span_bug.stderr
+++ b/src/test/ui/treat-err-as-bug/delay_span_bug.stderr
@@ -7,5 +7,5 @@ LL | fn main() {}
 error: internal compiler error: unexpected panic
 
 query stack during panic:
-#0 [trigger_delay_span_bug] trigger a delay span bug
+#0 [trigger_delay_span_bug] triggering a delay span bug
 end of query stack
diff --git a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs
index 4f424b8c665..5f75fdc716e 100644
--- a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs
+++ b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs
@@ -1,7 +1,11 @@
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
-type OneLifetime<'a, 'b> = impl std::fmt::Debug;
+pub trait Captures<'a> {}
+
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+type OneLifetime<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
 
 fn foo<'a, 'b>(a: &'a u32, b: &'b u32) -> OneLifetime<'a, 'b> {
     a
diff --git a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr
index 0c50a84e894..546598e8a5c 100644
--- a/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr
+++ b/src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr
@@ -1,11 +1,11 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/different_lifetimes_defining_uses.rs:11:5
+  --> $DIR/different_lifetimes_defining_uses.rs:15:5
    |
 LL |     b
    |     ^ expected `&'a u32`, got `&'b u32`
    |
 note: previous use here
-  --> $DIR/different_lifetimes_defining_uses.rs:7:5
+  --> $DIR/different_lifetimes_defining_uses.rs:11:5
    |
 LL |     a
    |     ^
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs
index c9b9e128f88..9d938a61600 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs
@@ -2,8 +2,11 @@
 
 fn main() {}
 
-type Two<'a, 'b> = impl std::fmt::Debug;
+pub trait Captures<'a> {}
 
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
 
 fn one<'a>(t: &'a ()) -> Two<'a, 'a> {
     t
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr
index 222aaea78d9..72e1ef4b492 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr
@@ -1,13 +1,13 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_lifetime_param.rs:9:5
+  --> $DIR/generic_duplicate_lifetime_param.rs:12:5
    |
 LL |     t
    |     ^
    |
 note: lifetime used multiple times
-  --> $DIR/generic_duplicate_lifetime_param.rs:5:10
+  --> $DIR/generic_duplicate_lifetime_param.rs:9:10
    |
-LL | type Two<'a, 'b> = impl std::fmt::Debug;
+LL | type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
    |          ^^  ^^
 
 error: aborting due to previous error
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
index 093c1c23186..80462f8ac04 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
@@ -7,7 +7,12 @@ fn main() {}
 // test that unused generic parameters are ok
 type TwoTys<T, U> = impl Debug;
 
-type TwoLifetimes<'a, 'b> = impl Debug;
+
+pub trait Captures<'a> {}
+
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>;
 
 type TwoConsts<const X: usize, const Y: usize> = impl Debug;
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
index b2edcc5526a..98e4bfea10d 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
@@ -1,5 +1,5 @@
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:16:5
+  --> $DIR/generic_duplicate_param_use.rs:21:5
    |
 LL |     t
    |     ^
@@ -11,25 +11,25 @@ LL | type TwoTys<T, U> = impl Debug;
    |             ^  ^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:21:5
+  --> $DIR/generic_duplicate_param_use.rs:26:5
    |
 LL |     t
    |     ^
    |
 note: lifetime used multiple times
-  --> $DIR/generic_duplicate_param_use.rs:10:19
+  --> $DIR/generic_duplicate_param_use.rs:15:19
    |
-LL | type TwoLifetimes<'a, 'b> = impl Debug;
+LL | type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>;
    |                   ^^  ^^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:26:5
+  --> $DIR/generic_duplicate_param_use.rs:31:5
    |
 LL |     t
    |     ^
    |
 note: constant used multiple times
-  --> $DIR/generic_duplicate_param_use.rs:12:16
+  --> $DIR/generic_duplicate_param_use.rs:17:16
    |
 LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
    |                ^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^
diff --git a/src/test/ui/type-alias-impl-trait/generic_lifetime_param.rs b/src/test/ui/type-alias-impl-trait/generic_lifetime_param.rs
index e109c38c986..106efefbaf2 100644
--- a/src/test/ui/type-alias-impl-trait/generic_lifetime_param.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_lifetime_param.rs
@@ -1,10 +1,11 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(type_alias_impl_trait)]
 
 fn main() {}
 
-type Region<'a> = impl std::fmt::Debug;
+type Region<'a> = impl std::fmt::Debug + 'a;
+
 
 fn region<'b>(a: &'b ()) -> Region<'b> {
     a
diff --git a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs
index 6e5b8f491ea..07f825aea50 100644
--- a/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs
+++ b/src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs
@@ -1,7 +1,7 @@
 #![feature(type_alias_impl_trait)]
 
 mod test_lifetime_param {
-    type Ty<'a> = impl Sized;
+    type Ty<'a> = impl Sized + 'a;
     fn defining(a: &str) -> Ty<'_> { a }
     fn assert_static<'a: 'static>() {}
     //~^ WARN: unnecessary lifetime parameter `'a`
@@ -10,7 +10,7 @@ mod test_lifetime_param {
 }
 
 mod test_higher_kinded_lifetime_param {
-    type Ty<'a> = impl Sized;
+    type Ty<'a> = impl Sized + 'a;
     fn defining(a: &str) -> Ty<'_> { a }
     fn assert_static<'a: 'static>() {}
     //~^ WARN: unnecessary lifetime parameter `'a`
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.rs b/src/test/ui/type-alias-impl-trait/issue-89686.rs
index de070fc9deb..058417bdb80 100644
--- a/src/test/ui/type-alias-impl-trait/issue-89686.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-89686.rs
@@ -4,7 +4,7 @@
 
 use std::future::Future;
 
-type G<'a, T> = impl Future<Output = ()>;
+type G<'a, T> = impl Future<Output = ()> + 'a;
 
 trait Trait {
     type F: Future<Output = ()>;
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.stderr b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
index b636ada8b75..3b95a575ac2 100644
--- a/src/test/ui/type-alias-impl-trait/issue-89686.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
@@ -6,7 +6,7 @@ LL |         async move { self.f().await }
    |
 help: consider restricting type parameter `T`
    |
-LL | type G<'a, T: Trait> = impl Future<Output = ()>;
+LL | type G<'a, T: Trait> = impl Future<Output = ()> + 'a;
    |             +++++++
 
 error: aborting due to previous error
diff --git a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs
new file mode 100644
index 00000000000..428194058c3
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.rs
@@ -0,0 +1,7 @@
+#![feature(type_alias_impl_trait)]
+
+type Opaque<'a, T> = impl Sized;
+fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
+//~^ ERROR: non-defining opaque type use in defining scope
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
new file mode 100644
index 00000000000..df2b3ed1911
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
@@ -0,0 +1,8 @@
+error: non-defining opaque type use in defining scope
+  --> $DIR/missing_lifetime_bound.rs:4:47
+   |
+LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
+   |                                               ^ lifetime `'a` is part of concrete type but not used in parameter list of the `impl Trait` type alias
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs
index 3f122f10609..65eb2952e0f 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs
@@ -1,6 +1,10 @@
 #![feature(type_alias_impl_trait)]
 
-type Foo<'a, 'b> = impl std::fmt::Debug;
+pub trait Captures<'a> {}
+
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+type Foo<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
 
 fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
     (i, i) //~ ERROR concrete type differs from previous
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr
index 81e603e2355..d7676b8e9b1 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr
@@ -1,5 +1,5 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
+  --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:10:5
    |
 LL |     (i, i)
    |     ^^^^^^
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
index 83fd9a1da45..21fca047a3c 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
@@ -7,7 +7,11 @@ fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>)
     (a.clone(), a)
 }
 
-type Foo<'a, 'b> = impl std::fmt::Debug;
+pub trait Captures<'a> {}
+
+impl<'a, T: ?Sized> Captures<'a> for T {}
+
+type Foo<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
 
 fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
     (i, j)
diff --git a/src/test/ui/typeck/issue-87181/empty-tuple-method.stderr b/src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
index a18c54a29b5..23e7b7cc363 100644
--- a/src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
+++ b/src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
@@ -4,7 +4,7 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the
 LL |     thing.bar.foo();
    |               ^^^ method not found in `fn() -> Foo {Foo}`
    |
-help: use parentheses to instantiate this tuple struct
+help: use parentheses to construct this tuple struct
    |
 LL |     (thing.bar)().foo();
    |     +         +++
diff --git a/src/test/ui/typeck/issue-87181/enum-variant.stderr b/src/test/ui/typeck/issue-87181/enum-variant.stderr
index 90641410d8e..2247ea27021 100644
--- a/src/test/ui/typeck/issue-87181/enum-variant.stderr
+++ b/src/test/ui/typeck/issue-87181/enum-variant.stderr
@@ -4,7 +4,7 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` i
 LL |     thing.bar.foo();
    |               ^^^ method not found in `fn() -> Foo {Foo::Tup}`
    |
-help: use parentheses to instantiate this tuple variant
+help: use parentheses to construct this tuple variant
    |
 LL |     (thing.bar)().foo();
    |     +         +++
diff --git a/src/test/ui/typeck/issue-87181/tuple-field.stderr b/src/test/ui/typeck/issue-87181/tuple-field.stderr
index c1ca26ee9af..0a7d30b615a 100644
--- a/src/test/ui/typeck/issue-87181/tuple-field.stderr
+++ b/src/test/ui/typeck/issue-87181/tuple-field.stderr
@@ -4,7 +4,7 @@ error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
 LL |     thing.bar.0;
    |               ^
    |
-help: use parentheses to instantiate this tuple struct
+help: use parentheses to construct this tuple struct
    |
 LL |     (thing.bar)(/* char */, /* u16 */).0;
    |     +         ++++++++++++++++++++++++
diff --git a/src/test/ui/typeck/slow-lhs-suggestion.rs b/src/test/ui/typeck/slow-lhs-suggestion.rs
new file mode 100644
index 00000000000..80dfd683524
--- /dev/null
+++ b/src/test/ui/typeck/slow-lhs-suggestion.rs
@@ -0,0 +1,26 @@
+fn main() {
+    1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+    //~^ ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/typeck/slow-lhs-suggestion.stderr b/src/test/ui/typeck/slow-lhs-suggestion.stderr
new file mode 100644
index 00000000000..c5bf795eeee
--- /dev/null
+++ b/src/test/ui/typeck/slow-lhs-suggestion.stderr
@@ -0,0 +1,187 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:95
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                                             - ^
+   |                                                                                             |
+   |                                                                                             cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:91
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                                         - ^
+   |                                                                                         |
+   |                                                                                         cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:87
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                                     - ^
+   |                                                                                     |
+   |                                                                                     cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:83
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                                 - ^
+   |                                                                                 |
+   |                                                                                 cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:79
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                             - ^
+   |                                                                             |
+   |                                                                             cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:75
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                         - ^
+   |                                                                         |
+   |                                                                         cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:71
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                     - ^
+   |                                                                     |
+   |                                                                     cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:67
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                                 - ^
+   |                                                                 |
+   |                                                                 cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:63
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                             - ^
+   |                                                             |
+   |                                                             cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:59
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                         - ^
+   |                                                         |
+   |                                                         cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:55
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                     - ^
+   |                                                     |
+   |                                                     cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:51
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                                 - ^
+   |                                                 |
+   |                                                 cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:47
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                             - ^
+   |                                             |
+   |                                             cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:43
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                         - ^
+   |                                         |
+   |                                         cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:39
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                     - ^
+   |                                     |
+   |                                     cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:35
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                                 - ^
+   |                                 |
+   |                                 cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:31
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                             - ^
+   |                             |
+   |                             cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:27
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                         - ^
+   |                         |
+   |                         cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:23
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                     - ^
+   |                     |
+   |                     cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:19
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |                 - ^
+   |                 |
+   |                 cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:15
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |             - ^
+   |             |
+   |             cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:11
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |         - ^
+   |         |
+   |         cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/slow-lhs-suggestion.rs:2:7
+   |
+LL |     1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1 = 1;
+   |     - ^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to 23 previous errors
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject b332991a57c9d055f1864de1eed93e2178d4944
+Subproject 071eeaf210708219a5a1b2c4728ca2f97df7f2a
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index eb0455ae404..c9a8307eba4 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_hir;
 use rustc_hir::intravisit;
 use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
-use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
@@ -178,7 +178,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
 
     fn fake_read(
         &mut self,
-        _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
+        _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
         _: FakeReadCause,
         _: HirId,
     ) {
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 2dcefd78763..89ffca8128a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -32,6 +32,7 @@ extern crate rustc_driver;
 extern crate rustc_errors;
 extern crate rustc_hir;
 extern crate rustc_hir_analysis;
+extern crate rustc_hir_typeck;
 extern crate rustc_hir_pretty;
 extern crate rustc_index;
 extern crate rustc_infer;
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index db73ab55b37..91b321c4474 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -4,7 +4,7 @@ use clippy_utils::{get_enclosing_block, higher, path_to_local};
 use if_chain::if_chain;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
-use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::{mir::FakeReadCause, ty};
@@ -115,7 +115,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
 
     fn fake_read(
         &mut self,
-        _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
+        _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
         _: FakeReadCause,
         _: HirId,
     ) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 825ec84b4a8..b8ed9b9ec18 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -69,11 +69,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
                     "only a `panic!` in `if`-then statement",
                     |diag| {
                         // comments can be noisy, do not show them to the user
-                        diag.tool_only_span_suggestion(
-                                    expr.span.shrink_to_lo(),
-                                    "add comments back",
-                                    comments,
-                                    applicability);
+                        if !comments.is_empty() {
+                            diag.tool_only_span_suggestion(
+                                        expr.span.shrink_to_lo(),
+                                        "add comments back",
+                                        comments,
+                                        applicability);
+                        }
                         diag.span_suggestion(
                                     expr.span,
                                     "try instead",
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 6017941452c..5cf88bfc888 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
@@ -8,7 +8,7 @@ use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trai
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
-use rustc_hir_analysis::check::{FnCtxt, Inherited};
+use rustc_hir_typeck::{FnCtxt, Inherited};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 9d26e590086..67debe7e08a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -180,10 +180,13 @@ fn assignment_suggestions<'tcx>(
     let suggestions = assignments
         .iter()
         .flat_map(|assignment| {
-            [
-                assignment.span.until(assignment.rhs_span),
-                assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()),
-            ]
+            let mut spans = vec![assignment.span.until(assignment.rhs_span)];
+
+            if assignment.rhs_span.hi() != assignment.span.hi() {
+                spans.push(assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()));
+            }
+
+            spans
         })
         .map(|span| (span, String::new()))
         .collect::<Vec<(Span, String)>>();
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 7f881e27dd2..9c949a28f44 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
@@ -12,7 +12,7 @@ use rustc_hir::{
     BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
 };
 use rustc_hir::{HirIdMap, HirIdSet};
-use rustc_hir_analysis::expr_use_visitor as euv;
+use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
@@ -342,7 +342,7 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
 
     fn fake_read(
         &mut self,
-        _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
+        _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
         _: FakeReadCause,
         _: HirId,
     ) {
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index c7e964cf23e..ee9fd94064c 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -8,7 +8,7 @@ use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_lint::LateContext;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::BorrowKind;
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 102f7541c8c..70d166c4854 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -1,5 +1,5 @@
 use rustc_hir::Expr;
-use rustc_hir_analysis::check::{cast, FnCtxt, Inherited};
+use rustc_hir_typeck::{cast, FnCtxt, Inherited};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{cast::CastKind, Ty};
 use rustc_span::DUMMY_SP;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index e7e3625c078..7e42fcc6569 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -24,7 +24,7 @@ extern crate rustc_attr;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
 extern crate rustc_hir;
-extern crate rustc_hir_analysis;
+extern crate rustc_hir_typeck;
 extern crate rustc_infer;
 extern crate rustc_lexer;
 extern crate rustc_lint;
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 3c5dd92b9cd..5089987ef72 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -10,7 +10,7 @@ use rustc_ast_pretty::pprust::token_kind_to_string;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind};
-use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::hir::place::ProjectionKind;
@@ -769,8 +769,7 @@ impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic {
 
     fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability) {
         let mut remove_span = item;
-        let hi = cx.sess().source_map().next_point(remove_span).hi();
-        let fmpos = cx.sess().source_map().lookup_byte_offset(hi);
+        let fmpos = cx.sess().source_map().lookup_byte_offset(remove_span.hi());
 
         if let Some(ref src) = fmpos.sf.src {
             let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
@@ -1055,11 +1054,10 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
 
     fn fake_read(
         &mut self,
-        _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
+        _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
         _: FakeReadCause,
         _: HirId,
-    ) {
-    }
+    ) {}
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a15daec7c3c..3b5a9ba8356 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -657,21 +657,18 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
     let mut output = None;
     let lang_items = cx.tcx.lang_items();
 
-    for pred in cx
+    for (pred, _) in cx
         .tcx
         .bound_explicit_item_bounds(ty.item_def_id)
-        .transpose_iter()
-        .map(|x| x.map_bound(|(p, _)| p))
+        .subst_iter_copied(cx.tcx, ty.substs)
     {
-        match pred.0.kind().skip_binder() {
+        match pred.kind().skip_binder() {
             PredicateKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id())) =>
             {
-                let i = pred
-                    .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
-                    .subst(cx.tcx, ty.substs);
+                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
 
                 if inputs.map_or(false, |inputs| inputs != i) {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -684,10 +681,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
-                output = Some(
-                    pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap()))
-                        .subst(cx.tcx, ty.substs),
-                );
+                output = pred.kind().rebind(p.term.ty()).transpose();
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index e32bae6ed1f..000fb51c018 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirIdSet;
 use rustc_hir::{Expr, ExprKind, HirId, Node};
-use rustc_hir_analysis::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -75,11 +75,10 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
 
     fn fake_read(
         &mut self,
-        _: &rustc_hir_analysis::expr_use_visitor::PlaceWithHirId<'tcx>,
+        _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
         _: FakeReadCause,
         _: HirId,
-    ) {
-    }
+    ) {}
 }
 
 pub struct ParamBindingIdCollector {
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index e43635abcd1..79c29c04e05 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -1,3 +1,4 @@
+// needs-asm-support
 // run-rustfix
 
 #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index d999b3b7dc8..2d7985457d8 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // run-rustfix
 
 #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr
index 2ef9966525c..2c4c49d2522 100644
--- a/src/tools/clippy/tests/ui/entry.stderr
+++ b/src/tools/clippy/tests/ui/entry.stderr
@@ -1,5 +1,5 @@
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:24:5
+  --> $DIR/entry.rs:25:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         m.insert(k, v);
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::map-entry` implied by `-D warnings`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:29:5
+  --> $DIR/entry.rs:30:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         if true {
@@ -32,7 +32,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:38:5
+  --> $DIR/entry.rs:39:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         if true {
@@ -55,7 +55,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:47:5
+  --> $DIR/entry.rs:48:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         if true {
@@ -79,7 +79,7 @@ LL +     }
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:57:5
+  --> $DIR/entry.rs:58:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         foo();
@@ -96,7 +96,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:63:5
+  --> $DIR/entry.rs:64:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         match 0 {
@@ -122,7 +122,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:75:5
+  --> $DIR/entry.rs:76:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         match 0 {
@@ -146,7 +146,7 @@ LL +     }
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:85:5
+  --> $DIR/entry.rs:86:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         foo();
@@ -187,7 +187,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:119:5
+  --> $DIR/entry.rs:120:5
    |
 LL | /     if !m.contains_key(&m!(k)) {
 LL | |         m.insert(m!(k), m!(v));
@@ -195,7 +195,7 @@ LL | |     }
    | |_____^ help: try this: `m.entry(m!(k)).or_insert_with(|| m!(v));`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:151:5
+  --> $DIR/entry.rs:152:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         let x = (String::new(), String::new());
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 7718588fdf6..237638ee134 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -4,13 +4,9 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qaqaq{:?}", a);
 LL | |     }
-   | |_____^
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);`
    |
    = note: `-D clippy::manual-assert` implied by `-D warnings`
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qaqaq{:?}", a);
-   |
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:34:5
@@ -18,12 +14,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qwqwq");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qwqwq");
-   |
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:51:5
@@ -31,12 +22,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() {
 LL | |         panic!("panic1");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!b.is_empty(), "panic1");
-   |
+   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:54:5
@@ -44,12 +30,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |         panic!("panic2");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() && a.is_empty()), "panic2");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:57:5
@@ -57,12 +38,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |         panic!("panic3");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:60:5
@@ -70,12 +46,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |         panic!("panic4");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() || a.is_empty()), "panic4");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:63:5
@@ -83,12 +54,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |         panic!("panic5");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:66:5
@@ -96,12 +62,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() {
 LL | |         panic!("with expansion {}", one!())
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!a.is_empty(), "with expansion {}", one!());
-   |
+   | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:73:5
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 7718588fdf6..237638ee134 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -4,13 +4,9 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qaqaq{:?}", a);
 LL | |     }
-   | |_____^
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);`
    |
    = note: `-D clippy::manual-assert` implied by `-D warnings`
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qaqaq{:?}", a);
-   |
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:34:5
@@ -18,12 +14,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qwqwq");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qwqwq");
-   |
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:51:5
@@ -31,12 +22,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() {
 LL | |         panic!("panic1");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!b.is_empty(), "panic1");
-   |
+   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:54:5
@@ -44,12 +30,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |         panic!("panic2");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() && a.is_empty()), "panic2");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:57:5
@@ -57,12 +38,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |         panic!("panic3");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:60:5
@@ -70,12 +46,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |         panic!("panic4");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() || a.is_empty()), "panic4");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:63:5
@@ -83,12 +54,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |         panic!("panic5");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:66:5
@@ -96,12 +62,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() {
 LL | |         panic!("with expansion {}", one!())
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!a.is_empty(), "with expansion {}", one!());
-   |
+   | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:73:5
diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
index 29cc026a8fd..590ad63c90b 100644
--- a/src/tools/clippy/tests/ui/missing_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_doc.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // aux-build: proc_macro_with_span.rs
 
 #![warn(clippy::missing_docs_in_private_items)]
diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr
index 6c8e66f4643..d3bef28bf64 100644
--- a/src/tools/clippy/tests/ui/missing_doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> $DIR/missing_doc.rs:15:1
+  --> $DIR/missing_doc.rs:16:1
    |
 LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | type Typedef = String;
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a type alias
-  --> $DIR/missing_doc.rs:16:1
+  --> $DIR/missing_doc.rs:17:1
    |
 LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing_doc.rs:18:1
+  --> $DIR/missing_doc.rs:19:1
    |
 LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing_doc.rs:19:1
+  --> $DIR/missing_doc.rs:20:1
    |
 LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:23:1
+  --> $DIR/missing_doc.rs:24:1
    |
 LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:24:1
+  --> $DIR/missing_doc.rs:25:1
    |
 LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing_doc.rs:38:1
+  --> $DIR/missing_doc.rs:39:1
    |
 LL | / enum Baz {
 LL | |     BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing_doc.rs:39:5
+  --> $DIR/missing_doc.rs:40:5
    |
 LL |     BazA { a: isize, b: isize },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing_doc.rs:39:12
+  --> $DIR/missing_doc.rs:40:12
    |
 LL |     BazA { a: isize, b: isize },
    |            ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing_doc.rs:39:22
+  --> $DIR/missing_doc.rs:40:22
    |
 LL |     BazA { a: isize, b: isize },
    |                      ^^^^^^^^
 
 error: missing documentation for a variant
-  --> $DIR/missing_doc.rs:40:5
+  --> $DIR/missing_doc.rs:41:5
    |
 LL |     BarB,
    |     ^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing_doc.rs:43:1
+  --> $DIR/missing_doc.rs:44:1
    |
 LL | / pub enum PubBaz {
 LL | |     PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing_doc.rs:44:5
+  --> $DIR/missing_doc.rs:45:5
    |
 LL |     PubBazA { a: isize },
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing_doc.rs:44:15
+  --> $DIR/missing_doc.rs:45:15
    |
 LL |     PubBazA { a: isize },
    |               ^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing_doc.rs:64:1
+  --> $DIR/missing_doc.rs:65:1
    |
 LL | const FOO: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing_doc.rs:71:1
+  --> $DIR/missing_doc.rs:72:1
    |
 LL | pub const FOO4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing_doc.rs:73:1
+  --> $DIR/missing_doc.rs:74:1
    |
 LL | static BAR: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing_doc.rs:80:1
+  --> $DIR/missing_doc.rs:81:1
    |
 LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing_doc.rs:82:1
+  --> $DIR/missing_doc.rs:83:1
    |
 LL | / mod internal_impl {
 LL | |     /// dox
@@ -126,31 +126,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:85:5
+  --> $DIR/missing_doc.rs:86:5
    |
 LL |     pub fn undocumented1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:86:5
+  --> $DIR/missing_doc.rs:87:5
    |
 LL |     pub fn undocumented2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:87:5
+  --> $DIR/missing_doc.rs:88:5
    |
 LL |     fn undocumented3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:92:9
+  --> $DIR/missing_doc.rs:93:9
    |
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:93:9
+  --> $DIR/missing_doc.rs:94:9
    |
 LL |         fn also_undocumented2() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 6f852275003..0d9a629e179 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -4,6 +4,7 @@ use std::fs::File;
 use std::io::prelude::*;
 use std::io::BufReader;
 use std::path::{Path, PathBuf};
+use std::process::Command;
 
 use tracing::*;
 
@@ -843,6 +844,20 @@ pub fn extract_llvm_version(version: &str) -> Option<u32> {
     Some(version)
 }
 
+pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
+    let output = Command::new(binary_path).arg("--version").output().ok()?;
+    if !output.status.success() {
+        return None;
+    }
+    let version = String::from_utf8(output.stdout).ok()?;
+    for line in version.lines() {
+        if let Some(version) = line.split("LLVM version ").skip(1).next() {
+            return extract_llvm_version(version);
+        }
+    }
+    None
+}
+
 /// Takes a directive of the form "<version1> [- <version2>]",
 /// returns the numeric representation of <version1> and <version2> as
 /// tuple: (<version1> as u32, <version2> as u32)
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index b48395035d4..a8cf6623f35 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -200,7 +200,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
         Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
     };
     let llvm_version =
-        matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version);
+        matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else(
+            || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
+        );
 
     let src_base = opt_path(matches, "src-base");
     let run_ignored = matches.opt_present("ignored");
@@ -395,6 +397,8 @@ pub fn run_tests(config: Config) {
         make_tests(c, &mut tests);
     }
 
+    tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
+
     let res = test::run_tests_console(&opts, tests);
     match res {
         Ok(true) => {}
diff --git a/src/tools/miri/tests/pass-dep/shims/fs.rs b/src/tools/miri/tests/pass-dep/shims/fs.rs
index 9faced02916..e573d330aa4 100644
--- a/src/tools/miri/tests/pass-dep/shims/fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/fs.rs
@@ -4,7 +4,8 @@
 #![feature(io_error_more)]
 #![feature(io_error_uncategorized)]
 
-use std::ffi::CString;
+use std::collections::HashMap;
+use std::ffi::{CString, OsString};
 use std::fs::{
     create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename, File,
     OpenOptions,
@@ -394,21 +395,34 @@ fn test_directory() {
     // Creating a directory when it already exists should fail.
     assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind());
 
-    // Create some files inside the directory
+    // Create some files and dirs inside the directory
     let path_1 = dir_path.join("test_file_1");
     drop(File::create(&path_1).unwrap());
     let path_2 = dir_path.join("test_file_2");
     drop(File::create(&path_2).unwrap());
-    // Test that the files are present inside the directory
-    let dir_iter = read_dir(&dir_path).unwrap();
-    let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
-    file_names.sort_unstable();
-    assert_eq!(file_names, vec!["test_file_1", "test_file_2"]);
+    let dir_1 = dir_path.join("test_dir_1");
+    create_dir(&dir_1).unwrap();
+    // Test that read_dir metadata calls succeed
+    assert_eq!(
+        HashMap::from([
+            (OsString::from("test_file_1"), true),
+            (OsString::from("test_file_2"), true),
+            (OsString::from("test_dir_1"), false)
+        ]),
+        read_dir(&dir_path)
+            .unwrap()
+            .map(|e| {
+                let e = e.unwrap();
+                (e.file_name(), e.metadata().unwrap().is_file())
+            })
+            .collect::<HashMap<_, _>>()
+    );
     // Deleting the directory should fail, since it is not empty.
     assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind());
     // Clean up the files in the directory
     remove_file(&path_1).unwrap();
     remove_file(&path_2).unwrap();
+    remove_dir(&dir_1).unwrap();
     // Now there should be nothing left in the directory.
     let dir_iter = read_dir(&dir_path).unwrap();
     let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs
index bed9d39161d..ec992da6812 100644
--- a/src/tools/remote-test-server/src/main.rs
+++ b/src/tools/remote-test-server/src/main.rs
@@ -74,7 +74,11 @@ impl Config {
                 "--bind" => next_is_bind = true,
                 "--sequential" => config.sequential = true,
                 "--verbose" | "-v" => config.verbose = true,
-                arg => panic!("unknown argument: {}", arg),
+                "--help" | "-h" => {
+                    show_help();
+                    std::process::exit(0);
+                }
+                arg => panic!("unknown argument: {}, use `--help` for known arguments", arg),
             }
         }
         if next_is_bind {
@@ -85,6 +89,22 @@ impl Config {
     }
 }
 
+fn show_help() {
+    eprintln!(
+        r#"Usage:
+
+{} [OPTIONS]
+
+OPTIONS:
+    --bind <IP>:<PORT>   Specify IP address and port to listen for requests, e.g. "0.0.0.0:12345"
+    --sequential         Run only one test at a time
+    -v, --verbose        Show status messages
+    -h, --help           Show this help screen
+"#,
+        std::env::args().next().unwrap()
+    );
+}
+
 fn print_verbose(s: &str, conf: Config) {
     if conf.verbose {
         println!("{}", s);
@@ -92,9 +112,8 @@ fn print_verbose(s: &str, conf: Config) {
 }
 
 fn main() {
-    println!("starting test server");
-
     let config = Config::parse_args();
+    println!("starting test server");
 
     let listener = t!(TcpListener::bind(config.bind));
     let (work, tmp): (PathBuf, PathBuf) = if cfg!(target_os = "android") {
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 1563ee0b143..bb77324378a 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -43,14 +43,31 @@ jobs:
           rustup component add rustfmt rust-src
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+        uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
 
-      - name: Compile
+      - name: Bump opt-level
+        if: matrix.os == 'ubuntu-latest'
+        run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml
+
+      - name: Compile (tests)
         run: cargo test --no-run --locked
 
+      # It's faster to `test` before `build` ¯\_(ツ)_/¯
+      - name: Compile (rust-analyzer)
+        if: matrix.os == 'ubuntu-latest'
+        run: cargo build --quiet
+
       - name: Test
         run: cargo test -- --nocapture --quiet
 
+      - name: Run analysis-stats on rust-analyzer
+        if: matrix.os == 'ubuntu-latest'
+        run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats .
+
+      - name: Run analysis-stats on rust std library
+        if: matrix.os == 'ubuntu-latest'
+        run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
+
   # Weird targets to catch non-portable code
   rust-cross:
     if: github.repository == 'rust-lang/rust-analyzer'
@@ -73,7 +90,7 @@ jobs:
           rustup target add ${{ env.targets }} ${{ env.targets_ide }}
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+        uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
 
       - name: Check
         run: |
@@ -99,9 +116,9 @@ jobs:
         uses: actions/checkout@v3
 
       - name: Install Nodejs
-        uses: actions/setup-node@v1
+        uses: actions/setup-node@v3
         with:
-          node-version: 16.x
+          node-version: 16
 
       - name: Install xvfb
         if: matrix.os == 'ubuntu-latest'
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index f4d472e3d5c..422fe29f9d5 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -76,9 +76,9 @@ jobs:
           rustup component add rust-src
 
       - name: Install Node.js
-        uses: actions/setup-node@v1
+        uses: actions/setup-node@v3
         with:
-          node-version: 16.x
+          node-version: 16
 
       - name: Update apt repositories
         if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
@@ -184,9 +184,9 @@ jobs:
     needs: ["dist", "dist-x86_64-unknown-linux-musl"]
     steps:
       - name: Install Nodejs
-        uses: actions/setup-node@v1
+        uses: actions/setup-node@v3
         with:
-          node-version: 16.x
+          node-version: 16
 
       - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
         if: github.ref == 'refs/heads/release'
@@ -259,6 +259,7 @@ jobs:
         working-directory: ./editors/code
         # token from https://dev.azure.com/rust-analyzer/
         run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
+        timeout-minutes: 2
 
       - name: Publish Extension (Code Marketplace, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
@@ -269,3 +270,4 @@ jobs:
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
         run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
+        timeout-minutes: 2
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 744330b142a..0ddea2f728d 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -37,9 +37,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.62"
+version = "1.0.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
+checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
 
 [[package]]
 name = "anymap"
@@ -49,9 +49,9 @@ checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72"
 
 [[package]]
 name = "arbitrary"
-version = "1.1.3"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
+checksum = "d86fd10d912cab78764cc44307d9cd5f164e09abbeb87fb19fb6d95937e8da5f"
 
 [[package]]
 name = "arrayvec"
@@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.84.0"
+version = "0.86.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf29c109d57f8d57b0e7675391be37a9285d86dd93278bd5f14a0ad3c447a6c2"
+checksum = "5499d415d855b5094366a824815341893ad3de0ecb6048c430118bdae6d27402"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -183,9 +183,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.84.0"
+version = "0.86.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d391763027b5e50a5e15caf6d2857ec585fd68160367bbeac9e1804209620918"
+checksum = "3800118c76a48507b0eece3a01f3a429b5c478d203c493096e6040c67ab960e1"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -194,9 +194,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.84.0"
+version = "0.86.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afafd92dcdc7fe0ea940ee94bdd8cc5bd18f4a4a84c593d6d7025fe16c150478"
+checksum = "1baf60628fd73104d1f8562586a52d48f37f1e84435aab2e62674b1fd935b8c8"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -207,9 +207,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.84.0"
+version = "0.86.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3af1d111f11c91c48ace02e93e470c5bae6d2631bd112e4545317da53660d7fc"
+checksum = "0e9c3c068f9358786348e58a1b94ef0a5cf90a9810fc1f10fda896f0b5d80185"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -270,45 +270,44 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.10"
+version = "0.9.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
+checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
 dependencies = [
  "autocfg",
  "cfg-if",
  "crossbeam-utils",
  "memoffset",
- "once_cell",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.11"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
+checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
 dependencies = [
  "cfg-if",
- "once_cell",
 ]
 
 [[package]]
 name = "dashmap"
-version = "5.3.4"
+version = "5.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f"
+checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
 dependencies = [
  "cfg-if",
  "hashbrown",
  "lock_api",
+ "once_cell",
  "parking_lot_core 0.9.3",
 ]
 
 [[package]]
 name = "derive_arbitrary"
-version = "1.1.3"
+version = "1.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d"
+checksum = "226ad66541d865d7a7173ad6a9e691c33fdb910ac723f4bc734b3e5294a1f931"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -404,11 +403,10 @@ dependencies = [
 
 [[package]]
 name = "form_urlencoded"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
+checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
 dependencies = [
- "matches",
  "percent-encoding",
 ]
 
@@ -546,6 +544,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
+ "chalk-derive",
  "chalk-ir",
  "chalk-recursive",
  "chalk-solve",
@@ -573,9 +572,9 @@ dependencies = [
 
 [[package]]
 name = "home"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
+checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
 dependencies = [
  "winapi",
 ]
@@ -714,11 +713,10 @@ dependencies = [
 
 [[package]]
 name = "idna"
-version = "0.2.3"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
 dependencies = [
- "matches",
  "unicode-bidi",
  "unicode-normalization",
 ]
@@ -764,18 +762,18 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "itoa"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
 
 [[package]]
 name = "jod-thread"
@@ -815,9 +813,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.132"
+version = "0.2.135"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
+checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
 
 [[package]]
 name = "libloading"
@@ -831,9 +829,9 @@ dependencies = [
 
 [[package]]
 name = "libmimalloc-sys"
-version = "0.1.25"
+version = "0.1.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c"
+checksum = "8fc093ab289b0bfda3aa1bdfab9c9542be29c7ef385cfcbe77f8c9813588eb48"
 dependencies = [
  "cc",
 ]
@@ -844,9 +842,9 @@ version = "0.0.0"
 
 [[package]]
 name = "lock_api"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -895,12 +893,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "matches"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
-
-[[package]]
 name = "mbe"
 version = "0.0.0"
 dependencies = [
@@ -941,18 +933,18 @@ dependencies = [
 
 [[package]]
 name = "mimalloc"
-version = "0.1.29"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698"
+checksum = "76ce6a4b40d3bff9eb3ce9881ca0737a85072f9f975886082640cd46a75cdb35"
 dependencies = [
  "libmimalloc-sys",
 ]
 
 [[package]]
 name = "miniz_oxide"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
+checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
 dependencies = [
  "adler",
 ]
@@ -980,9 +972,9 @@ dependencies = [
 
 [[package]]
 name = "notify"
-version = "5.0.0-pre.16"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "530f6314d6904508082f4ea424a0275cf62d341e118b313663f266429cb19693"
+checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a"
 dependencies = [
  "bitflags",
  "crossbeam-channel",
@@ -1017,9 +1009,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.13.1"
+version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
+checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
 
 [[package]]
 name = "oorandom"
@@ -1088,9 +1080,9 @@ dependencies = [
 
 [[package]]
 name = "paste"
-version = "1.0.8"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
+checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
 
 [[package]]
 name = "paths"
@@ -1098,9 +1090,9 @@ version = "0.0.0"
 
 [[package]]
 name = "percent-encoding"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
 
 [[package]]
 name = "perf-event"
@@ -1190,9 +1182,9 @@ version = "0.0.0"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.46"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
 dependencies = [
  "unicode-ident",
 ]
@@ -1265,9 +1257,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark-to-cmark"
-version = "10.0.2"
+version = "10.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913"
+checksum = "0194e6e1966c23cc5fd988714f85b18d548d773e81965413555d96569931833d"
 dependencies = [
  "pulldown-cmark",
 ]
@@ -1340,9 +1332,9 @@ checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 
 [[package]]
 name = "rowan"
-version = "0.15.8"
+version = "0.15.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8"
+checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332"
 dependencies = [
  "countme",
  "hashbrown",
@@ -1493,27 +1485,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "semver"
-version = "1.0.13"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.144"
+version = "1.0.145"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
+checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.144"
+version = "1.0.145"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
+checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1522,9 +1514,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
 dependencies = [
  "indexmap",
  "itoa",
@@ -1554,9 +1546,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
 
 [[package]]
 name = "smol_str"
@@ -1666,18 +1658,18 @@ checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a"
 
 [[package]]
 name = "thiserror"
-version = "1.0.31"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.31"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1715,9 +1707,9 @@ dependencies = [
 
 [[package]]
 name = "tikv-jemalloc-sys"
-version = "0.5.1+5.3.0-patched"
+version = "0.5.2+5.3.0-patched"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261"
+checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3"
 dependencies = [
  "cc",
  "fs_extra",
@@ -1758,9 +1750,9 @@ dependencies = [
 
 [[package]]
 name = "tracing"
-version = "0.1.36"
+version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
 dependencies = [
  "cfg-if",
  "pin-project-lite",
@@ -1770,9 +1762,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.22"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
+checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1781,9 +1773,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.29"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
+checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
 dependencies = [
  "once_cell",
  "valuable",
@@ -1802,9 +1794,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.15"
+version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
+checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
 dependencies = [
  "matchers",
  "once_cell",
@@ -1866,40 +1858,39 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.1"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.21"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
 dependencies = [
  "tinyvec",
 ]
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
+checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
 
 [[package]]
 name = "url"
-version = "2.2.2"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
+checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
 dependencies = [
  "form_urlencoded",
  "idna",
- "matches",
  "percent-encoding",
  "serde",
 ]
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 6b68ca82389..286ef1e7dcb 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -27,6 +27,7 @@ debug = 0
 # chalk-solve = { path = "../chalk/chalk-solve" }
 # chalk-ir = { path = "../chalk/chalk-ir" }
 # chalk-recursive = { path = "../chalk/chalk-recursive" }
+# chalk-derive = { path = "../chalk/chalk-derive" }
 
 # ungrammar = { path = "../ungrammar" }
 
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index c9664a83ab8..ee1ad677a95 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -22,5 +22,5 @@ oorandom = "11.1.3"
 # We depend on both individually instead of using `features = ["derive"]` to microoptimize the
 # build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
 # supports `arbitrary`. This way, we avoid feature unification.
-arbitrary = "1.1.0"
-derive_arbitrary = "1.1.0"
+arbitrary = "1.1.7"
+derive_arbitrary = "1.1.6"
diff --git a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml
index 688e790c536..2ad32d24837 100644
--- a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml
@@ -11,11 +11,11 @@ doctest = false
 
 [dependencies]
 crossbeam-channel = "0.5.5"
-tracing = "0.1.35"
+tracing = "0.1.37"
 cargo_metadata = "0.15.0"
 rustc-hash = "1.1.0"
 serde = { version = "1.0.137", features = ["derive"] }
-serde_json = "1.0.81"
+serde_json = "1.0.86"
 jod-thread = "0.1.2"
 
 toolchain = { path = "../toolchain", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index e8cff2f3e6c..4ad8e75970b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -15,17 +15,17 @@ arrayvec = "0.7.2"
 bitflags = "1.3.2"
 cov-mark = "2.0.0-pre.1"
 # We need to freeze the version of the crate, as the raw-api feature is considered unstable
-dashmap = { version = "=5.3.4", features = ["raw-api"] }
+dashmap = { version = "=5.4.0", features = ["raw-api"] }
 drop_bomb = "0.1.5"
 either = "1.7.0"
 fst = { version = "0.4.7", default-features = false }
 hashbrown = { version = "0.12.1", default-features = false }
 indexmap = "1.9.1"
-itertools = "0.10.3"
+itertools = "0.10.5"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.12.0"
+once_cell = "1.15.0"
 rustc-hash = "1.1.0"
-smallvec = "1.9.0"
+smallvec = "1.10.0"
 tracing = "0.1.35"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 2dc7714bbb5..759f3b8c04b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -311,7 +311,20 @@ impl Body {
             DefWithBodyId::FunctionId(f) => {
                 let f = f.lookup(db);
                 let src = f.source(db);
-                params = src.value.param_list();
+                params = src.value.param_list().map(|param_list| {
+                    let item_tree = f.id.item_tree(db);
+                    let func = &item_tree[f.id.value];
+                    let krate = f.container.module(db).krate;
+                    let crate_graph = db.crate_graph();
+                    (
+                        param_list,
+                        func.params.clone().map(move |param| {
+                            item_tree
+                                .attrs(db, krate, param.into())
+                                .is_cfg_enabled(&crate_graph[krate].cfg_options)
+                        }),
+                    )
+                });
                 (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
             }
             DefWithBodyId::ConstId(c) => {
@@ -334,6 +347,7 @@ impl Body {
         let expander = Expander::new(db, file_id, module);
         let (mut body, source_map) = Body::new(db, expander, params, body);
         body.shrink_to_fit();
+
         (Arc::new(body), Arc::new(source_map))
     }
 
@@ -370,7 +384,7 @@ impl Body {
     fn new(
         db: &dyn DefDatabase,
         expander: Expander,
-        params: Option<ast::ParamList>,
+        params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
         body: Option<ast::Expr>,
     ) -> (Body, BodySourceMap) {
         lower::lower(db, expander, params, body)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index c4f91e49a6e..ccc01c3efca 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -77,7 +77,7 @@ impl<'a> LowerCtx<'a> {
 pub(super) fn lower(
     db: &dyn DefDatabase,
     expander: Expander,
-    params: Option<ast::ParamList>,
+    params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
     body: Option<ast::Expr>,
 ) -> (Body, BodySourceMap) {
     ExprCollector {
@@ -119,11 +119,13 @@ struct ExprCollector<'a> {
 impl ExprCollector<'_> {
     fn collect(
         mut self,
-        param_list: Option<ast::ParamList>,
+        param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
         body: Option<ast::Expr>,
     ) -> (Body, BodySourceMap) {
-        if let Some(param_list) = param_list {
-            if let Some(self_param) = param_list.self_param() {
+        if let Some((param_list, mut attr_enabled)) = param_list {
+            if let Some(self_param) =
+                param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
+            {
                 let ptr = AstPtr::new(&self_param);
                 let param_pat = self.alloc_pat(
                     Pat::Bind {
@@ -139,7 +141,11 @@ impl ExprCollector<'_> {
                 self.body.params.push(param_pat);
             }
 
-            for pat in param_list.params().filter_map(|param| param.pat()) {
+            for pat in param_list
+                .params()
+                .zip(attr_enabled)
+                .filter_map(|(param, enabled)| param.pat().filter(|_| enabled))
+            {
                 let param_pat = self.collect_pat(pat);
                 self.body.params.push(param_pat);
             }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 4f626105a53..c04cd165192 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -93,12 +93,12 @@ macro_rules! option_env {() => {}}
 
 fn main() { option_env!("TEST_ENV_VAR"); }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! option_env {() => {}}
 
-fn main() { std::option::Option::None:: < &str>; }
-"##]],
+fn main() { $crate::option::Option::None:: < &str>; }
+"#]],
     );
 }
 
@@ -191,7 +191,7 @@ fn main() {
     format_args!("{} {:?}", arg1(a, b, c), arg2);
 }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! format_args {
     ($fmt:expr) => ({ /* compiler built-in */ });
@@ -199,9 +199,9 @@ macro_rules! format_args {
 }
 
 fn main() {
-    std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a, b, c)), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(arg2), std::fmt::Display::fmt), ]);
+    $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]);
 }
-"##]],
+"#]],
     );
 }
 
@@ -219,7 +219,7 @@ fn main() {
     format_args!("{} {:?}", a::<A,B>(), b);
 }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! format_args {
     ($fmt:expr) => ({ /* compiler built-in */ });
@@ -227,9 +227,9 @@ macro_rules! format_args {
 }
 
 fn main() {
-    std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A, B>()), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(b), std::fmt::Display::fmt), ]);
+    $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]);
 }
-"##]],
+"#]],
     );
 }
 
@@ -248,7 +248,7 @@ fn main() {
         format_args!/*+errors*/("{} {:?}", a.);
 }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! format_args {
     ($fmt:expr) => ({ /* compiler built-in */ });
@@ -258,9 +258,9 @@ macro_rules! format_args {
 fn main() {
     let _ =
         /* parse error: expected field name or number */
-std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a.), std::fmt::Display::fmt), ]);
+$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]);
 }
-"##]],
+"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
index dfd470ffca6..3359c99b396 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
@@ -15,11 +15,11 @@ tracing = "0.1.35"
 either = "1.7.0"
 rustc-hash = "1.1.0"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-itertools = "0.10.3"
+itertools = "0.10.5"
 hashbrown = { version = "0.12.1", features = [
     "inline-more",
 ], default-features = false }
-smallvec = { version = "1.9.0", features = ["const_new"] }
+smallvec = { version = "1.10.0", features = ["const_new"] }
 
 stdx = { path = "../stdx", version = "0.0.0" }
 base-db = { path = "../base-db", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 8befa7f7da7..7b19518e25a 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -238,9 +238,9 @@ fn format_args_expand(
 ) -> ExpandResult<tt::Subtree> {
     // We expand `format_args!("", a1, a2)` to
     // ```
-    // std::fmt::Arguments::new_v1(&[], &[
-    //   std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
-    //   std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
+    // $crate::fmt::Arguments::new_v1(&[], &[
+    //   $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt),
+    //   $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt),
     // ])
     // ```,
     // which is still not really correct, but close enough for now
@@ -262,10 +262,10 @@ fn format_args_expand(
     }
     let _format_string = args.remove(0);
     let arg_tts = args.into_iter().flat_map(|arg| {
-        quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
+        quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), }
     }.token_trees);
     let expanded = quote! {
-        std::fmt::Arguments::new_v1(&[], &[##arg_tts])
+        #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts])
     };
     ExpandResult::ok(expanded)
 }
@@ -675,8 +675,8 @@ fn option_env_expand(
     };
 
     let expanded = match get_env_inner(db, arg_id, &key) {
-        None => quote! { std::option::Option::None::<&str> },
-        Some(s) => quote! { std::option::Some(#s) },
+        None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> },
+        Some(s) => quote! { #DOLLAR_CRATE::option::Some(#s) },
     };
 
     ExpandResult::ok(ExpandedEager::new(expanded))
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index bc97ee15c7d..87e4db03984 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -221,8 +221,16 @@ pub fn expand_speculative(
     fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
     let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
 
-    let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
-    let token = node.syntax_node().covering_element(range).into_token()?;
+    let syntax_node = node.syntax_node();
+    let token = rev_tmap
+        .ranges_by_token(token_id, token_to_map.kind())
+        .filter_map(|range| syntax_node.covering_element(range).into_token())
+        .min_by_key(|t| {
+            // prefer tokens of the same kind and text
+            // Note the inversion of the score here, as we want to prefer the first token in case
+            // of all tokens having the same score
+            (t.kind() != token_to_map.kind()) as u8 + (t.text() != token_to_map.text()) as u8
+        })?;
     Some((node.syntax_node(), token))
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index d7586d129b7..68413df420c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -259,6 +259,7 @@ macro_rules! __known_path {
     (core::future::Future) => {};
     (core::future::IntoFuture) => {};
     (core::ops::Try) => {};
+    (core::ops::FromResidual) => {};
     ($path:path) => {
         compile_error!("Please register your known path in the path module")
     };
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 2679a1c3602..8a735b965ab 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -279,6 +279,8 @@ pub mod known {
         RangeToInclusive,
         RangeTo,
         Range,
+        Residual,
+        FromResidual,
         Neg,
         Not,
         None,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 7f143f396c7..ed13275bab8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -11,18 +11,19 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.3"
+itertools = "0.10.5"
 arrayvec = "0.7.2"
-smallvec = "1.9.0"
+smallvec = "1.10.0"
 ena = "0.14.0"
 tracing = "0.1.35"
 rustc-hash = "1.1.0"
 scoped-tls = "1.0.0"
-chalk-solve = { version = "0.84.0", default-features = false }
-chalk-ir = "0.84.0"
-chalk-recursive = { version = "0.84.0", default-features = false }
+chalk-solve = { version = "0.86.0", default-features = false }
+chalk-ir = "0.86.0"
+chalk-recursive = { version = "0.86.0", default-features = false }
+chalk-derive = "0.86.0"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.12.0"
+once_cell = "1.15.0"
 typed-arena = "2.0.1"
 
 stdx = { path = "../stdx", version = "0.0.0" }
@@ -37,7 +38,7 @@ limit = { path = "../limit", version = "0.0.0" }
 test-utils = { path = "../test-utils" }
 expect-test = "1.4.0"
 tracing = "0.1.35"
-tracing-subscriber = { version = "0.3.14", default-features = false, features = [
+tracing-subscriber = { version = "0.3.16", default-features = false, features = [
     "env-filter",
     "registry",
 ] }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 3f3f8f7d0f2..43c3451cab3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -823,10 +823,10 @@ pub(super) fn generic_predicate_to_inline_bound(
             Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
         }
         WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
-            if projection_ty.self_type_parameter(Interner) != self_ty_shifted_in {
+            let trait_ = projection_ty.trait_(db);
+            if projection_ty.self_type_parameter(db) != self_ty_shifted_in {
                 return None;
             }
-            let trait_ = projection_ty.trait_(db);
             let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
                 .iter()
                 .map(|ty| ty.clone().cast(Interner))
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 4f0e9dbf1e4..e2099d7e509 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -262,7 +262,7 @@ impl TyExt for Ty {
                                     WhereClause::AliasEq(AliasEq {
                                         alias: AliasTy::Projection(proj),
                                         ty: _,
-                                    }) => &proj.self_type_parameter(Interner) == self,
+                                    }) => &proj.self_type_parameter(db) == self,
                                     _ => false,
                                 })
                                 .collect::<Vec<_>>();
@@ -333,6 +333,7 @@ impl TyExt for Ty {
 pub trait ProjectionTyExt {
     fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
     fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
+    fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
 }
 
 impl ProjectionTyExt for ProjectionTy {
@@ -349,6 +350,10 @@ impl ProjectionTyExt for ProjectionTy {
             _ => panic!("projection ty without parent trait"),
         }
     }
+
+    fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
+        self.trait_ref(db).self_type_parameter(Interner)
+    }
 }
 
 pub trait TraitRefExt {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 7f0baf49dad..0221f922feb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -291,7 +291,7 @@ impl HirDisplay for ProjectionTy {
 
         let trait_ = f.db.trait_data(self.trait_(f.db));
         write!(f, "<")?;
-        self.self_type_parameter(Interner).hir_fmt(f)?;
+        self.self_type_parameter(f.db).hir_fmt(f)?;
         write!(f, " as {}", trait_.name)?;
         if self.substitution.len(Interner) > 1 {
             write!(f, "<")?;
@@ -731,7 +731,7 @@ impl HirDisplay for Ty {
                                         WhereClause::AliasEq(AliasEq {
                                             alias: AliasTy::Projection(proj),
                                             ty: _,
-                                        }) => &proj.self_type_parameter(Interner) == self,
+                                        }) => &proj.self_type_parameter(f.db) == self,
                                         _ => false,
                                     })
                                     .collect::<Vec<_>>();
@@ -751,9 +751,19 @@ impl HirDisplay for Ty {
             }
             TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
             TyKind::Dyn(dyn_ty) => {
+                // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
+                // FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
+                // more efficient when either of them hits stable.
+                let mut bounds: SmallVec<[_; 4]> =
+                    dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
+                let (auto_traits, others): (SmallVec<[_; 4]>, _) =
+                    bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
+                bounds.extend(others);
+                bounds.extend(auto_traits);
+
                 write_bounds_like_dyn_trait_with_prefix(
                     "dyn",
-                    dyn_ty.bounds.skip_binders().interned(),
+                    &bounds,
                     SizedByDefault::NotSized,
                     f,
                 )?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 0efff651cc1..6a5c4966f7b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -190,7 +190,9 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 pub enum InferenceDiagnostic {
     NoSuchField { expr: ExprId },
     BreakOutsideOfLoop { expr: ExprId, is_break: bool },
+    IncorrectTryTarget { expr: ExprId },
     MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
+    DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
 }
 
 /// A mismatch between an expected and an inferred type.
@@ -905,17 +907,6 @@ impl<'a> InferenceContext<'a> {
         self.db.trait_data(trait_).associated_type_by_name(&name![Item])
     }
 
-    fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
-        // FIXME resolve via lang_item once try v2 is stable
-        let path = path![core::ops::Try];
-        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
-        let trait_data = self.db.trait_data(trait_);
-        trait_data
-            // FIXME remove once try v2 is stable
-            .associated_type_by_name(&name![Ok])
-            .or_else(|| trait_data.associated_type_by_name(&name![Output]))
-    }
-
     fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
         let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index f56108b26c4..59ab50d0717 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -19,24 +19,24 @@ use hir_def::{
     resolver::resolver_for_expr,
     ConstParamId, FieldId, ItemContainerId, Lookup,
 };
-use hir_expand::name::Name;
+use hir_expand::{name, name::Name};
 use stdx::always;
 use syntax::ast::RangeOp;
 
 use crate::{
     autoderef::{self, Autoderef},
     consteval,
-    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
+    infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
     lower::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
     mapping::{from_chalk, ToChalk},
     method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
     primitive::{self, UintTy},
-    static_lifetime, to_chalk_trait_id,
+    static_lifetime, to_assoc_type_id, to_chalk_trait_id,
     utils::{generics, Generics},
-    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
-    Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+    AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
+    ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 };
 
 use super::{
@@ -564,9 +564,29 @@ impl<'a> InferenceContext<'a> {
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
                 self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
             }
-            Expr::Try { expr } => {
-                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
-                self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
+            &Expr::Try { expr } => {
+                let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
+                match self.resolve_try_impl_for(inner_ty.clone()) {
+                    Some((_, Some((output, residual)))) => {
+                        if let Some((_trait, false)) =
+                            self.implements_from_residual(self.return_ty.clone(), residual)
+                        {
+                            self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
+                                expr: tgt_expr,
+                            });
+                        }
+                        output
+                    }
+                    Some((trait_, None)) => {
+                        self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
+                            expr,
+                            trait_,
+                            ty: inner_ty,
+                        });
+                        self.err_ty()
+                    }
+                    None => self.err_ty(),
+                }
             }
             Expr::Cast { expr, type_ref } => {
                 // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
@@ -1530,4 +1550,67 @@ impl<'a> InferenceContext<'a> {
         let ctx = self.breakables.pop().expect("breakable stack broken");
         (ctx.may_break.then(|| ctx.coerce.complete()), res)
     }
+
+    /// Check whether `ty` implements `FromResidual<r>`
+    fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
+        let from_residual_trait = self
+            .resolver
+            .resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
+        let r = GenericArgData::Ty(r).intern(Interner);
+        let b = TyBuilder::trait_ref(self.db, from_residual_trait);
+        if b.remaining() != 2 {
+            return Some((from_residual_trait, false));
+        }
+        let trait_ref = b.push(ty).push(r).build();
+        Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
+    }
+
+    fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
+        let path = path![core::ops::Try];
+        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
+
+        let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
+        let substitution = trait_ref.substitution.clone();
+        self.push_obligation(trait_ref.clone().cast(Interner));
+
+        let trait_data = self.db.trait_data(trait_);
+        let output = trait_data.associated_type_by_name(&name![Output]);
+        let residual = trait_data.associated_type_by_name(&name![Residual]);
+
+        let output_ty = match output {
+            Some(output) => {
+                let output_ty = self.table.new_type_var();
+                let alias_eq = AliasEq {
+                    alias: AliasTy::Projection(ProjectionTy {
+                        associated_ty_id: to_assoc_type_id(output),
+                        substitution: substitution.clone(),
+                    }),
+                    ty: output_ty.clone(),
+                };
+                self.push_obligation(alias_eq.cast(Interner));
+                output_ty
+            }
+            None => self.err_ty(),
+        };
+        let residual_ty = match residual {
+            Some(residual) => {
+                let residual_ty = self.table.new_type_var();
+                let alias_eq = AliasEq {
+                    alias: AliasTy::Projection(ProjectionTy {
+                        associated_ty_id: to_assoc_type_id(residual),
+                        substitution,
+                    }),
+                    ty: residual_ty.clone(),
+                };
+                self.push_obligation(alias_eq.cast(Interner));
+                residual_ty
+            }
+            None => self.err_ty(),
+        };
+        // FIXME: We are doing the work twice here I think?
+        Some((
+            trait_,
+            self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
+        ))
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 6ccd0b215c6..b00e3216b2d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -4,7 +4,7 @@ use std::{fmt, mem, sync::Arc};
 
 use chalk_ir::{
     cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
-    IntTy, NoSolution, TyVariableKind, UniverseIndex,
+    IntTy, TyVariableKind, UniverseIndex,
 };
 use chalk_solve::infer::ParameterEnaVariableExt;
 use ena::unify::UnifyKey;
@@ -331,7 +331,6 @@ impl<'a> InferenceTable<'a> {
             &mut resolve::Resolver { table: self, var_stack, fallback },
             DebruijnIndex::INNERMOST,
         )
-        .expect("fold failed unexpectedly")
     }
 
     pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
@@ -452,13 +451,14 @@ impl<'a> InferenceTable<'a> {
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         use chalk_ir::fold::TypeFolder;
+
+        #[derive(chalk_derive::FallibleTypeFolder)]
+        #[has_interner(Interner)]
         struct VarFudger<'a, 'b> {
             table: &'a mut InferenceTable<'b>,
             highest_known_var: InferenceVar,
         }
         impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
-            type Error = NoSolution;
-
             fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
                 self
             }
@@ -472,24 +472,24 @@ impl<'a> InferenceTable<'a> {
                 var: chalk_ir::InferenceVar,
                 kind: TyVariableKind,
                 _outer_binder: chalk_ir::DebruijnIndex,
-            ) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
-                Ok(if var < self.highest_known_var {
+            ) -> chalk_ir::Ty<Interner> {
+                if var < self.highest_known_var {
                     var.to_ty(Interner, kind)
                 } else {
                     self.table.new_type_var()
-                })
+                }
             }
 
             fn fold_inference_lifetime(
                 &mut self,
                 var: chalk_ir::InferenceVar,
                 _outer_binder: chalk_ir::DebruijnIndex,
-            ) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
-                Ok(if var < self.highest_known_var {
+            ) -> chalk_ir::Lifetime<Interner> {
+                if var < self.highest_known_var {
                     var.to_lifetime(Interner)
                 } else {
                     self.table.new_lifetime_var()
-                })
+                }
             }
 
             fn fold_inference_const(
@@ -497,12 +497,12 @@ impl<'a> InferenceTable<'a> {
                 ty: chalk_ir::Ty<Interner>,
                 var: chalk_ir::InferenceVar,
                 _outer_binder: chalk_ir::DebruijnIndex,
-            ) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
-                Ok(if var < self.highest_known_var {
+            ) -> chalk_ir::Const<Interner> {
+                if var < self.highest_known_var {
                     var.to_const(Interner, ty)
                 } else {
                     self.table.new_const_var(ty)
-                })
+                }
             }
         }
 
@@ -512,7 +512,6 @@ impl<'a> InferenceTable<'a> {
         self.rollback_to(snapshot);
         result
             .fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
-            .expect("fold_with with VarFudger")
     }
 
     /// This checks whether any of the free variables in the `canonicalized`
@@ -639,21 +638,24 @@ mod resolve {
     use chalk_ir::{
         cast::Cast,
         fold::{TypeFoldable, TypeFolder},
-        Fallible, NoSolution,
     };
     use hir_def::type_ref::ConstScalar;
 
-    pub(super) struct Resolver<'a, 'b, F> {
+    #[derive(chalk_derive::FallibleTypeFolder)]
+    #[has_interner(Interner)]
+    pub(super) struct Resolver<
+        'a,
+        'b,
+        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+    > {
         pub(super) table: &'a mut InferenceTable<'b>,
         pub(super) var_stack: &'a mut Vec<InferenceVar>,
         pub(super) fallback: F,
     }
-    impl<'a, 'b, 'i, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
+    impl<'a, 'b, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
     where
-        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
+        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
     {
-        type Error = NoSolution;
-
         fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
             self
         }
@@ -667,20 +669,19 @@ mod resolve {
             var: InferenceVar,
             kind: TyVariableKind,
             outer_binder: DebruijnIndex,
-        ) -> Fallible<Ty> {
+        ) -> Ty {
             let var = self.table.var_unification_table.inference_var_root(var);
             if self.var_stack.contains(&var) {
                 // recursive type
                 let default = self.table.fallback_value(var, kind).cast(Interner);
-                return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
                     .assert_ty_ref(Interner)
-                    .clone());
+                    .clone();
             }
             let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
                 // known_ty may contain other variables that are known by now
                 self.var_stack.push(var);
-                let result =
-                    known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
+                let result = known_ty.fold_with(self, outer_binder);
                 self.var_stack.pop();
                 result.assert_ty_ref(Interner).clone()
             } else {
@@ -689,7 +690,7 @@ mod resolve {
                     .assert_ty_ref(Interner)
                     .clone()
             };
-            Ok(result)
+            result
         }
 
         fn fold_inference_const(
@@ -697,7 +698,7 @@ mod resolve {
             ty: Ty,
             var: InferenceVar,
             outer_binder: DebruijnIndex,
-        ) -> Fallible<Const> {
+        ) -> Const {
             let var = self.table.var_unification_table.inference_var_root(var);
             let default = ConstData {
                 ty: ty.clone(),
@@ -707,35 +708,33 @@ mod resolve {
             .cast(Interner);
             if self.var_stack.contains(&var) {
                 // recursive
-                return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
+                return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
                     .assert_const_ref(Interner)
-                    .clone());
+                    .clone();
             }
-            let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
+            if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
                 // known_ty may contain other variables that are known by now
                 self.var_stack.push(var);
-                let result =
-                    known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
+                let result = known_ty.fold_with(self, outer_binder);
                 self.var_stack.pop();
                 result.assert_const_ref(Interner).clone()
             } else {
                 (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
                     .assert_const_ref(Interner)
                     .clone()
-            };
-            Ok(result)
+            }
         }
 
         fn fold_inference_lifetime(
             &mut self,
             _var: InferenceVar,
             _outer_binder: DebruijnIndex,
-        ) -> Fallible<Lifetime> {
+        ) -> Lifetime {
             // fall back all lifetimes to 'static -- currently we don't deal
             // with any lifetimes, but we can sometimes get some lifetime
             // variables through Chalk's unification, and this at least makes
             // sure we don't leak them outside of inference
-            Ok(crate::static_lifetime())
+            crate::static_lifetime()
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index de4a5446e57..c4b700cbce6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -254,13 +254,13 @@ impl CallableSig {
 }
 
 impl TypeFoldable<Interner> for CallableSig {
-    fn fold_with<E>(
+    fn try_fold_with<E>(
         self,
-        folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
+        folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
         outer_binder: DebruijnIndex,
     ) -> Result<Self, E> {
         let vec = self.params_and_return.to_vec();
-        let folded = vec.fold_with(folder, outer_binder)?;
+        let folded = vec.try_fold_with(folder, outer_binder)?;
         Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
     }
 }
@@ -292,16 +292,19 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
     for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
     for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
 ) -> T {
-    use chalk_ir::{fold::TypeFolder, Fallible};
-    struct FreeVarFolder<F1, F2>(F1, F2);
+    use chalk_ir::fold::TypeFolder;
+
+    #[derive(chalk_derive::FallibleTypeFolder)]
+    #[has_interner(Interner)]
+    struct FreeVarFolder<
+        F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
+        F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
+    >(F1, F2);
     impl<
-            'i,
-            F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
-            F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
+            F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
+            F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
         > TypeFolder<Interner> for FreeVarFolder<F1, F2>
     {
-        type Error = NoSolution;
-
         fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
             self
         }
@@ -310,12 +313,8 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
             Interner
         }
 
-        fn fold_free_var_ty(
-            &mut self,
-            bound_var: BoundVar,
-            outer_binder: DebruijnIndex,
-        ) -> Fallible<Ty> {
-            Ok(self.0(bound_var, outer_binder))
+        fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
+            self.0(bound_var, outer_binder)
         }
 
         fn fold_free_var_const(
@@ -323,12 +322,11 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
             ty: Ty,
             bound_var: BoundVar,
             outer_binder: DebruijnIndex,
-        ) -> Fallible<Const> {
-            Ok(self.1(ty, bound_var, outer_binder))
+        ) -> Const {
+            self.1(ty, bound_var, outer_binder)
         }
     }
     t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
-        .expect("fold failed unexpectedly")
 }
 
 pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
@@ -351,16 +349,13 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
     f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
     binders: DebruijnIndex,
 ) -> T {
-    use chalk_ir::{
-        fold::{TypeFolder, TypeSuperFoldable},
-        Fallible,
-    };
-    struct TyFolder<F>(F);
-    impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i>
-        TypeFolder<Interner> for TyFolder<F>
+    use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
+    #[derive(chalk_derive::FallibleTypeFolder)]
+    #[has_interner(Interner)]
+    struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
+    impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
+        for TyFolder<F>
     {
-        type Error = NoSolution;
-
         fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
             self
         }
@@ -369,16 +364,16 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
             Interner
         }
 
-        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
-            let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
-            Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
+        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
+            let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
+            self.0(Either::Left(ty), outer_binder).left().unwrap()
         }
 
-        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
-            Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
+        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
+            self.0(Either::Right(c), outer_binder).right().unwrap()
         }
     }
-    t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
+    t.fold_with(&mut TyFolder(f), binders)
 }
 
 /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
@@ -390,16 +385,16 @@ where
     T: HasInterner<Interner = Interner>,
 {
     use chalk_ir::{
-        fold::{TypeFolder, TypeSuperFoldable},
+        fold::{FallibleTypeFolder, TypeSuperFoldable},
         Fallible,
     };
     struct ErrorReplacer {
         vars: usize,
     }
-    impl TypeFolder<Interner> for ErrorReplacer {
+    impl FallibleTypeFolder<Interner> for ErrorReplacer {
         type Error = NoSolution;
 
-        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
+        fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
             self
         }
 
@@ -407,18 +402,17 @@ where
             Interner
         }
 
-        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
+        fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
             if let TyKind::Error = ty.kind(Interner) {
                 let index = self.vars;
                 self.vars += 1;
                 Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
             } else {
-                let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
-                Ok(ty)
+                ty.try_super_fold_with(self.as_dyn(), outer_binder)
             }
         }
 
-        fn fold_inference_ty(
+        fn try_fold_inference_ty(
             &mut self,
             _var: InferenceVar,
             _kind: TyVariableKind,
@@ -433,7 +427,7 @@ where
             }
         }
 
-        fn fold_free_var_ty(
+        fn try_fold_free_var_ty(
             &mut self,
             _bound_var: BoundVar,
             _outer_binder: DebruijnIndex,
@@ -447,7 +441,7 @@ where
             }
         }
 
-        fn fold_inference_const(
+        fn try_fold_inference_const(
             &mut self,
             ty: Ty,
             _var: InferenceVar,
@@ -460,7 +454,7 @@ where
             }
         }
 
-        fn fold_free_var_const(
+        fn try_fold_free_var_const(
             &mut self,
             ty: Ty,
             _bound_var: BoundVar,
@@ -473,7 +467,7 @@ where
             }
         }
 
-        fn fold_inference_lifetime(
+        fn try_fold_inference_lifetime(
             &mut self,
             _var: InferenceVar,
             _outer_binder: DebruijnIndex,
@@ -485,7 +479,7 @@ where
             }
         }
 
-        fn fold_free_var_lifetime(
+        fn try_fold_free_var_lifetime(
             &mut self,
             _bound_var: BoundVar,
             _outer_binder: DebruijnIndex,
@@ -498,7 +492,7 @@ where
         }
     }
     let mut error_replacer = ErrorReplacer { vars: 0 };
-    let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
+    let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
         Ok(t) => t,
         Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 3a1a3f4fdeb..a79efeb6daa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -1111,6 +1111,24 @@ pub fn resolve_indexing_op(
     }
     None
 }
+/// Returns the receiver type for the try branch trait call.
+pub fn resolve_branch_op(
+    db: &dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
+    ty: Canonical<Ty>,
+    try_trait: TraitId,
+) -> Option<ReceiverAdjustments> {
+    let mut table = InferenceTable::new(db, env.clone());
+    let ty = table.instantiate_canonical(ty);
+    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
+    for (ty, adj) in deref_chain.into_iter().zip(adj) {
+        let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
+        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
+            return Some(adj);
+        }
+    }
+    None
+}
 
 macro_rules! check_that {
     ($cond:expr) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index 240942e488d..8a8ff08cfe8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -56,6 +56,28 @@ fn main() {
 }
 
 #[test]
+fn render_dyn_ty_independent_of_order() {
+    check_types_source_code(
+        r#"
+auto trait Send {}
+trait A {
+    type Assoc;
+}
+trait B: A {}
+
+fn test(
+    _: &(dyn A<Assoc = ()> + Send),
+  //^ &(dyn A<Assoc = ()> + Send)
+    _: &(dyn Send + A<Assoc = ()>),
+  //^ &(dyn A<Assoc = ()> + Send)
+    _: &dyn B<Assoc = ()>,
+  //^ &(dyn B<Assoc = ()>)
+) {}
+        "#,
+    );
+}
+
+#[test]
 fn render_dyn_for_ty() {
     // FIXME
     check_types_source_code(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index eb04bf87783..74de33117ee 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -1070,3 +1070,13 @@ fn main() {
         "#,
     );
 }
+
+#[test]
+fn cfg_params() {
+    check_types(
+        r#"
+fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
+                                           //^^^ u32
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 555b6972fb7..b91172e3342 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -163,97 +163,15 @@ fn test() {
 }
 
 #[test]
-fn infer_try() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:core
-fn test() {
-    let r: Result<i32, u64> = Result::Ok(1);
-    let v = r?;
-    v;
-} //^ i32
-
-//- /core.rs crate:core
-pub mod ops {
-    pub trait Try {
-        type Ok;
-        type Error;
-    }
-}
-
-pub mod result {
-    pub enum Result<O, E> {
-        Ok(O),
-        Err(E)
-    }
-
-    impl<O, E> crate::ops::Try for Result<O, E> {
-        type Ok = O;
-        type Error = E;
-    }
-}
-
-pub mod prelude {
-    pub mod rust_2018 {
-        pub use crate::{result::*, ops::*};
-    }
-}
-"#,
-    );
-}
-
-#[test]
 fn infer_try_trait_v2() {
     check_types(
         r#"
-//- /main.rs crate:main deps:core
-fn test() {
-    let r: Result<i32, u64> = Result::Ok(1);
+//- minicore: try
+fn test() -> core::ops::ControlFlow<u32, f32> {
+    let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
     let v = r?;
-    v;
-} //^ i32
-
-//- /core.rs crate:core
-mod ops {
-    mod try_trait {
-        pub trait Try: FromResidual {
-            type Output;
-            type Residual;
-        }
-        pub trait FromResidual<R = <Self as Try>::Residual> {}
-    }
-
-    pub use self::try_trait::FromResidual;
-    pub use self::try_trait::Try;
-}
-
-mod convert {
-    pub trait From<T> {}
-    impl<T> From<T> for T {}
-}
-
-pub mod result {
-    use crate::convert::From;
-    use crate::ops::{Try, FromResidual};
-
-    pub enum Infallible {}
-    pub enum Result<O, E> {
-        Ok(O),
-        Err(E)
-    }
-
-    impl<O, E> Try for Result<O, E> {
-        type Output = O;
-        type Error = Result<Infallible, E>;
-    }
-
-    impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
-}
-
-pub mod prelude {
-    pub mod rust_2018 {
-        pub use crate::result::*;
-    }
+      //^ f32
+    r
 }
 "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 372c3a3cca6..c425f35acfe 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -13,8 +13,8 @@ use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
-    Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
-    WhereClause,
+    Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
+    TyKind, WhereClause,
 };
 
 /// This controls how much 'time' we give the Chalk solver before giving up.
@@ -95,7 +95,7 @@ pub(crate) fn trait_solve_query(
         ..
     }))) = &goal.value.goal.data(Interner)
     {
-        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
+        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) {
             // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
             return Some(Solution::Ambig(Guidance::Unknown));
         }
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index 8e6a2441b33..e1418de3cdc 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -13,9 +13,9 @@ doctest = false
 rustc-hash = "1.1.0"
 either = "1.7.0"
 arrayvec = "0.7.2"
-itertools = "0.10.3"
-smallvec = "1.9.0"
-once_cell = "1.12.0"
+itertools = "0.10.5"
+smallvec = "1.10.0"
+once_cell = "1.15.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index c5dc60f1ec5..6c8b3088adc 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -6,7 +6,7 @@
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
-use hir_def::path::ModPath;
+use hir_def::{path::ModPath, TraitId};
 use hir_expand::{name::Name, HirFileId, InFile};
 use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
 
@@ -33,6 +33,7 @@ diagnostics![
     BreakOutsideOfLoop,
     InactiveCode,
     IncorrectCase,
+    IncorrectTryExpr,
     InvalidDeriveTarget,
     MacroError,
     MalformedDerive,
@@ -40,6 +41,7 @@ diagnostics![
     MissingFields,
     MissingMatchArms,
     MissingUnsafe,
+    NotImplemented,
     NoSuchField,
     ReplaceFilterMapNextWithFindMap,
     TypeMismatch,
@@ -153,6 +155,16 @@ pub struct MismatchedArgCount {
     pub expected: usize,
     pub found: usize,
 }
+#[derive(Debug)]
+pub struct IncorrectTryExpr {
+    pub expr: InFile<AstPtr<ast::Expr>>,
+}
+#[derive(Debug)]
+pub struct NotImplemented {
+    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub trait_: TraitId,
+    pub ty: Type,
+}
 
 #[derive(Debug)]
 pub struct MissingMatchArms {
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index f5324208c9a..e6c5c6b5833 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -81,11 +81,12 @@ use crate::db::{DefDatabase, HirDatabase};
 pub use crate::{
     attrs::{HasAttrs, Namespace},
     diagnostics::{
-        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
-        MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
-        MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
-        UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
-        UnresolvedModule, UnresolvedProcMacro,
+        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, IncorrectTryExpr,
+        InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
+        MissingMatchArms, MissingUnsafe, NoSuchField, NotImplemented,
+        ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
+        UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
+        UnresolvedProcMacro,
     },
     has_source::HasSource,
     semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -1282,30 +1283,45 @@ impl DefWithBody {
         let infer = db.infer(self.into());
         let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
         for d in &infer.diagnostics {
-            match d {
+            match *d {
                 hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
-                    let field = source_map.field_syntax(*expr);
+                    let field = source_map.field_syntax(expr);
                     acc.push(NoSuchField { field }.into())
                 }
-                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
+                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
                     let expr = source_map
                         .expr_syntax(expr)
                         .expect("break outside of loop in synthetic syntax");
                     acc.push(BreakOutsideOfLoop { expr, is_break }.into())
                 }
                 hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
-                    match source_map.expr_syntax(*call_expr) {
+                    match source_map.expr_syntax(call_expr) {
                         Ok(source_ptr) => acc.push(
                             MismatchedArgCount {
                                 call_expr: source_ptr,
-                                expected: *expected,
-                                found: *found,
+                                expected: expected,
+                                found: found,
                             }
                             .into(),
                         ),
                         Err(SyntheticSyntax) => (),
                     }
                 }
+                hir_ty::InferenceDiagnostic::IncorrectTryTarget { expr } => {
+                    let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
+                    acc.push(IncorrectTryExpr { expr }.into())
+                }
+                hir_ty::InferenceDiagnostic::DoesNotImplement { expr, trait_, ref ty } => {
+                    let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
+                    acc.push(
+                        NotImplemented {
+                            expr,
+                            trait_,
+                            ty: Type::new(db, DefWithBodyId::from(self), ty.clone()),
+                        }
+                        .into(),
+                    )
+                }
             }
         }
         for (expr, mismatch) in infer.expr_type_mismatches() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
index fca09d384c6..57a41f3d9a9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
 [dependencies]
 cov-mark = "2.0.0-pre.1"
 
-itertools = "0.10.3"
+itertools = "0.10.5"
 either = "1.7.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index e257218ba93..678dc877d13 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -156,6 +156,8 @@ pub(super) fn find_importable_node(
     {
         ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
             .zip(Some(method_under_caret.syntax().clone().into()))
+    } else if let Some(_) = ctx.find_node_at_offset_with_descend::<ast::Param>() {
+        None
     } else if let Some(pat) = ctx
         .find_node_at_offset_with_descend::<ast::IdentPat>()
         .filter(ast::IdentPat::is_simple_ident)
@@ -269,6 +271,20 @@ mod tests {
     }
 
     #[test]
+    fn ignore_parameter_name() {
+        check_assist_not_applicable(
+            auto_import,
+            r"
+            mod foo {
+                pub mod bar {}
+            }
+
+            fn foo(bar$0: &str) {}
+            ",
+        );
+    }
+
+    #[test]
     fn prefer_shorter_paths() {
         let before = r"
 //- /main.rs crate:main deps:foo,bar
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
new file mode 100644
index 00000000000..8d11e0bac94
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -0,0 +1,822 @@
+use either::Either;
+use ide_db::defs::Definition;
+use itertools::Itertools;
+use syntax::{
+    ast::{self, AstNode, HasGenericParams, HasVisibility},
+    match_ast, SyntaxKind, SyntaxNode,
+};
+
+use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: convert_named_struct_to_tuple_struct
+//
+// Converts struct with named fields to tuple struct, and analogously for enum variants with named
+// fields.
+//
+// ```
+// struct Point$0 { x: f32, y: f32 }
+//
+// impl Point {
+//     pub fn new(x: f32, y: f32) -> Self {
+//         Point { x, y }
+//     }
+//
+//     pub fn x(&self) -> f32 {
+//         self.x
+//     }
+//
+//     pub fn y(&self) -> f32 {
+//         self.y
+//     }
+// }
+// ```
+// ->
+// ```
+// struct Point(f32, f32);
+//
+// impl Point {
+//     pub fn new(x: f32, y: f32) -> Self {
+//         Point(x, y)
+//     }
+//
+//     pub fn x(&self) -> f32 {
+//         self.0
+//     }
+//
+//     pub fn y(&self) -> f32 {
+//         self.1
+//     }
+// }
+// ```
+pub(crate) fn convert_named_struct_to_tuple_struct(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
+    let strukt = ctx
+        .find_node_at_offset::<ast::Struct>()
+        .map(Either::Left)
+        .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
+    let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
+    let record_fields = match field_list {
+        ast::FieldList::RecordFieldList(it) => it,
+        ast::FieldList::TupleFieldList(_) => return None,
+    };
+    let strukt_def = match &strukt {
+        Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
+        Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
+    };
+    let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
+
+    acc.add(
+        AssistId("convert_named_struct_to_tuple_struct", AssistKind::RefactorRewrite),
+        "Convert to tuple struct",
+        target,
+        |edit| {
+            edit_field_references(ctx, edit, record_fields.fields());
+            edit_struct_references(ctx, edit, strukt_def);
+            edit_struct_def(ctx, edit, &strukt, record_fields);
+        },
+    )
+}
+
+fn edit_struct_def(
+    ctx: &AssistContext<'_>,
+    edit: &mut SourceChangeBuilder,
+    strukt: &Either<ast::Struct, ast::Variant>,
+    record_fields: ast::RecordFieldList,
+) {
+    let tuple_fields = record_fields
+        .fields()
+        .filter_map(|f| Some(ast::make::tuple_field(f.visibility(), f.ty()?)));
+    let tuple_fields = ast::make::tuple_field_list(tuple_fields);
+    let record_fields_text_range = record_fields.syntax().text_range();
+
+    edit.edit_file(ctx.file_id());
+    edit.replace(record_fields_text_range, tuple_fields.syntax().text());
+
+    if let Either::Left(strukt) = strukt {
+        if let Some(w) = strukt.where_clause() {
+            let mut where_clause = w.to_string();
+            if where_clause.ends_with(',') {
+                where_clause.pop();
+            }
+            where_clause.push(';');
+
+            edit.delete(w.syntax().text_range());
+            edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
+            edit.insert(record_fields_text_range.end(), where_clause);
+            edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
+
+            if let Some(tok) = strukt
+                .generic_param_list()
+                .and_then(|l| l.r_angle_token())
+                .and_then(|tok| tok.next_token())
+                .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
+            {
+                edit.delete(tok.text_range());
+            }
+        } else {
+            edit.insert(record_fields_text_range.end(), ";");
+        }
+    }
+
+    if let Some(tok) = record_fields
+        .l_curly_token()
+        .and_then(|tok| tok.prev_token())
+        .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
+    {
+        edit.delete(tok.text_range())
+    }
+}
+
+fn edit_struct_references(
+    ctx: &AssistContext<'_>,
+    edit: &mut SourceChangeBuilder,
+    strukt: Either<hir::Struct, hir::Variant>,
+) {
+    let strukt_def = match strukt {
+        Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)),
+        Either::Right(v) => Definition::Variant(v),
+    };
+    let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
+
+    let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> {
+        match_ast! {
+            match node {
+                ast::RecordPat(record_struct_pat) => {
+                    edit.replace(
+                        record_struct_pat.syntax().text_range(),
+                        ast::make::tuple_struct_pat(
+                            record_struct_pat.path()?,
+                            record_struct_pat
+                                .record_pat_field_list()?
+                                .fields()
+                                .filter_map(|pat| pat.pat())
+                        )
+                        .to_string()
+                    );
+                },
+                ast::RecordExpr(record_expr) => {
+                    let path = record_expr.path()?;
+                    let args = record_expr
+                        .record_expr_field_list()?
+                        .fields()
+                        .filter_map(|f| f.expr())
+                        .join(", ");
+
+                    edit.replace(record_expr.syntax().text_range(), format!("{path}({args})"));
+                },
+                _ => return None,
+            }
+        }
+        Some(())
+    };
+
+    for (file_id, refs) in usages {
+        edit.edit_file(file_id);
+        for r in refs {
+            for node in r.name.syntax().ancestors() {
+                if edit_node(edit, node).is_some() {
+                    break;
+                }
+            }
+        }
+    }
+}
+
+fn edit_field_references(
+    ctx: &AssistContext<'_>,
+    edit: &mut SourceChangeBuilder,
+    fields: impl Iterator<Item = ast::RecordField>,
+) {
+    for (index, field) in fields.enumerate() {
+        let field = match ctx.sema.to_def(&field) {
+            Some(it) => it,
+            None => continue,
+        };
+        let def = Definition::Field(field);
+        let usages = def.usages(&ctx.sema).all();
+        for (file_id, refs) in usages {
+            edit.edit_file(file_id);
+            for r in refs {
+                if let Some(name_ref) = r.name.as_name_ref() {
+                    // Only edit the field reference if it's part of a `.field` access
+                    if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() {
+                        edit.replace(name_ref.syntax().text_range(), index.to_string());
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn not_applicable_other_than_record_struct() {
+        check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0(u32)"#);
+        check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0;"#);
+    }
+
+    #[test]
+    fn convert_simple_struct() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+struct A$0 { inner: Inner }
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A { inner }
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.inner
+    }
+}"#,
+            r#"
+struct Inner;
+struct A(Inner);
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A(inner)
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.0
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_struct_referenced_via_self_kw() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+struct A$0 { inner: Inner }
+
+impl A {
+    fn new(inner: Inner) -> Self {
+        Self { inner }
+    }
+
+    fn new_with_default() -> Self {
+        Self::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.inner
+    }
+}"#,
+            r#"
+struct Inner;
+struct A(Inner);
+
+impl A {
+    fn new(inner: Inner) -> Self {
+        Self(inner)
+    }
+
+    fn new_with_default() -> Self {
+        Self::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.0
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_destructured_struct() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+struct A$0 { inner: Inner }
+
+impl A {
+    fn into_inner(self) -> Inner {
+        let A { inner: a } = self;
+        a
+    }
+
+    fn into_inner_via_self(self) -> Inner {
+        let Self { inner } = self;
+        inner
+    }
+}"#,
+            r#"
+struct Inner;
+struct A(Inner);
+
+impl A {
+    fn into_inner(self) -> Inner {
+        let A(a) = self;
+        a
+    }
+
+    fn into_inner_via_self(self) -> Inner {
+        let Self(inner) = self;
+        inner
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_struct_with_visibility() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct A$0 {
+    pub first: u32,
+    pub(crate) second: u64
+}
+
+impl A {
+    fn new() -> A {
+        A { first: 42, second: 42 }
+    }
+
+    fn into_first(self) -> u32 {
+        self.first
+    }
+
+    fn into_second(self) -> u64 {
+        self.second
+    }
+}"#,
+            r#"
+struct A(pub u32, pub(crate) u64);
+
+impl A {
+    fn new() -> A {
+        A(42, 42)
+    }
+
+    fn into_first(self) -> u32 {
+        self.0
+    }
+
+    fn into_second(self) -> u64 {
+        self.1
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_struct_with_wrapped_references() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner$0 { uint: u32 }
+struct Outer { inner: Inner }
+
+impl Outer {
+    fn new() -> Self {
+        Self { inner: Inner { uint: 42 } }
+    }
+
+    fn into_inner(self) -> u32 {
+        self.inner.uint
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer { inner: Inner { uint: x } } = self;
+        x
+    }
+}"#,
+            r#"
+struct Inner(u32);
+struct Outer { inner: Inner }
+
+impl Outer {
+    fn new() -> Self {
+        Self { inner: Inner(42) }
+    }
+
+    fn into_inner(self) -> u32 {
+        self.inner.0
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer { inner: Inner(x) } = self;
+        x
+    }
+}"#,
+        );
+
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner { uint: u32 }
+struct Outer$0 { inner: Inner }
+
+impl Outer {
+    fn new() -> Self {
+        Self { inner: Inner { uint: 42 } }
+    }
+
+    fn into_inner(self) -> u32 {
+        self.inner.uint
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer { inner: Inner { uint: x } } = self;
+        x
+    }
+}"#,
+            r#"
+struct Inner { uint: u32 }
+struct Outer(Inner);
+
+impl Outer {
+    fn new() -> Self {
+        Self(Inner { uint: 42 })
+    }
+
+    fn into_inner(self) -> u32 {
+        self.0.uint
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer(Inner { uint: x }) = self;
+        x
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_struct_with_multi_file_references() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+//- /main.rs
+struct Inner;
+struct A$0 { inner: Inner }
+
+mod foo;
+
+//- /foo.rs
+use crate::{A, Inner};
+fn f() {
+    let a = A { inner: Inner };
+}
+"#,
+            r#"
+//- /main.rs
+struct Inner;
+struct A(Inner);
+
+mod foo;
+
+//- /foo.rs
+use crate::{A, Inner};
+fn f() {
+    let a = A(Inner);
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_struct_with_where_clause() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Wrap$0<T>
+where
+    T: Display,
+{ field1: T }
+"#,
+            r#"
+struct Wrap<T>(T)
+where
+    T: Display;
+
+"#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_other_than_record_variant() {
+        check_assist_not_applicable(
+            convert_named_struct_to_tuple_struct,
+            r#"enum Enum { Variant$0(usize) };"#,
+        );
+        check_assist_not_applicable(
+            convert_named_struct_to_tuple_struct,
+            r#"enum Enum { Variant$0 }"#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_variant() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+enum A {
+    $0Variant { field1: usize },
+}
+
+impl A {
+    fn new(value: usize) -> A {
+        A::Variant { field1: value }
+    }
+
+    fn new_with_default() -> A {
+        A::new(Default::default())
+    }
+
+    fn value(self) -> usize {
+        match self {
+            A::Variant { field1: value } => value,
+        }
+    }
+}"#,
+            r#"
+enum A {
+    Variant(usize),
+}
+
+impl A {
+    fn new(value: usize) -> A {
+        A::Variant(value)
+    }
+
+    fn new_with_default() -> A {
+        A::new(Default::default())
+    }
+
+    fn value(self) -> usize {
+        match self {
+            A::Variant(value) => value,
+        }
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_variant_referenced_via_self_kw() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+enum A {
+    $0Variant { field1: usize },
+}
+
+impl A {
+    fn new(value: usize) -> A {
+        Self::Variant { field1: value }
+    }
+
+    fn new_with_default() -> A {
+        Self::new(Default::default())
+    }
+
+    fn value(self) -> usize {
+        match self {
+            Self::Variant { field1: value } => value,
+        }
+    }
+}"#,
+            r#"
+enum A {
+    Variant(usize),
+}
+
+impl A {
+    fn new(value: usize) -> A {
+        Self::Variant(value)
+    }
+
+    fn new_with_default() -> A {
+        Self::new(Default::default())
+    }
+
+    fn value(self) -> usize {
+        match self {
+            Self::Variant(value) => value,
+        }
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_destructured_variant() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+enum A {
+    $0Variant { field1: usize },
+}
+
+impl A {
+    fn into_inner(self) -> usize {
+        let A::Variant { field1: first } = self;
+        first
+    }
+
+    fn into_inner_via_self(self) -> usize {
+        let Self::Variant { field1: first } = self;
+        first
+    }
+}"#,
+            r#"
+enum A {
+    Variant(usize),
+}
+
+impl A {
+    fn into_inner(self) -> usize {
+        let A::Variant(first) = self;
+        first
+    }
+
+    fn into_inner_via_self(self) -> usize {
+        let Self::Variant(first) = self;
+        first
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_variant_with_wrapped_references() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+enum Inner {
+    $0Variant { field1: usize },
+}
+enum Outer {
+    Variant(Inner),
+}
+
+impl Outer {
+    fn new() -> Self {
+        Self::Variant(Inner::Variant { field1: 42 })
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer::Variant(Inner::Variant { field1: x }) = self;
+        x
+    }
+}"#,
+            r#"
+enum Inner {
+    Variant(usize),
+}
+enum Outer {
+    Variant(Inner),
+}
+
+impl Outer {
+    fn new() -> Self {
+        Self::Variant(Inner::Variant(42))
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer::Variant(Inner::Variant(x)) = self;
+        x
+    }
+}"#,
+        );
+
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+enum Inner {
+    Variant(usize),
+}
+enum Outer {
+    $0Variant { field1: Inner },
+}
+
+impl Outer {
+    fn new() -> Self {
+        Self::Variant { field1: Inner::Variant(42) }
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer::Variant { field1: Inner::Variant(x) } = self;
+        x
+    }
+}"#,
+            r#"
+enum Inner {
+    Variant(usize),
+}
+enum Outer {
+    Variant(Inner),
+}
+
+impl Outer {
+    fn new() -> Self {
+        Self::Variant(Inner::Variant(42))
+    }
+
+    fn into_inner_destructed(self) -> u32 {
+        let Outer::Variant(Inner::Variant(x)) = self;
+        x
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_variant_with_multi_file_references() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+//- /main.rs
+struct Inner;
+enum A {
+    $0Variant { field1: Inner },
+}
+
+mod foo;
+
+//- /foo.rs
+use crate::{A, Inner};
+fn f() {
+    let a = A::Variant { field1: Inner };
+}
+"#,
+            r#"
+//- /main.rs
+struct Inner;
+enum A {
+    Variant(Inner),
+}
+
+mod foo;
+
+//- /foo.rs
+use crate::{A, Inner};
+fn f() {
+    let a = A::Variant(Inner);
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_directly_used_variant() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+//- /main.rs
+struct Inner;
+enum A {
+    $0Variant { field1: Inner },
+}
+
+mod foo;
+
+//- /foo.rs
+use crate::{A::Variant, Inner};
+fn f() {
+    let a = Variant { field1: Inner };
+}
+"#,
+            r#"
+//- /main.rs
+struct Inner;
+enum A {
+    Variant(Inner),
+}
+
+mod foo;
+
+//- /foo.rs
+use crate::{A::Variant, Inner};
+fn f() {
+    let a = Variant(Inner);
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 8d5cab283d0..970e948dfd9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -9,7 +9,7 @@ use ide_db::{
     search::FileReference,
     FxHashSet, RootDatabase,
 };
-use itertools::{Itertools, Position};
+use itertools::Itertools;
 use syntax::{
     ast::{
         self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
@@ -298,37 +298,7 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
     let name = variant.name()?;
     let ty = generics
         .filter(|generics| generics.generic_params().count() > 0)
-        .map(|generics| {
-            let mut generic_str = String::with_capacity(8);
-
-            for (p, more) in generics.generic_params().with_position().map(|p| match p {
-                Position::First(p) | Position::Middle(p) => (p, true),
-                Position::Last(p) | Position::Only(p) => (p, false),
-            }) {
-                match p {
-                    ast::GenericParam::ConstParam(konst) => {
-                        if let Some(name) = konst.name() {
-                            generic_str.push_str(name.text().as_str());
-                        }
-                    }
-                    ast::GenericParam::LifetimeParam(lt) => {
-                        if let Some(lt) = lt.lifetime() {
-                            generic_str.push_str(lt.text().as_str());
-                        }
-                    }
-                    ast::GenericParam::TypeParam(ty) => {
-                        if let Some(name) = ty.name() {
-                            generic_str.push_str(name.text().as_str());
-                        }
-                    }
-                }
-                if more {
-                    generic_str.push_str(", ");
-                }
-            }
-
-            make::ty(&format!("{}<{}>", &name.text(), &generic_str))
-        })
+        .map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args())))
         .unwrap_or_else(|| make::ty(&name.text()));
 
     // change from a record to a tuple field list
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index e26c76da189..8b67982f915 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -1,4 +1,4 @@
-use hir::{HasSource, HirDisplay, Module, Semantics, TypeInfo};
+use hir::{Adt, HasSource, HirDisplay, Module, Semantics, TypeInfo};
 use ide_db::{
     base_db::FileId,
     defs::{Definition, NameRefClass},
@@ -145,7 +145,8 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
         return None;
     }
     let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
-    let (target, insert_offset) = get_method_target(ctx, &target_module, &impl_)?;
+    let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
+
     let function_builder =
         FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
     let text_range = call.syntax().text_range();
@@ -174,10 +175,11 @@ fn add_func_to_accumulator(
     label: String,
 ) -> Option<()> {
     acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
-        let function_template = function_builder.render();
+        let indent = IndentLevel::from_node(function_builder.target.syntax());
+        let function_template = function_builder.render(adt_name.is_some());
         let mut func = function_template.to_string(ctx.config.snippet_cap);
         if let Some(name) = adt_name {
-            func = format!("\nimpl {} {{\n{}\n}}", name, func);
+            func = format!("\n{}impl {} {{\n{}\n{}}}", indent, name, func, indent);
         }
         builder.edit_file(file);
         match ctx.config.snippet_cap {
@@ -307,7 +309,7 @@ impl FunctionBuilder {
         })
     }
 
-    fn render(self) -> FunctionTemplate {
+    fn render(self, is_method: bool) -> FunctionTemplate {
         let placeholder_expr = make::ext::expr_todo();
         let fn_body = make::block_expr(vec![], Some(placeholder_expr));
         let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
@@ -325,8 +327,14 @@ impl FunctionBuilder {
 
         match self.target {
             GeneratedFunctionTarget::BehindItem(it) => {
-                let indent = IndentLevel::from_node(&it);
-                leading_ws = format!("\n\n{}", indent);
+                let mut indent = IndentLevel::from_node(&it);
+                if is_method {
+                    indent = indent + 1;
+                    leading_ws = format!("{}", indent);
+                } else {
+                    leading_ws = format!("\n\n{}", indent);
+                }
+
                 fn_def = fn_def.indent(indent);
                 trailing_ws = String::new();
             }
@@ -411,14 +419,13 @@ fn get_fn_target(
 
 fn get_method_target(
     ctx: &AssistContext<'_>,
-    target_module: &Module,
     impl_: &Option<ast::Impl>,
+    adt: &Adt,
 ) -> Option<(GeneratedFunctionTarget, TextSize)> {
     let target = match impl_ {
         Some(impl_) => next_space_for_fn_in_impl(impl_)?,
         None => {
-            next_space_for_fn_in_module(ctx.sema.db, &target_module.definition_source(ctx.sema.db))?
-                .1
+            GeneratedFunctionTarget::BehindItem(adt.source(ctx.sema.db)?.syntax().value.clone())
         }
     };
     Some((target.clone(), get_insert_offset(&target)))
@@ -437,7 +444,7 @@ fn assoc_fn_target_info(
         return None;
     }
     let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
-    let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
+    let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
     let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
     Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset))
 }
@@ -1468,14 +1475,12 @@ fn foo() {S.bar$0();}
 ",
             r"
 struct S;
-fn foo() {S.bar();}
 impl S {
-
-
-fn bar(&self) ${0:-> _} {
-    todo!()
-}
+    fn bar(&self) ${0:-> _} {
+        todo!()
+    }
 }
+fn foo() {S.bar();}
 ",
         )
     }
@@ -1516,14 +1521,12 @@ fn foo() {s::S.bar$0();}
             r"
 mod s {
     pub struct S;
-impl S {
-
-
-    pub(crate) fn bar(&self) ${0:-> _} {
-        todo!()
+    impl S {
+        pub(crate) fn bar(&self) ${0:-> _} {
+            todo!()
+        }
     }
 }
-}
 fn foo() {s::S.bar();}
 ",
         )
@@ -1544,18 +1547,16 @@ mod s {
 ",
             r"
 struct S;
+impl S {
+    fn bar(&self) ${0:-> _} {
+        todo!()
+    }
+}
 mod s {
     fn foo() {
         super::S.bar();
     }
 }
-impl S {
-
-
-fn bar(&self) ${0:-> _} {
-    todo!()
-}
-}
 
 ",
         )
@@ -1571,14 +1572,12 @@ fn foo() {$0S.bar();}
 ",
             r"
 struct S;
-fn foo() {S.bar();}
 impl S {
-
-
-fn bar(&self) ${0:-> _} {
-    todo!()
-}
+    fn bar(&self) ${0:-> _} {
+        todo!()
+    }
 }
+fn foo() {S.bar();}
 ",
         )
     }
@@ -1593,14 +1592,12 @@ fn foo() {S::bar$0();}
 ",
             r"
 struct S;
-fn foo() {S::bar();}
 impl S {
-
-
-fn bar() ${0:-> _} {
-    todo!()
-}
+    fn bar() ${0:-> _} {
+        todo!()
+    }
 }
+fn foo() {S::bar();}
 ",
         )
     }
@@ -1641,14 +1638,12 @@ fn foo() {s::S::bar$0();}
             r"
 mod s {
     pub struct S;
-impl S {
-
-
-    pub(crate) fn bar() ${0:-> _} {
-        todo!()
+    impl S {
+        pub(crate) fn bar() ${0:-> _} {
+            todo!()
+        }
     }
 }
-}
 fn foo() {s::S::bar();}
 ",
         )
@@ -1664,14 +1659,12 @@ fn foo() {$0S::bar();}
 ",
             r"
 struct S;
-fn foo() {S::bar();}
 impl S {
-
-
-fn bar() ${0:-> _} {
-    todo!()
-}
+    fn bar() ${0:-> _} {
+        todo!()
+    }
 }
+fn foo() {S::bar();}
 ",
         )
     }
@@ -1841,15 +1834,13 @@ fn main() {
 ",
             r"
 enum Foo {}
-fn main() {
-    Foo::new();
-}
 impl Foo {
-
-
-fn new() ${0:-> _} {
-    todo!()
+    fn new() ${0:-> _} {
+        todo!()
+    }
 }
+fn main() {
+    Foo::new();
 }
 ",
         )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index 68287a20bf8..307cea3d0a4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -52,6 +52,7 @@ mod tests {
 
     use super::*;
 
+    // FIXME: break up into separate test fns
     #[test]
     fn test_add_impl() {
         check_assist(
@@ -136,6 +137,18 @@ mod tests {
 
         check_assist(
             generate_impl,
+            r#"
+            struct Defaulted<const N: i32 = 0> {}$0"#,
+            r#"
+            struct Defaulted<const N: i32 = 0> {}
+
+            impl<const N: i32> Defaulted<N> {
+                $0
+            }"#,
+        );
+
+        check_assist(
+            generate_impl,
             r#"pub trait Trait {}
 struct Struct<T>$0
 where
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 82bcc3dfa5d..a07318cefad 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -121,6 +121,7 @@ mod handlers {
     mod convert_iter_for_each_to_for;
     mod convert_let_else_to_match;
     mod convert_tuple_struct_to_named_struct;
+    mod convert_named_struct_to_tuple_struct;
     mod convert_to_guarded_return;
     mod convert_two_arm_bool_match_to_matches_macro;
     mod convert_while_to_loop;
@@ -218,6 +219,7 @@ mod handlers {
             convert_iter_for_each_to_for::convert_iter_for_each_to_for,
             convert_iter_for_each_to_for::convert_for_loop_with_for_each,
             convert_let_else_to_match::convert_let_else_to_match,
+            convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
             convert_to_guarded_return::convert_to_guarded_return,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
             convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index a3bb66e379e..f7f2417d074 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -232,6 +232,7 @@ fn assist_order_field_struct() {
     assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
     assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
     assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
+    assert_eq!(assists.next().expect("expected assist").label, "Convert to tuple struct");
     assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index d403f86c6d8..2c4000efe0f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -408,6 +408,47 @@ fn main() {
 }
 
 #[test]
+fn doctest_convert_named_struct_to_tuple_struct() {
+    check_doc_test(
+        "convert_named_struct_to_tuple_struct",
+        r#####"
+struct Point$0 { x: f32, y: f32 }
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Point { x, y }
+    }
+
+    pub fn x(&self) -> f32 {
+        self.x
+    }
+
+    pub fn y(&self) -> f32 {
+        self.y
+    }
+}
+"#####,
+        r#####"
+struct Point(f32, f32);
+
+impl Point {
+    pub fn new(x: f32, y: f32) -> Self {
+        Point(x, y)
+    }
+
+    pub fn x(&self) -> f32 {
+        self.0
+    }
+
+    pub fn y(&self) -> f32 {
+        self.1
+    }
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_convert_to_guarded_return() {
     check_doc_test(
         "convert_to_guarded_return",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 4ab6e2627fa..38396cd7d7b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -2,8 +2,6 @@
 
 use std::ops;
 
-use itertools::Itertools;
-
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 use hir::{db::HirDatabase, HirDisplay, Semantics};
 use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
@@ -15,7 +13,7 @@ use syntax::{
         edit_in_place::{AttrsOwnerEdit, Removable},
         make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
-    ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
+    ted, AstNode, AstToken, Direction, SourceFile,
     SyntaxKind::*,
     SyntaxNode, TextRange, TextSize, T,
 };
@@ -424,34 +422,44 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
 }
 
 fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
-    let generic_params = adt.generic_param_list();
+    // Ensure lifetime params are before type & const params
+    let generic_params = adt.generic_param_list().map(|generic_params| {
+        let lifetime_params =
+            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
+        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
+            // remove defaults since they can't be specified in impls
+            match param {
+                ast::TypeOrConstParam::Type(param) => {
+                    let param = param.clone_for_update();
+                    param.remove_default();
+                    Some(ast::GenericParam::TypeParam(param))
+                }
+                ast::TypeOrConstParam::Const(param) => {
+                    let param = param.clone_for_update();
+                    param.remove_default();
+                    Some(ast::GenericParam::ConstParam(param))
+                }
+            }
+        });
+
+        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
+    });
+
+    // FIXME: use syntax::make & mutable AST apis instead
+    // `trait_text` and `code` can't be opaque blobs of text
     let mut buf = String::with_capacity(code.len());
+
+    // Copy any cfg attrs from the original adt
     buf.push_str("\n\n");
-    adt.attrs()
-        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
-        .for_each(|attr| buf.push_str(format!("{}\n", attr).as_str()));
+    let cfg_attrs = adt
+        .attrs()
+        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
+    cfg_attrs.for_each(|attr| buf.push_str(&format!("{attr}\n")));
+
+    // `impl{generic_params} {trait_text} for {name}{generic_params.to_generic_args()}`
     buf.push_str("impl");
     if let Some(generic_params) = &generic_params {
-        let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
-        let toc_params = generic_params.type_or_const_params().map(|toc_param| {
-            let type_param = match toc_param {
-                ast::TypeOrConstParam::Type(x) => x,
-                ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(),
-            };
-            let mut buf = String::new();
-            if let Some(it) = type_param.name() {
-                format_to!(buf, "{}", it.syntax());
-            }
-            if let Some(it) = type_param.colon_token() {
-                format_to!(buf, "{} ", it);
-            }
-            if let Some(it) = type_param.type_bound_list() {
-                format_to!(buf, "{}", it.syntax());
-            }
-            buf
-        });
-        let generics = lifetimes.chain(toc_params).format(", ");
-        format_to!(buf, "<{}>", generics);
+        format_to!(buf, "{generic_params}");
     }
     buf.push(' ');
     if let Some(trait_text) = trait_text {
@@ -460,23 +468,15 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
     }
     buf.push_str(&adt.name().unwrap().text());
     if let Some(generic_params) = generic_params {
-        let lifetime_params = generic_params
-            .lifetime_params()
-            .filter_map(|it| it.lifetime())
-            .map(|it| SmolStr::from(it.text()));
-        let toc_params = generic_params
-            .type_or_const_params()
-            .filter_map(|it| it.name())
-            .map(|it| SmolStr::from(it.text()));
-        format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", "))
+        format_to!(buf, "{}", generic_params.to_generic_args());
     }
 
     match adt.where_clause() {
         Some(where_clause) => {
-            format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
+            format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
         }
         None => {
-            format_to!(buf, " {{\n{}\n}}", code);
+            format_to!(buf, " {{\n{code}\n}}");
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
index 8c9d6b22864..75835bce95d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
@@ -11,10 +11,10 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.3"
+itertools = "0.10.5"
 
-once_cell = "1.12.0"
-smallvec = "1.9.0"
+once_cell = "1.15.0"
+smallvec = "1.10.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 97b90c62dd7..296dfc14250 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -19,6 +19,7 @@ pub(crate) mod snippet;
 pub(crate) mod r#type;
 pub(crate) mod use_;
 pub(crate) mod vis;
+pub(crate) mod env_vars;
 
 use std::iter;
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
new file mode 100644
index 00000000000..09e95e53de6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -0,0 +1,150 @@
+//! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
+use hir::Semantics;
+use ide_db::{syntax_helpers::node_ext::macro_call_for_string_token, RootDatabase};
+use syntax::ast::{self, IsString};
+
+use crate::{
+    completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
+};
+
+const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
+    ("CARGO","Path to the cargo binary performing the build"),
+    ("CARGO_MANIFEST_DIR","The directory containing the manifest of your package"),
+    ("CARGO_PKG_VERSION","The full version of your package"),
+    ("CARGO_PKG_VERSION_MAJOR","The major version of your package"),
+    ("CARGO_PKG_VERSION_MINOR","The minor version of your package"),
+    ("CARGO_PKG_VERSION_PATCH","The patch version of your package"),
+    ("CARGO_PKG_VERSION_PRE","The pre-release version of your package"),
+    ("CARGO_PKG_AUTHORS","Colon separated list of authors from the manifest of your package"),
+    ("CARGO_PKG_NAME","The name of your package"),
+    ("CARGO_PKG_DESCRIPTION","The description from the manifest of your package"),
+    ("CARGO_PKG_HOMEPAGE","The home page from the manifest of your package"),
+    ("CARGO_PKG_REPOSITORY","The repository from the manifest of your package"),
+    ("CARGO_PKG_LICENSE","The license from the manifest of your package"),
+    ("CARGO_PKG_LICENSE_FILE","The license file from the manifest of your package"),
+    ("CARGO_PKG_RUST_VERSION","The Rust version from the manifest of your package. Note that this is the minimum Rust version supported by the package, not the current Rust version"),
+    ("CARGO_CRATE_NAME","The name of the crate that is currently being compiled"),
+    ("CARGO_BIN_NAME","The name of the binary that is currently being compiled (if it is a binary). This name does not include any file extension, such as .exe"),
+    ("CARGO_PRIMARY_PACKAGE","This environment variable will be set if the package being built is primary. Primary packages are the ones the user selected on the command-line, either with -p flags or the defaults based on the current directory and the default workspace members. This environment variable will not be set when building dependencies. This is only set when compiling the package (not when running binaries or tests)"),
+    ("CARGO_TARGET_TMPDIR","Only set when building integration test or benchmark code. This is a path to a directory inside the target directory where integration tests or benchmarks are free to put any data needed by the tests/benches. Cargo initially creates this directory but doesn't manage its content in any way, this is the responsibility of the test code")
+];
+
+pub(crate) fn complete_cargo_env_vars(
+    acc: &mut Completions,
+    ctx: &CompletionContext<'_>,
+    expanded: &ast::String,
+) -> Option<()> {
+    guard_env_macro(expanded, &ctx.sema)?;
+    let range = expanded.text_range_between_quotes()?;
+
+    CARGO_DEFINED_VARS.iter().for_each(|(var, detail)| {
+        let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var);
+        item.detail(*detail);
+        item.add_to(acc);
+    });
+
+    Some(())
+}
+
+fn guard_env_macro(string: &ast::String, semantics: &Semantics<'_, RootDatabase>) -> Option<()> {
+    let call = macro_call_for_string_token(string)?;
+    let name = call.path()?.segment()?.name_ref()?;
+    let makro = semantics.resolve_macro_call(&call)?;
+    let db = semantics.db;
+
+    match name.text().as_str() {
+        "env" | "option_env" if makro.kind(db) == hir::MacroKind::BuiltIn => Some(()),
+        _ => None,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_edit, completion_list};
+
+    fn check(macro_name: &str) {
+        check_edit(
+            "CARGO_BIN_NAME",
+            &format!(
+                r#"
+            #[rustc_builtin_macro]
+            macro_rules! {} {{
+                ($var:literal) => {{ 0 }}
+            }}
+
+            fn main() {{
+                let foo = {}!("CAR$0");
+            }}
+        "#,
+                macro_name, macro_name
+            ),
+            &format!(
+                r#"
+            #[rustc_builtin_macro]
+            macro_rules! {} {{
+                ($var:literal) => {{ 0 }}
+            }}
+
+            fn main() {{
+                let foo = {}!("CARGO_BIN_NAME");
+            }}
+        "#,
+                macro_name, macro_name
+            ),
+        );
+    }
+    #[test]
+    fn completes_env_variable_in_env() {
+        check("env")
+    }
+
+    #[test]
+    fn completes_env_variable_in_option_env() {
+        check("option_env");
+    }
+
+    #[test]
+    fn doesnt_complete_in_random_strings() {
+        let fixture = r#"
+            fn main() {
+                let foo = "CA$0";
+            }
+        "#;
+
+        let completions = completion_list(fixture);
+        assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
+    }
+
+    #[test]
+    fn doesnt_complete_in_random_macro() {
+        let fixture = r#"
+            macro_rules! bar {
+                ($($arg:tt)*) => { 0 }
+            }
+
+            fn main() {
+                let foo = bar!("CA$0");
+
+            }
+        "#;
+
+        let completions = completion_list(fixture);
+        assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
+    }
+
+    #[test]
+    fn doesnt_complete_for_shadowed_macro() {
+        let fixture = r#"
+            macro_rules! env {
+                ($var:literal) => { 0 }
+            }
+
+            fn main() {
+                let foo = env!("CA$0");
+            }
+        "#;
+
+        let completions = completion_list(fixture);
+        assert!(completions.is_empty(), "Completions weren't empty: {}", completions)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index a5e854b74df..9850813a0ce 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -1,4 +1,4 @@
-//! See `CompletionContext` structure.
+//! See [`CompletionContext`] structure.
 
 mod analysis;
 #[cfg(test)]
@@ -23,7 +23,10 @@ use syntax::{
 };
 use text_edit::Indel;
 
-use crate::CompletionConfig;
+use crate::{
+    context::analysis::{expand_and_analyze, AnalysisResult},
+    CompletionConfig,
+};
 
 const COMPLETION_MARKER: &str = "intellijRulezz";
 
@@ -561,15 +564,27 @@ impl<'a> CompletionContext<'a> {
             let edit = Indel::insert(offset, COMPLETION_MARKER.to_string());
             parse.reparse(&edit).tree()
         };
-        let fake_ident_token =
-            file_with_fake_ident.syntax().token_at_offset(offset).right_biased()?;
 
+        // always pick the token to the immediate left of the cursor, as that is what we are actually
+        // completing on
         let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
-        let token = sema.descend_into_macros_single(original_token.clone());
+
+        let AnalysisResult {
+            analysis,
+            expected: (expected_type, expected_name),
+            qualifier_ctx,
+            token,
+            offset,
+        } = expand_and_analyze(
+            &sema,
+            original_file.syntax().clone(),
+            file_with_fake_ident.syntax().clone(),
+            offset,
+            &original_token,
+        )?;
 
         // adjust for macro input, this still fails if there is no token written yet
-        let scope_offset = if original_token == token { offset } else { token.text_range().end() };
-        let scope = sema.scope_at_offset(&token.parent()?, scope_offset)?;
+        let scope = sema.scope_at_offset(&token.parent()?, offset)?;
 
         let krate = scope.krate();
         let module = scope.module();
@@ -583,7 +598,7 @@ impl<'a> CompletionContext<'a> {
 
         let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count();
 
-        let mut ctx = CompletionContext {
+        let ctx = CompletionContext {
             sema,
             scope,
             db,
@@ -593,19 +608,13 @@ impl<'a> CompletionContext<'a> {
             token,
             krate,
             module,
-            expected_name: None,
-            expected_type: None,
-            qualifier_ctx: Default::default(),
+            expected_name,
+            expected_type,
+            qualifier_ctx,
             locals,
             depth_from_crate_root,
         };
-        let ident_ctx = ctx.expand_and_analyze(
-            original_file.syntax().clone(),
-            file_with_fake_ident.syntax().clone(),
-            offset,
-            fake_ident_token,
-        )?;
-        Some((ctx, ident_ctx))
+        Some((ctx, analysis))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 01dd9a234f5..04111ec7efa 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -11,1063 +11,1094 @@ use syntax::{
 };
 
 use crate::context::{
-    AttrCtx, CompletionAnalysis, CompletionContext, DotAccess, DotAccessKind, ExprCtx,
-    ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext,
-    NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathKind, PatternContext,
-    PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget, TypeLocation,
-    COMPLETION_MARKER,
+    AttrCtx, CompletionAnalysis, DotAccess, DotAccessKind, ExprCtx, ItemListKind, LifetimeContext,
+    LifetimeKind, NameContext, NameKind, NameRefContext, NameRefKind, ParamContext, ParamKind,
+    PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
+    TypeAscriptionTarget, TypeLocation, COMPLETION_MARKER,
 };
 
-impl<'a> CompletionContext<'a> {
-    /// Expand attributes and macro calls at the current cursor position for both the original file
-    /// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
-    /// and speculative states stay in sync.
-    pub(super) fn expand_and_analyze(
-        &mut self,
-        mut original_file: SyntaxNode,
-        mut speculative_file: SyntaxNode,
-        mut offset: TextSize,
-        mut fake_ident_token: SyntaxToken,
-    ) -> Option<CompletionAnalysis> {
-        let _p = profile::span("CompletionContext::expand_and_fill");
-        let mut derive_ctx = None;
-
-        'expansion: loop {
-            let parent_item =
-                |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
-            let ancestor_items = iter::successors(
-                Option::zip(
-                    find_node_at_offset::<ast::Item>(&original_file, offset),
-                    find_node_at_offset::<ast::Item>(&speculative_file, offset),
+struct ExpansionResult {
+    original_file: SyntaxNode,
+    speculative_file: SyntaxNode,
+    offset: TextSize,
+    fake_ident_token: SyntaxToken,
+    derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
+}
+
+pub(super) struct AnalysisResult {
+    pub(super) analysis: CompletionAnalysis,
+    pub(super) expected: (Option<Type>, Option<ast::NameOrNameRef>),
+    pub(super) qualifier_ctx: QualifierCtx,
+    pub(super) token: SyntaxToken,
+    pub(super) offset: TextSize,
+}
+
+pub(super) fn expand_and_analyze(
+    sema: &Semantics<'_, RootDatabase>,
+    original_file: SyntaxNode,
+    speculative_file: SyntaxNode,
+    offset: TextSize,
+    original_token: &SyntaxToken,
+) -> Option<AnalysisResult> {
+    // as we insert after the offset, right biased will *always* pick the identifier no matter
+    // if there is an ident already typed or not
+    let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?;
+    // the relative offset between the cursor and the *identifier* token we are completing on
+    let relative_offset = offset - fake_ident_token.text_range().start();
+    // make the offset point to the start of the original token, as that is what the
+    // intermediate offsets calculated in expansion always points to
+    let offset = offset - relative_offset;
+    let expansion = expand(sema, original_file, speculative_file, offset, fake_ident_token);
+    // add the relative offset back, so that left_biased finds the proper token
+    let offset = expansion.offset + relative_offset;
+    let token = expansion.original_file.token_at_offset(offset).left_biased()?;
+
+    analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
+        AnalysisResult { analysis, expected, qualifier_ctx, token, offset }
+    })
+}
+
+/// Expand attributes and macro calls at the current cursor position for both the original file
+/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
+/// and speculative states stay in sync.
+fn expand(
+    sema: &Semantics<'_, RootDatabase>,
+    mut original_file: SyntaxNode,
+    mut speculative_file: SyntaxNode,
+    mut offset: TextSize,
+    mut fake_ident_token: SyntaxToken,
+) -> ExpansionResult {
+    let _p = profile::span("CompletionContext::expand");
+    let mut derive_ctx = None;
+
+    'expansion: loop {
+        let parent_item =
+            |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
+        let ancestor_items = iter::successors(
+            Option::zip(
+                find_node_at_offset::<ast::Item>(&original_file, offset),
+                find_node_at_offset::<ast::Item>(&speculative_file, offset),
+            ),
+            |(a, b)| parent_item(a).zip(parent_item(b)),
+        );
+
+        // first try to expand attributes as these are always the outermost macro calls
+        'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
+            match (
+                sema.expand_attr_macro(&actual_item),
+                sema.speculative_expand_attr_macro(
+                    &actual_item,
+                    &item_with_fake_ident,
+                    fake_ident_token.clone(),
                 ),
-                |(a, b)| parent_item(a).zip(parent_item(b)),
-            );
-
-            // first try to expand attributes as these are always the outermost macro calls
-            'ancestors: for (actual_item, item_with_fake_ident) in ancestor_items {
-                match (
-                    self.sema.expand_attr_macro(&actual_item),
-                    self.sema.speculative_expand_attr_macro(
-                        &actual_item,
-                        &item_with_fake_ident,
-                        fake_ident_token.clone(),
-                    ),
-                ) {
-                    // maybe parent items have attributes, so continue walking the ancestors
-                    (None, None) => continue 'ancestors,
-                    // successful expansions
-                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
-                        let new_offset = fake_mapped_token.text_range().start();
-                        if new_offset > actual_expansion.text_range().end() {
-                            // offset outside of bounds from the original expansion,
-                            // stop here to prevent problems from happening
-                            break 'expansion;
-                        }
-                        original_file = actual_expansion;
-                        speculative_file = fake_expansion;
-                        fake_ident_token = fake_mapped_token;
-                        offset = new_offset;
-                        continue 'expansion;
+            ) {
+                // maybe parent items have attributes, so continue walking the ancestors
+                (None, None) => continue 'ancestors,
+                // successful expansions
+                (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
+                    let new_offset = fake_mapped_token.text_range().start();
+                    if new_offset > actual_expansion.text_range().end() {
+                        // offset outside of bounds from the original expansion,
+                        // stop here to prevent problems from happening
+                        break 'expansion;
                     }
-                    // exactly one expansion failed, inconsistent state so stop expanding completely
-                    _ => break 'expansion,
+                    original_file = actual_expansion;
+                    speculative_file = fake_expansion;
+                    fake_ident_token = fake_mapped_token;
+                    offset = new_offset;
+                    continue 'expansion;
                 }
+                // exactly one expansion failed, inconsistent state so stop expanding completely
+                _ => break 'expansion,
             }
+        }
 
-            // No attributes have been expanded, so look for macro_call! token trees or derive token trees
-            let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
-                Some(it) => it,
-                None => break 'expansion,
-            };
-            let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
-                Some(it) => it,
-                None => break 'expansion,
-            };
+        // No attributes have been expanded, so look for macro_call! token trees or derive token trees
+        let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
+            Some(it) => it,
+            None => break 'expansion,
+        };
+        let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
+            Some(it) => it,
+            None => break 'expansion,
+        };
 
-            // Expand pseudo-derive expansion
-            if let (Some(orig_attr), Some(spec_attr)) = (
-                orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
-                spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
+        // Expand pseudo-derive expansion
+        if let (Some(orig_attr), Some(spec_attr)) = (
+            orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
+            spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
+        ) {
+            if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = (
+                sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
+                sema.speculative_expand_derive_as_pseudo_attr_macro(
+                    &orig_attr,
+                    &spec_attr,
+                    fake_ident_token.clone(),
+                ),
             ) {
-                if let (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) = (
-                    self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
-                    self.sema.speculative_expand_derive_as_pseudo_attr_macro(
-                        &orig_attr,
-                        &spec_attr,
-                        fake_ident_token.clone(),
-                    ),
-                ) {
-                    derive_ctx = Some((
-                        actual_expansion,
-                        fake_expansion,
-                        fake_mapped_token.text_range().start(),
-                        orig_attr,
-                    ));
-                }
-                // at this point we won't have any more successful expansions, so stop
+                derive_ctx = Some((
+                    actual_expansion,
+                    fake_expansion,
+                    fake_mapped_token.text_range().start(),
+                    orig_attr,
+                ));
+            }
+            // at this point we won't have any more successful expansions, so stop
+            break 'expansion;
+        }
+
+        // Expand fn-like macro calls
+        if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
+            orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
+            spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
+        ) {
+            let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
+            let mac_call_path1 =
+                macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
+
+            // inconsistent state, stop expanding
+            if mac_call_path0 != mac_call_path1 {
                 break 'expansion;
             }
+            let speculative_args = match macro_call_with_fake_ident.token_tree() {
+                Some(tt) => tt,
+                None => break 'expansion,
+            };
 
-            // Expand fn-like macro calls
-            if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
-                orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
-                spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
+            match (
+                sema.expand(&actual_macro_call),
+                sema.speculative_expand(
+                    &actual_macro_call,
+                    &speculative_args,
+                    fake_ident_token.clone(),
+                ),
             ) {
-                let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
-                let mac_call_path1 =
-                    macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
-
-                // inconsistent state, stop expanding
-                if mac_call_path0 != mac_call_path1 {
-                    break 'expansion;
-                }
-                let speculative_args = match macro_call_with_fake_ident.token_tree() {
-                    Some(tt) => tt,
-                    None => break 'expansion,
-                };
-
-                match (
-                    self.sema.expand(&actual_macro_call),
-                    self.sema.speculative_expand(
-                        &actual_macro_call,
-                        &speculative_args,
-                        fake_ident_token.clone(),
-                    ),
-                ) {
-                    // successful expansions
-                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
-                        let new_offset = fake_mapped_token.text_range().start();
-                        if new_offset > actual_expansion.text_range().end() {
-                            // offset outside of bounds from the original expansion,
-                            // stop here to prevent problems from happening
-                            break 'expansion;
-                        }
-                        original_file = actual_expansion;
-                        speculative_file = fake_expansion;
-                        fake_ident_token = fake_mapped_token;
-                        offset = new_offset;
-                        continue 'expansion;
+                // successful expansions
+                (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
+                    let new_offset = fake_mapped_token.text_range().start();
+                    if new_offset > actual_expansion.text_range().end() {
+                        // offset outside of bounds from the original expansion,
+                        // stop here to prevent problems from happening
+                        break 'expansion;
                     }
-                    // at least on expansion failed, we won't have anything to expand from this point
-                    // onwards so break out
-                    _ => break 'expansion,
+                    original_file = actual_expansion;
+                    speculative_file = fake_expansion;
+                    fake_ident_token = fake_mapped_token;
+                    offset = new_offset;
+                    continue 'expansion;
                 }
+                // at least on expansion failed, we won't have anything to expand from this point
+                // onwards so break out
+                _ => break 'expansion,
             }
-
-            // none of our states have changed so stop the loop
-            break 'expansion;
         }
 
-        self.analyze(&original_file, speculative_file, offset, derive_ctx)
+        // none of our states have changed so stop the loop
+        break 'expansion;
     }
+    ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx }
+}
 
-    /// Calculate the expected type and name of the cursor position.
-    fn expected_type_and_name(
-        &self,
-        name_like: &ast::NameLike,
-    ) -> (Option<Type>, Option<NameOrNameRef>) {
-        let mut node = match self.token.parent() {
-            Some(it) => it,
-            None => return (None, None),
-        };
+/// Fill the completion context, this is what does semantic reasoning about the surrounding context
+/// of the completion location.
+fn analyze(
+    sema: &Semantics<'_, RootDatabase>,
+    expansion_result: ExpansionResult,
+    original_token: &SyntaxToken,
+    self_token: &SyntaxToken,
+) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
+    let _p = profile::span("CompletionContext::analyze");
+    let ExpansionResult { original_file, speculative_file, offset, fake_ident_token, derive_ctx } =
+        expansion_result;
+    let syntax_element = NodeOrToken::Token(fake_ident_token);
+    if is_in_token_of_for_loop(syntax_element.clone()) {
+        // for pat $0
+        // there is nothing to complete here except `in` keyword
+        // don't bother populating the context
+        // FIXME: the completion calculations should end up good enough
+        // such that this special case becomes unnecessary
+        return None;
+    }
 
-        let strip_refs = |mut ty: Type| match name_like {
-            ast::NameLike::NameRef(n) => {
-                let p = match n.syntax().parent() {
-                    Some(it) => it,
-                    None => return ty,
-                };
-                let top_syn = match_ast! {
-                    match p {
-                        ast::FieldExpr(e) => e
-                            .syntax()
-                            .ancestors()
-                            .map_while(ast::FieldExpr::cast)
-                            .last()
-                            .map(|it| it.syntax().clone()),
-                        ast::PathSegment(e) => e
-                            .syntax()
-                            .ancestors()
-                            .skip(1)
-                            .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
-                            .find_map(ast::PathExpr::cast)
-                            .map(|it| it.syntax().clone()),
-                        _ => None
-                    }
+    // Overwrite the path kind for derives
+    if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
+        if let Some(ast::NameLike::NameRef(name_ref)) =
+            find_node_at_offset(&file_with_fake_ident, offset)
+        {
+            let parent = name_ref.syntax().parent()?;
+            let (mut nameref_ctx, _) = classify_name_ref(&sema, &original_file, name_ref, parent)?;
+            if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
+                path_ctx.kind = PathKind::Derive {
+                    existing_derives: sema
+                        .resolve_derive_macro(&origin_attr)
+                        .into_iter()
+                        .flatten()
+                        .flatten()
+                        .collect(),
                 };
-                let top_syn = match top_syn {
-                    Some(it) => it,
-                    None => return ty,
-                };
-                for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
-                    cov_mark::hit!(expected_type_fn_param_ref);
-                    ty = ty.strip_reference();
-                }
-                ty
             }
-            _ => ty,
-        };
+            return Some((
+                CompletionAnalysis::NameRef(nameref_ctx),
+                (None, None),
+                QualifierCtx::default(),
+            ));
+        }
+        return None;
+    }
 
-        loop {
-            break match_ast! {
-                match node {
-                    ast::LetStmt(it) => {
-                        cov_mark::hit!(expected_type_let_with_leading_char);
-                        cov_mark::hit!(expected_type_let_without_leading_char);
-                        let ty = it.pat()
-                            .and_then(|pat| self.sema.type_of_pat(&pat))
-                            .or_else(|| it.initializer().and_then(|it| self.sema.type_of_expr(&it)))
-                            .map(TypeInfo::original);
-                        let name = match it.pat() {
-                            Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
-                            Some(_) | None => None,
-                        };
-
-                        (ty, name)
-                    },
-                    ast::LetExpr(it) => {
-                        cov_mark::hit!(expected_type_if_let_without_leading_char);
-                        let ty = it.pat()
-                            .and_then(|pat| self.sema.type_of_pat(&pat))
-                            .or_else(|| it.expr().and_then(|it| self.sema.type_of_expr(&it)))
-                            .map(TypeInfo::original);
-                        (ty, None)
-                    },
-                    ast::ArgList(_) => {
-                        cov_mark::hit!(expected_type_fn_param);
-                        ActiveParameter::at_token(
-                            &self.sema,
-                            self.token.clone(),
-                        ).map(|ap| {
-                            let name = ap.ident().map(NameOrNameRef::Name);
-
-                            let ty = strip_refs(ap.ty);
-                            (Some(ty), name)
-                        })
-                        .unwrap_or((None, None))
-                    },
-                    ast::RecordExprFieldList(it) => {
-                        // wouldn't try {} be nice...
-                        (|| {
-                            if self.token.kind() == T![..]
-                                || self.token.prev_token().map(|t| t.kind()) == Some(T![..])
-                            {
-                                cov_mark::hit!(expected_type_struct_func_update);
-                                let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?;
-                                let ty = self.sema.type_of_expr(&record_expr.into())?;
-                                Some((
-                                    Some(ty.original),
-                                    None
-                                ))
-                            } else {
-                                cov_mark::hit!(expected_type_struct_field_without_leading_char);
-                                let expr_field = self.token.prev_sibling_or_token()?
-                                    .into_node()
-                                    .and_then(ast::RecordExprField::cast)?;
-                                let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
-                                Some((
-                                    Some(ty),
-                                    expr_field.field_name().map(NameOrNameRef::NameRef),
-                                ))
-                            }
-                        })().unwrap_or((None, None))
-                    },
-                    ast::RecordExprField(it) => {
-                        if let Some(expr) = it.expr() {
-                            cov_mark::hit!(expected_type_struct_field_with_leading_char);
-                            (
-                                self.sema.type_of_expr(&expr).map(TypeInfo::original),
-                                it.field_name().map(NameOrNameRef::NameRef),
-                            )
-                        } else {
-                            cov_mark::hit!(expected_type_struct_field_followed_by_comma);
-                            let ty = self.sema.resolve_record_field(&it)
-                                .map(|(_, _, ty)| ty);
-                            (
-                                ty,
-                                it.field_name().map(NameOrNameRef::NameRef),
-                            )
-                        }
-                    },
-                    // match foo { $0 }
-                    // match foo { ..., pat => $0 }
-                    ast::MatchExpr(it) => {
-                        let on_arrow = previous_non_trivia_token(self.token.clone()).map_or(false, |it| T![=>] == it.kind());
-
-                        let ty = if on_arrow {
-                            // match foo { ..., pat => $0 }
-                            cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
-                            cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
-                            self.sema.type_of_expr(&it.into())
-                        } else {
-                            // match foo { $0 }
-                            cov_mark::hit!(expected_type_match_arm_without_leading_char);
-                            it.expr().and_then(|e| self.sema.type_of_expr(&e))
-                        }.map(TypeInfo::original);
-                        (ty, None)
-                    },
-                    ast::IfExpr(it) => {
-                        let ty = it.condition()
-                            .and_then(|e| self.sema.type_of_expr(&e))
-                            .map(TypeInfo::original);
-                        (ty, None)
-                    },
-                    ast::IdentPat(it) => {
-                        cov_mark::hit!(expected_type_if_let_with_leading_char);
-                        cov_mark::hit!(expected_type_match_arm_with_leading_char);
-                        let ty = self.sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original);
-                        (ty, None)
-                    },
-                    ast::Fn(it) => {
-                        cov_mark::hit!(expected_type_fn_ret_with_leading_char);
-                        cov_mark::hit!(expected_type_fn_ret_without_leading_char);
-                        let def = self.sema.to_def(&it);
-                        (def.map(|def| def.ret_type(self.db)), None)
-                    },
-                    ast::ClosureExpr(it) => {
-                        let ty = self.sema.type_of_expr(&it.into());
-                        ty.and_then(|ty| ty.original.as_callable(self.db))
-                            .map(|c| (Some(c.return_type()), None))
-                            .unwrap_or((None, None))
-                    },
-                    ast::ParamList(_) => (None, None),
-                    ast::Stmt(_) => (None, None),
-                    ast::Item(_) => (None, None),
-                    _ => {
-                        match node.parent() {
-                            Some(n) => {
-                                node = n;
-                                continue;
-                            },
-                            None => (None, None),
-                        }
-                    },
+    let name_like = match find_node_at_offset(&speculative_file, offset) {
+        Some(it) => it,
+        None => {
+            let analysis = if let Some(original) = ast::String::cast(original_token.clone()) {
+                CompletionAnalysis::String {
+                    original,
+                    expanded: ast::String::cast(self_token.clone()),
+                }
+            } else {
+                // Fix up trailing whitespace problem
+                // #[attr(foo = $0
+                let token = syntax::algo::skip_trivia_token(self_token.clone(), Direction::Prev)?;
+                let p = token.parent()?;
+                if p.kind() == SyntaxKind::TOKEN_TREE
+                    && p.ancestors().any(|it| it.kind() == SyntaxKind::META)
+                {
+                    let colon_prefix = previous_non_trivia_token(self_token.clone())
+                        .map_or(false, |it| T![:] == it.kind());
+                    CompletionAnalysis::UnexpandedAttrTT {
+                        fake_attribute_under_caret: syntax_element
+                            .ancestors()
+                            .find_map(ast::Attr::cast),
+                        colon_prefix,
+                    }
+                } else {
+                    return None;
                 }
             };
+            return Some((analysis, (None, None), QualifierCtx::default()));
         }
-    }
-
-    /// Fill the completion context, this is what does semantic reasoning about the surrounding context
-    /// of the completion location.
-    fn analyze(
-        &mut self,
-        original_file: &SyntaxNode,
-        file_with_fake_ident: SyntaxNode,
-        offset: TextSize,
-        derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
-    ) -> Option<CompletionAnalysis> {
-        let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased()?;
-        let syntax_element = NodeOrToken::Token(fake_ident_token);
-        if is_in_token_of_for_loop(syntax_element.clone()) {
-            // for pat $0
-            // there is nothing to complete here except `in` keyword
-            // don't bother populating the context
-            // FIXME: the completion calculations should end up good enough
-            // such that this special case becomes unnecessary
-            return None;
+    };
+    let expected = expected_type_and_name(sema, &self_token, &name_like);
+    let mut qual_ctx = QualifierCtx::default();
+    let analysis = match name_like {
+        ast::NameLike::Lifetime(lifetime) => {
+            CompletionAnalysis::Lifetime(classify_lifetime(sema, &original_file, lifetime)?)
+        }
+        ast::NameLike::NameRef(name_ref) => {
+            let parent = name_ref.syntax().parent()?;
+            let (nameref_ctx, qualifier_ctx) =
+                classify_name_ref(sema, &original_file, name_ref, parent.clone())?;
+            qual_ctx = qualifier_ctx;
+            CompletionAnalysis::NameRef(nameref_ctx)
+        }
+        ast::NameLike::Name(name) => {
+            let name_ctx = classify_name(sema, &original_file, name)?;
+            CompletionAnalysis::Name(name_ctx)
         }
+    };
+    Some((analysis, expected, qual_ctx))
+}
 
-        // Overwrite the path kind for derives
-        if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
-            if let Some(ast::NameLike::NameRef(name_ref)) =
-                find_node_at_offset(&file_with_fake_ident, offset)
-            {
-                let parent = name_ref.syntax().parent()?;
-                let (mut nameref_ctx, _) =
-                    Self::classify_name_ref(&self.sema, &original_file, name_ref, parent)?;
-                if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
-                    path_ctx.kind = PathKind::Derive {
-                        existing_derives: self
-                            .sema
-                            .resolve_derive_macro(&origin_attr)
-                            .into_iter()
-                            .flatten()
-                            .flatten()
-                            .collect(),
-                    };
+/// Calculate the expected type and name of the cursor position.
+fn expected_type_and_name(
+    sema: &Semantics<'_, RootDatabase>,
+    token: &SyntaxToken,
+    name_like: &ast::NameLike,
+) -> (Option<Type>, Option<NameOrNameRef>) {
+    let mut node = match token.parent() {
+        Some(it) => it,
+        None => return (None, None),
+    };
+
+    let strip_refs = |mut ty: Type| match name_like {
+        ast::NameLike::NameRef(n) => {
+            let p = match n.syntax().parent() {
+                Some(it) => it,
+                None => return ty,
+            };
+            let top_syn = match_ast! {
+                match p {
+                    ast::FieldExpr(e) => e
+                        .syntax()
+                        .ancestors()
+                        .map_while(ast::FieldExpr::cast)
+                        .last()
+                        .map(|it| it.syntax().clone()),
+                    ast::PathSegment(e) => e
+                        .syntax()
+                        .ancestors()
+                        .skip(1)
+                        .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
+                        .find_map(ast::PathExpr::cast)
+                        .map(|it| it.syntax().clone()),
+                    _ => None
                 }
-                return Some(CompletionAnalysis::NameRef(nameref_ctx));
+            };
+            let top_syn = match top_syn {
+                Some(it) => it,
+                None => return ty,
+            };
+            for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
+                cov_mark::hit!(expected_type_fn_param_ref);
+                ty = ty.strip_reference();
             }
-            return None;
+            ty
         }
+        _ => ty,
+    };
 
-        let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
-            Some(it) => it,
-            None => {
-                let analysis =
-                    if let Some(original) = ast::String::cast(self.original_token.clone()) {
-                        CompletionAnalysis::String {
-                            original,
-                            expanded: ast::String::cast(self.token.clone()),
-                        }
-                    } else {
-                        // Fix up trailing whitespace problem
-                        // #[attr(foo = $0
-                        let token =
-                            syntax::algo::skip_trivia_token(self.token.clone(), Direction::Prev)?;
-                        let p = token.parent()?;
-                        if p.kind() == SyntaxKind::TOKEN_TREE
-                            && p.ancestors().any(|it| it.kind() == SyntaxKind::META)
+    loop {
+        break match_ast! {
+            match node {
+                ast::LetStmt(it) => {
+                    cov_mark::hit!(expected_type_let_with_leading_char);
+                    cov_mark::hit!(expected_type_let_without_leading_char);
+                    let ty = it.pat()
+                        .and_then(|pat| sema.type_of_pat(&pat))
+                        .or_else(|| it.initializer().and_then(|it| sema.type_of_expr(&it)))
+                        .map(TypeInfo::original);
+                    let name = match it.pat() {
+                        Some(ast::Pat::IdentPat(ident)) => ident.name().map(NameOrNameRef::Name),
+                        Some(_) | None => None,
+                    };
+
+                    (ty, name)
+                },
+                ast::LetExpr(it) => {
+                    cov_mark::hit!(expected_type_if_let_without_leading_char);
+                    let ty = it.pat()
+                        .and_then(|pat| sema.type_of_pat(&pat))
+                        .or_else(|| it.expr().and_then(|it| sema.type_of_expr(&it)))
+                        .map(TypeInfo::original);
+                    (ty, None)
+                },
+                ast::ArgList(_) => {
+                    cov_mark::hit!(expected_type_fn_param);
+                    ActiveParameter::at_token(
+                        &sema,
+                       token.clone(),
+                    ).map(|ap| {
+                        let name = ap.ident().map(NameOrNameRef::Name);
+
+                        let ty = strip_refs(ap.ty);
+                        (Some(ty), name)
+                    })
+                    .unwrap_or((None, None))
+                },
+                ast::RecordExprFieldList(it) => {
+                    // wouldn't try {} be nice...
+                    (|| {
+                        if token.kind() == T![..]
+                            ||token.prev_token().map(|t| t.kind()) == Some(T![..])
                         {
-                            let colon_prefix = previous_non_trivia_token(self.token.clone())
-                                .map_or(false, |it| T![:] == it.kind());
-                            CompletionAnalysis::UnexpandedAttrTT {
-                                fake_attribute_under_caret: syntax_element
-                                    .ancestors()
-                                    .find_map(ast::Attr::cast),
-                                colon_prefix,
-                            }
+                            cov_mark::hit!(expected_type_struct_func_update);
+                            let record_expr = it.syntax().parent().and_then(ast::RecordExpr::cast)?;
+                            let ty = sema.type_of_expr(&record_expr.into())?;
+                            Some((
+                                Some(ty.original),
+                                None
+                            ))
                         } else {
-                            return None;
+                            cov_mark::hit!(expected_type_struct_field_without_leading_char);
+                            let expr_field = token.prev_sibling_or_token()?
+                                .into_node()
+                                .and_then(ast::RecordExprField::cast)?;
+                            let (_, _, ty) = sema.resolve_record_field(&expr_field)?;
+                            Some((
+                                Some(ty),
+                                expr_field.field_name().map(NameOrNameRef::NameRef),
+                            ))
                         }
-                    };
-                return Some(analysis);
+                    })().unwrap_or((None, None))
+                },
+                ast::RecordExprField(it) => {
+                    if let Some(expr) = it.expr() {
+                        cov_mark::hit!(expected_type_struct_field_with_leading_char);
+                        (
+                            sema.type_of_expr(&expr).map(TypeInfo::original),
+                            it.field_name().map(NameOrNameRef::NameRef),
+                        )
+                    } else {
+                        cov_mark::hit!(expected_type_struct_field_followed_by_comma);
+                        let ty = sema.resolve_record_field(&it)
+                            .map(|(_, _, ty)| ty);
+                        (
+                            ty,
+                            it.field_name().map(NameOrNameRef::NameRef),
+                        )
+                    }
+                },
+                // match foo { $0 }
+                // match foo { ..., pat => $0 }
+                ast::MatchExpr(it) => {
+                    let on_arrow = previous_non_trivia_token(token.clone()).map_or(false, |it| T![=>] == it.kind());
+
+                    let ty = if on_arrow {
+                        // match foo { ..., pat => $0 }
+                        cov_mark::hit!(expected_type_match_arm_body_without_leading_char);
+                        cov_mark::hit!(expected_type_match_arm_body_with_leading_char);
+                        sema.type_of_expr(&it.into())
+                    } else {
+                        // match foo { $0 }
+                        cov_mark::hit!(expected_type_match_arm_without_leading_char);
+                        it.expr().and_then(|e| sema.type_of_expr(&e))
+                    }.map(TypeInfo::original);
+                    (ty, None)
+                },
+                ast::IfExpr(it) => {
+                    let ty = it.condition()
+                        .and_then(|e| sema.type_of_expr(&e))
+                        .map(TypeInfo::original);
+                    (ty, None)
+                },
+                ast::IdentPat(it) => {
+                    cov_mark::hit!(expected_type_if_let_with_leading_char);
+                    cov_mark::hit!(expected_type_match_arm_with_leading_char);
+                    let ty = sema.type_of_pat(&ast::Pat::from(it)).map(TypeInfo::original);
+                    (ty, None)
+                },
+                ast::Fn(it) => {
+                    cov_mark::hit!(expected_type_fn_ret_with_leading_char);
+                    cov_mark::hit!(expected_type_fn_ret_without_leading_char);
+                    let def = sema.to_def(&it);
+                    (def.map(|def| def.ret_type(sema.db)), None)
+                },
+                ast::ClosureExpr(it) => {
+                    let ty = sema.type_of_expr(&it.into());
+                    ty.and_then(|ty| ty.original.as_callable(sema.db))
+                        .map(|c| (Some(c.return_type()), None))
+                        .unwrap_or((None, None))
+                },
+                ast::ParamList(_) => (None, None),
+                ast::Stmt(_) => (None, None),
+                ast::Item(_) => (None, None),
+                _ => {
+                    match node.parent() {
+                        Some(n) => {
+                            node = n;
+                            continue;
+                        },
+                        None => (None, None),
+                    }
+                },
             }
         };
-        (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
-        let analysis = match name_like {
-            ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
-                Self::classify_lifetime(&self.sema, original_file, lifetime)?,
-            ),
-            ast::NameLike::NameRef(name_ref) => {
-                let parent = name_ref.syntax().parent()?;
-                let (nameref_ctx, qualifier_ctx) =
-                    Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone())?;
+    }
+}
 
-                self.qualifier_ctx = qualifier_ctx;
-                CompletionAnalysis::NameRef(nameref_ctx)
-            }
-            ast::NameLike::Name(name) => {
-                let name_ctx = Self::classify_name(&self.sema, original_file, name)?;
-                CompletionAnalysis::Name(name_ctx)
-            }
-        };
-        Some(analysis)
+fn classify_lifetime(
+    _sema: &Semantics<'_, RootDatabase>,
+    original_file: &SyntaxNode,
+    lifetime: ast::Lifetime,
+) -> Option<LifetimeContext> {
+    let parent = lifetime.syntax().parent()?;
+    if parent.kind() == SyntaxKind::ERROR {
+        return None;
     }
 
-    fn classify_lifetime(
-        _sema: &Semantics<'_, RootDatabase>,
-        original_file: &SyntaxNode,
-        lifetime: ast::Lifetime,
-    ) -> Option<LifetimeContext> {
-        let parent = lifetime.syntax().parent()?;
-        if parent.kind() == SyntaxKind::ERROR {
-            return None;
+    let kind = match_ast! {
+        match parent {
+            ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
+                is_decl: param.lifetime().as_ref() == Some(&lifetime),
+                param
+            },
+            ast::BreakExpr(_) => LifetimeKind::LabelRef,
+            ast::ContinueExpr(_) => LifetimeKind::LabelRef,
+            ast::Label(_) => LifetimeKind::LabelDef,
+            _ => LifetimeKind::Lifetime,
         }
+    };
+    let lifetime = find_node_at_offset(&original_file, lifetime.syntax().text_range().start());
 
-        let kind = match_ast! {
-            match parent {
-                ast::LifetimeParam(param) => LifetimeKind::LifetimeParam {
-                    is_decl: param.lifetime().as_ref() == Some(&lifetime),
-                    param
-                },
-                ast::BreakExpr(_) => LifetimeKind::LabelRef,
-                ast::ContinueExpr(_) => LifetimeKind::LabelRef,
-                ast::Label(_) => LifetimeKind::LabelDef,
-                _ => LifetimeKind::Lifetime,
-            }
-        };
-        let lifetime = find_node_at_offset(&original_file, lifetime.syntax().text_range().start());
+    Some(LifetimeContext { lifetime, kind })
+}
 
-        Some(LifetimeContext { lifetime, kind })
-    }
+fn classify_name(
+    sema: &Semantics<'_, RootDatabase>,
+    original_file: &SyntaxNode,
+    name: ast::Name,
+) -> Option<NameContext> {
+    let parent = name.syntax().parent()?;
+    let kind = match_ast! {
+        match parent {
+            ast::Const(_) => NameKind::Const,
+            ast::ConstParam(_) => NameKind::ConstParam,
+            ast::Enum(_) => NameKind::Enum,
+            ast::Fn(_) => NameKind::Function,
+            ast::IdentPat(bind_pat) => {
+                let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into());
+                if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
+                    pat_ctx.record_pat = find_node_in_file_compensated(sema, original_file, &record_field.parent_record_pat());
+                }
 
-    fn classify_name(
-        sema: &Semantics<'_, RootDatabase>,
-        original_file: &SyntaxNode,
-        name: ast::Name,
-    ) -> Option<NameContext> {
-        let parent = name.syntax().parent()?;
-        let kind = match_ast! {
-            match parent {
-                ast::Const(_) => NameKind::Const,
-                ast::ConstParam(_) => NameKind::ConstParam,
-                ast::Enum(_) => NameKind::Enum,
-                ast::Fn(_) => NameKind::Function,
-                ast::IdentPat(bind_pat) => {
-                    let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into());
-                    if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
-                        pat_ctx.record_pat = find_node_in_file_compensated(sema, original_file, &record_field.parent_record_pat());
-                    }
+                NameKind::IdentPat(pat_ctx)
+            },
+            ast::MacroDef(_) => NameKind::MacroDef,
+            ast::MacroRules(_) => NameKind::MacroRules,
+            ast::Module(module) => NameKind::Module(module),
+            ast::RecordField(_) => NameKind::RecordField,
+            ast::Rename(_) => NameKind::Rename,
+            ast::SelfParam(_) => NameKind::SelfParam,
+            ast::Static(_) => NameKind::Static,
+            ast::Struct(_) => NameKind::Struct,
+            ast::Trait(_) => NameKind::Trait,
+            ast::TypeAlias(_) => NameKind::TypeAlias,
+            ast::TypeParam(_) => NameKind::TypeParam,
+            ast::Union(_) => NameKind::Union,
+            ast::Variant(_) => NameKind::Variant,
+            _ => return None,
+        }
+    };
+    let name = find_node_at_offset(&original_file, name.syntax().text_range().start());
+    Some(NameContext { name, kind })
+}
 
-                    NameKind::IdentPat(pat_ctx)
-                },
-                ast::MacroDef(_) => NameKind::MacroDef,
-                ast::MacroRules(_) => NameKind::MacroRules,
-                ast::Module(module) => NameKind::Module(module),
-                ast::RecordField(_) => NameKind::RecordField,
-                ast::Rename(_) => NameKind::Rename,
-                ast::SelfParam(_) => NameKind::SelfParam,
-                ast::Static(_) => NameKind::Static,
-                ast::Struct(_) => NameKind::Struct,
-                ast::Trait(_) => NameKind::Trait,
-                ast::TypeAlias(_) => NameKind::TypeAlias,
-                ast::TypeParam(_) => NameKind::TypeParam,
-                ast::Union(_) => NameKind::Union,
-                ast::Variant(_) => NameKind::Variant,
-                _ => return None,
-            }
-        };
-        let name = find_node_at_offset(&original_file, name.syntax().text_range().start());
-        Some(NameContext { name, kind })
+fn classify_name_ref(
+    sema: &Semantics<'_, RootDatabase>,
+    original_file: &SyntaxNode,
+    name_ref: ast::NameRef,
+    parent: SyntaxNode,
+) -> Option<(NameRefContext, QualifierCtx)> {
+    let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
+
+    let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
+
+    if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
+        let dot_prefix = previous_non_trivia_token(name_ref.syntax().clone())
+            .map_or(false, |it| T![.] == it.kind());
+
+        return find_node_in_file_compensated(
+            sema,
+            original_file,
+            &record_field.parent_record_lit(),
+        )
+        .map(|expr| NameRefKind::RecordExpr { expr, dot_prefix })
+        .map(make_res);
     }
-
-    fn classify_name_ref(
-        sema: &Semantics<'_, RootDatabase>,
-        original_file: &SyntaxNode,
-        name_ref: ast::NameRef,
-        parent: SyntaxNode,
-    ) -> Option<(NameRefContext, QualifierCtx)> {
-        let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
-
-        let make_res =
-            |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
-
-        if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
-            let dot_prefix = previous_non_trivia_token(name_ref.syntax().clone())
-                .map_or(false, |it| T![.] == it.kind());
-
-            return find_node_in_file_compensated(
+    if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
+        let kind = NameRefKind::Pattern(PatternContext {
+            param_ctx: None,
+            has_type_ascription: false,
+            ref_token: None,
+            mut_token: None,
+            record_pat: find_node_in_file_compensated(
                 sema,
                 original_file,
-                &record_field.parent_record_lit(),
+                &record_field.parent_record_pat(),
+            ),
+            ..pattern_context_for(
+                sema,
+                original_file,
+                record_field.parent_record_pat().clone().into(),
             )
-            .map(|expr| NameRefKind::RecordExpr { expr, dot_prefix })
-            .map(make_res);
+        });
+        return Some(make_res(kind));
+    }
+
+    let segment = match_ast! {
+        match parent {
+            ast::PathSegment(segment) => segment,
+            ast::FieldExpr(field) => {
+                let receiver = find_opt_node_in_file(original_file, field.expr());
+                let receiver_is_ambiguous_float_literal = match &receiver {
+                    Some(ast::Expr::Literal(l)) => matches! {
+                        l.kind(),
+                        ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().map_or(false, |it| it.text().ends_with('.'))
+                    },
+                    _ => false,
+                };
+                let kind = NameRefKind::DotAccess(DotAccess {
+                    receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
+                    kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
+                    receiver
+                });
+                return Some(make_res(kind));
+            },
+            ast::MethodCallExpr(method) => {
+                let receiver = find_opt_node_in_file(original_file, method.receiver());
+                let kind = NameRefKind::DotAccess(DotAccess {
+                    receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
+                    kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
+                    receiver
+                });
+                return Some(make_res(kind));
+            },
+            _ => return None,
         }
-        if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
-            let kind = NameRefKind::Pattern(PatternContext {
-                param_ctx: None,
-                has_type_ascription: false,
-                ref_token: None,
-                mut_token: None,
-                record_pat: find_node_in_file_compensated(
-                    sema,
-                    original_file,
-                    &record_field.parent_record_pat(),
-                ),
-                ..pattern_context_for(
-                    sema,
-                    original_file,
-                    record_field.parent_record_pat().clone().into(),
-                )
-            });
-            return Some(make_res(kind));
+    };
+
+    let path = segment.parent_path();
+    let original_path = find_node_in_file_compensated(sema, original_file, &path);
+
+    let mut path_ctx = PathCompletionCtx {
+        has_call_parens: false,
+        has_macro_bang: false,
+        qualified: Qualified::No,
+        parent: None,
+        path: path.clone(),
+        original_path,
+        kind: PathKind::Item { kind: ItemListKind::SourceFile },
+        has_type_args: false,
+        use_tree_parent: false,
+    };
+
+    let is_in_block = |it: &SyntaxNode| {
+        it.parent()
+            .map(|node| {
+                ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind())
+            })
+            .unwrap_or(false)
+    };
+    let func_update_record = |syn: &SyntaxNode| {
+        if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) {
+            find_node_in_file_compensated(sema, original_file, &record_expr)
+        } else {
+            None
+        }
+    };
+    let after_if_expr = |node: SyntaxNode| {
+        let prev_expr = (|| {
+            let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
+            ast::ExprStmt::cast(prev_sibling)?.expr()
+        })();
+        matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
+    };
+
+    // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
+    // ex. trait Foo $0 {}
+    // in these cases parser recovery usually kicks in for our inserted identifier, causing it
+    // to either be parsed as an ExprStmt or a MacroCall, depending on whether it is in a block
+    // expression or an item list.
+    // The following code checks if the body is missing, if it is we either cut off the body
+    // from the item or it was missing in the first place
+    let inbetween_body_and_decl_check = |node: SyntaxNode| {
+        if let Some(NodeOrToken::Node(n)) =
+            syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev)
+        {
+            if let Some(item) = ast::Item::cast(n) {
+                let is_inbetween = match &item {
+                    ast::Item::Const(it) => it.body().is_none(),
+                    ast::Item::Enum(it) => it.variant_list().is_none(),
+                    ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
+                    ast::Item::Fn(it) => it.body().is_none(),
+                    ast::Item::Impl(it) => it.assoc_item_list().is_none(),
+                    ast::Item::Module(it) => it.item_list().is_none(),
+                    ast::Item::Static(it) => it.body().is_none(),
+                    ast::Item::Struct(it) => it.field_list().is_none(),
+                    ast::Item::Trait(it) => it.assoc_item_list().is_none(),
+                    ast::Item::TypeAlias(it) => it.ty().is_none(),
+                    ast::Item::Union(it) => it.record_field_list().is_none(),
+                    _ => false,
+                };
+                if is_inbetween {
+                    return Some(item);
+                }
+            }
         }
+        None
+    };
 
-        let segment = match_ast! {
+    let type_location = |node: &SyntaxNode| {
+        let parent = node.parent()?;
+        let res = match_ast! {
             match parent {
-                ast::PathSegment(segment) => segment,
-                ast::FieldExpr(field) => {
-                    let receiver = find_opt_node_in_file(original_file, field.expr());
-                    let receiver_is_ambiguous_float_literal = match &receiver {
-                        Some(ast::Expr::Literal(l)) => matches! {
-                            l.kind(),
-                            ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().map_or(false, |it| it.text().ends_with('.'))
-                        },
-                        _ => false,
+                ast::Const(it) => {
+                    let name = find_opt_node_in_file(original_file, it.name())?;
+                    let original = ast::Const::cast(name.syntax().parent()?)?;
+                    TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
+                },
+                ast::RetType(it) => {
+                    if it.thin_arrow_token().is_none() {
+                        return None;
+                    }
+                    let parent = match ast::Fn::cast(parent.parent()?) {
+                        Some(x) => x.param_list(),
+                        None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
                     };
-                    let kind = NameRefKind::DotAccess(DotAccess {
-                        receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                        kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
-                        receiver
-                    });
-                    return Some(make_res(kind));
+
+                    let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
+                    TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! {
+                        match parent {
+                            ast::ClosureExpr(it) => {
+                                it.body()
+                            },
+                            ast::Fn(it) => {
+                                it.body().map(ast::Expr::BlockExpr)
+                            },
+                            _ => return None,
+                        }
+                    }))
                 },
-                ast::MethodCallExpr(method) => {
-                    let receiver = find_opt_node_in_file(original_file, method.receiver());
-                    let kind = NameRefKind::DotAccess(DotAccess {
-                        receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                        kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
-                        receiver
-                    });
-                    return Some(make_res(kind));
+                ast::Param(it) => {
+                    if it.colon_token().is_none() {
+                        return None;
+                    }
+                    TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat())))
                 },
+                ast::LetStmt(it) => {
+                    if it.colon_token().is_none() {
+                        return None;
+                    }
+                    TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
+                },
+                ast::Impl(it) => {
+                    match it.trait_() {
+                        Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
+                        _ => match it.self_ty() {
+                            Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
+                            _ => return None,
+                        },
+                    }
+                },
+                ast::TypeBound(_) => TypeLocation::TypeBound,
+                // is this case needed?
+                ast::TypeBoundList(_) => TypeLocation::TypeBound,
+                ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))),
+                // is this case needed?
+                ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))),
+                ast::TupleField(_) => TypeLocation::TupleField,
                 _ => return None,
             }
         };
+        Some(res)
+    };
 
-        let path = segment.parent_path();
-        let original_path = find_node_in_file_compensated(sema, original_file, &path);
-
-        let mut path_ctx = PathCompletionCtx {
-            has_call_parens: false,
-            has_macro_bang: false,
-            qualified: Qualified::No,
-            parent: None,
-            path: path.clone(),
-            original_path,
-            kind: PathKind::Item { kind: ItemListKind::SourceFile },
-            has_type_args: false,
-            use_tree_parent: false,
-        };
-
-        let is_in_block = |it: &SyntaxNode| {
-            it.parent()
-                .map(|node| {
-                    ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind())
-                })
-                .unwrap_or(false)
-        };
-        let func_update_record = |syn: &SyntaxNode| {
-            if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) {
-                find_node_in_file_compensated(sema, original_file, &record_expr)
+    let is_in_condition = |it: &ast::Expr| {
+        (|| {
+            let parent = it.syntax().parent()?;
+            if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
+                Some(expr.condition()? == *it)
+            } else if let Some(expr) = ast::IfExpr::cast(parent) {
+                Some(expr.condition()? == *it)
             } else {
                 None
             }
-        };
-        let after_if_expr = |node: SyntaxNode| {
-            let prev_expr = (|| {
-                let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
-                ast::ExprStmt::cast(prev_sibling)?.expr()
-            })();
-            matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
-        };
+        })()
+        .unwrap_or(false)
+    };
 
-        // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
-        // ex. trait Foo $0 {}
-        // in these cases parser recovery usually kicks in for our inserted identifier, causing it
-        // to either be parsed as an ExprStmt or a MacroCall, depending on whether it is in a block
-        // expression or an item list.
-        // The following code checks if the body is missing, if it is we either cut off the body
-        // from the item or it was missing in the first place
-        let inbetween_body_and_decl_check = |node: SyntaxNode| {
-            if let Some(NodeOrToken::Node(n)) =
-                syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev)
-            {
-                if let Some(item) = ast::Item::cast(n) {
-                    let is_inbetween = match &item {
-                        ast::Item::Const(it) => it.body().is_none(),
-                        ast::Item::Enum(it) => it.variant_list().is_none(),
-                        ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
-                        ast::Item::Fn(it) => it.body().is_none(),
-                        ast::Item::Impl(it) => it.assoc_item_list().is_none(),
-                        ast::Item::Module(it) => it.item_list().is_none(),
-                        ast::Item::Static(it) => it.body().is_none(),
-                        ast::Item::Struct(it) => it.field_list().is_none(),
-                        ast::Item::Trait(it) => it.assoc_item_list().is_none(),
-                        ast::Item::TypeAlias(it) => it.ty().is_none(),
-                        ast::Item::Union(it) => it.record_field_list().is_none(),
-                        _ => false,
-                    };
-                    if is_inbetween {
-                        return Some(item);
+    let make_path_kind_expr = |expr: ast::Expr| {
+        let it = expr.syntax();
+        let in_block_expr = is_in_block(it);
+        let in_loop_body = is_in_loop_body(it);
+        let after_if_expr = after_if_expr(it.clone());
+        let ref_expr_parent =
+            path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
+        let (innermost_ret_ty, self_param) = {
+            let find_ret_ty = |it: SyntaxNode| {
+                if let Some(item) = ast::Item::cast(it.clone()) {
+                    match item {
+                        ast::Item::Fn(f) => Some(sema.to_def(&f).map(|it| it.ret_type(sema.db))),
+                        ast::Item::MacroCall(_) => None,
+                        _ => Some(None),
                     }
-                }
-            }
-            None
-        };
-
-        let type_location = |node: &SyntaxNode| {
-            let parent = node.parent()?;
-            let res = match_ast! {
-                match parent {
-                    ast::Const(it) => {
-                        let name = find_opt_node_in_file(original_file, it.name())?;
-                        let original = ast::Const::cast(name.syntax().parent()?)?;
-                        TypeLocation::TypeAscription(TypeAscriptionTarget::Const(original.body()))
-                    },
-                    ast::RetType(it) => {
-                        if it.thin_arrow_token().is_none() {
-                            return None;
-                        }
-                        let parent = match ast::Fn::cast(parent.parent()?) {
-                            Some(x) => x.param_list(),
-                            None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(),
-                        };
-
-                        let parent = find_opt_node_in_file(original_file, parent)?.syntax().parent()?;
-                        TypeLocation::TypeAscription(TypeAscriptionTarget::RetType(match_ast! {
-                            match parent {
-                                ast::ClosureExpr(it) => {
-                                    it.body()
-                                },
-                                ast::Fn(it) => {
-                                    it.body().map(ast::Expr::BlockExpr)
-                                },
-                                _ => return None,
-                            }
-                        }))
-                    },
-                    ast::Param(it) => {
-                        if it.colon_token().is_none() {
-                            return None;
-                        }
-                        TypeLocation::TypeAscription(TypeAscriptionTarget::FnParam(find_opt_node_in_file(original_file, it.pat())))
-                    },
-                    ast::LetStmt(it) => {
-                        if it.colon_token().is_none() {
-                            return None;
-                        }
-                        TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
-                    },
-                    ast::Impl(it) => {
-                        match it.trait_() {
-                            Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
-                            _ => match it.self_ty() {
-                                Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
-                                _ => return None,
-                            },
-                        }
-                    },
-                    ast::TypeBound(_) => TypeLocation::TypeBound,
-                    // is this case needed?
-                    ast::TypeBoundList(_) => TypeLocation::TypeBound,
-                    ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))),
-                    // is this case needed?
-                    ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))),
-                    ast::TupleField(_) => TypeLocation::TupleField,
-                    _ => return None,
-                }
-            };
-            Some(res)
-        };
-
-        let is_in_condition = |it: &ast::Expr| {
-            (|| {
-                let parent = it.syntax().parent()?;
-                if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
-                    Some(expr.condition()? == *it)
-                } else if let Some(expr) = ast::IfExpr::cast(parent) {
-                    Some(expr.condition()? == *it)
                 } else {
-                    None
-                }
-            })()
-            .unwrap_or(false)
-        };
-
-        let make_path_kind_expr = |expr: ast::Expr| {
-            let it = expr.syntax();
-            let in_block_expr = is_in_block(it);
-            let in_loop_body = is_in_loop_body(it);
-            let after_if_expr = after_if_expr(it.clone());
-            let ref_expr_parent =
-                path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
-            let (innermost_ret_ty, self_param) = {
-                let find_ret_ty = |it: SyntaxNode| {
-                    if let Some(item) = ast::Item::cast(it.clone()) {
-                        match item {
-                            ast::Item::Fn(f) => {
-                                Some(sema.to_def(&f).map(|it| it.ret_type(sema.db)))
-                            }
-                            ast::Item::MacroCall(_) => None,
-                            _ => Some(None),
-                        }
-                    } else {
-                        let expr = ast::Expr::cast(it)?;
-                        let callable = match expr {
-                            // FIXME
-                            // ast::Expr::BlockExpr(b) if b.async_token().is_some() || b.try_token().is_some() => sema.type_of_expr(b),
-                            ast::Expr::ClosureExpr(_) => sema.type_of_expr(&expr),
-                            _ => return None,
-                        };
-                        Some(
-                            callable
-                                .and_then(|c| c.adjusted().as_callable(sema.db))
-                                .map(|it| it.return_type()),
-                        )
-                    }
-                };
-                let find_fn_self_param = |it| match it {
-                    ast::Item::Fn(fn_) => {
-                        Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db)))
-                    }
-                    ast::Item::MacroCall(_) => None,
-                    _ => Some(None),
-                };
-
-                match find_node_in_file_compensated(sema, original_file, &expr) {
-                    Some(it) => {
-                        let innermost_ret_ty = sema
-                            .ancestors_with_macros(it.syntax().clone())
-                            .find_map(find_ret_ty)
-                            .flatten();
-
-                        let self_param = sema
-                            .ancestors_with_macros(it.syntax().clone())
-                            .filter_map(ast::Item::cast)
-                            .find_map(find_fn_self_param)
-                            .flatten();
-                        (innermost_ret_ty, self_param)
-                    }
-                    None => (None, None),
+                    let expr = ast::Expr::cast(it)?;
+                    let callable = match expr {
+                        // FIXME
+                        // ast::Expr::BlockExpr(b) if b.async_token().is_some() || b.try_token().is_some() => sema.type_of_expr(b),
+                        ast::Expr::ClosureExpr(_) => sema.type_of_expr(&expr),
+                        _ => return None,
+                    };
+                    Some(
+                        callable
+                            .and_then(|c| c.adjusted().as_callable(sema.db))
+                            .map(|it| it.return_type()),
+                    )
                 }
             };
-            let is_func_update = func_update_record(it);
-            let in_condition = is_in_condition(&expr);
-            let incomplete_let = it
-                .parent()
-                .and_then(ast::LetStmt::cast)
-                .map_or(false, |it| it.semicolon_token().is_none());
-            let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
-
-            let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) {
-                Some(arm) => arm
-                    .fat_arrow_token()
-                    .map_or(true, |arrow| it.text_range().start() < arrow.text_range().start()),
-                None => false,
+            let find_fn_self_param = |it| match it {
+                ast::Item::Fn(fn_) => Some(sema.to_def(&fn_).and_then(|it| it.self_param(sema.db))),
+                ast::Item::MacroCall(_) => None,
+                _ => Some(None),
             };
 
-            PathKind::Expr {
-                expr_ctx: ExprCtx {
-                    in_block_expr,
-                    in_loop_body,
-                    after_if_expr,
-                    in_condition,
-                    ref_expr_parent,
-                    is_func_update,
-                    innermost_ret_ty,
-                    self_param,
-                    incomplete_let,
-                    impl_,
-                    in_match_guard,
-                },
+            match find_node_in_file_compensated(sema, original_file, &expr) {
+                Some(it) => {
+                    let innermost_ret_ty = sema
+                        .ancestors_with_macros(it.syntax().clone())
+                        .find_map(find_ret_ty)
+                        .flatten();
+
+                    let self_param = sema
+                        .ancestors_with_macros(it.syntax().clone())
+                        .filter_map(ast::Item::cast)
+                        .find_map(find_fn_self_param)
+                        .flatten();
+                    (innermost_ret_ty, self_param)
+                }
+                None => (None, None),
             }
         };
-        let make_path_kind_type = |ty: ast::Type| {
-            let location = type_location(ty.syntax());
-            PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
+        let is_func_update = func_update_record(it);
+        let in_condition = is_in_condition(&expr);
+        let incomplete_let = it
+            .parent()
+            .and_then(ast::LetStmt::cast)
+            .map_or(false, |it| it.semicolon_token().is_none());
+        let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
+
+        let in_match_guard = match it.parent().and_then(ast::MatchArm::cast) {
+            Some(arm) => arm
+                .fat_arrow_token()
+                .map_or(true, |arrow| it.text_range().start() < arrow.text_range().start()),
+            None => false,
         };
 
-        let mut kind_macro_call = |it: ast::MacroCall| {
-            path_ctx.has_macro_bang = it.excl_token().is_some();
-            let parent = it.syntax().parent()?;
-            // Any path in an item list will be treated as a macro call by the parser
-            let kind = match_ast! {
-                match parent {
-                    ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
-                    ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
-                    ast::MacroType(ty) => make_path_kind_type(ty.into()),
-                    ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
-                    ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
-                        Some(it) => match_ast! {
-                            match it {
-                                ast::Trait(_) => ItemListKind::Trait,
-                                ast::Impl(it) => if it.trait_().is_some() {
-                                    ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
-                                } else {
-                                    ItemListKind::Impl
-                                },
-                                _ => return None
-                            }
-                        },
-                        None => return None,
-                    } },
-                    ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
-                    ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
-                    _ => return None,
-                }
-            };
-            Some(kind)
-        };
-        let make_path_kind_attr = |meta: ast::Meta| {
-            let attr = meta.parent_attr()?;
-            let kind = attr.kind();
-            let attached = attr.syntax().parent()?;
-            let is_trailing_outer_attr = kind != AttrKind::Inner
-                && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
-                    .is_none();
-            let annotated_item_kind =
-                if is_trailing_outer_attr { None } else { Some(attached.kind()) };
-            Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
-        };
+        PathKind::Expr {
+            expr_ctx: ExprCtx {
+                in_block_expr,
+                in_loop_body,
+                after_if_expr,
+                in_condition,
+                ref_expr_parent,
+                is_func_update,
+                innermost_ret_ty,
+                self_param,
+                incomplete_let,
+                impl_,
+                in_match_guard,
+            },
+        }
+    };
+    let make_path_kind_type = |ty: ast::Type| {
+        let location = type_location(ty.syntax());
+        PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
+    };
 
-        // Infer the path kind
-        let parent = path.syntax().parent()?;
+    let mut kind_macro_call = |it: ast::MacroCall| {
+        path_ctx.has_macro_bang = it.excl_token().is_some();
+        let parent = it.syntax().parent()?;
+        // Any path in an item list will be treated as a macro call by the parser
         let kind = match_ast! {
             match parent {
-                ast::PathType(it) => make_path_kind_type(it.into()),
-                ast::PathExpr(it) => {
-                    if let Some(p) = it.syntax().parent() {
-                        if ast::ExprStmt::can_cast(p.kind()) {
-                            if let Some(kind) = inbetween_body_and_decl_check(p) {
-                                return Some(make_res(NameRefKind::Keyword(kind)));
-                            }
-                        }
-                    }
-
-                    path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
-
-                    make_path_kind_expr(it.into())
-                },
-                ast::TupleStructPat(it) => {
-                    path_ctx.has_call_parens = true;
-                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                },
-                ast::RecordPat(it) => {
-                    path_ctx.has_call_parens = true;
-                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                },
-                ast::PathPat(it) => {
-                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                },
-                ast::MacroCall(it) => {
-                    // A macro call in this position is usually a result of parsing recovery, so check that
-                    if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
-                        return Some(make_res(NameRefKind::Keyword(kind)));
-                    }
-
-                    kind_macro_call(it)?
-                },
-                ast::Meta(meta) => make_path_kind_attr(meta)?,
-                ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                ast::UseTree(_) => PathKind::Use,
-                // completing inside a qualifier
-                ast::Path(parent) => {
-                    path_ctx.parent = Some(parent.clone());
-                    let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
-                    match_ast! {
-                        match parent {
-                            ast::PathType(it) => make_path_kind_type(it.into()),
-                            ast::PathExpr(it) => {
-                                path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
-
-                                make_path_kind_expr(it.into())
-                            },
-                            ast::TupleStructPat(it) => {
-                                path_ctx.has_call_parens = true;
-                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                            },
-                            ast::RecordPat(it) => {
-                                path_ctx.has_call_parens = true;
-                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
-                            },
-                            ast::PathPat(it) => {
-                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                            },
-                            ast::MacroCall(it) => {
-                                kind_macro_call(it)?
+                ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
+                ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
+                ast::MacroType(ty) => make_path_kind_type(ty.into()),
+                ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
+                ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
+                    Some(it) => match_ast! {
+                        match it {
+                            ast::Trait(_) => ItemListKind::Trait,
+                            ast::Impl(it) => if it.trait_().is_some() {
+                                ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
+                            } else {
+                                ItemListKind::Impl
                             },
-                            ast::Meta(meta) => make_path_kind_attr(meta)?,
-                            ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                            ast::UseTree(_) => PathKind::Use,
-                            ast::RecordExpr(it) => make_path_kind_expr(it.into()),
-                            _ => return None,
+                            _ => return None
                         }
-                    }
-                },
-                ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+                    },
+                    None => return None,
+                } },
+                ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
+                ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
                 _ => return None,
             }
         };
+        Some(kind)
+    };
+    let make_path_kind_attr = |meta: ast::Meta| {
+        let attr = meta.parent_attr()?;
+        let kind = attr.kind();
+        let attached = attr.syntax().parent()?;
+        let is_trailing_outer_attr = kind != AttrKind::Inner
+            && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
+        let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) };
+        Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
+    };
 
-        path_ctx.kind = kind;
-        path_ctx.has_type_args = segment.generic_arg_list().is_some();
+    // Infer the path kind
+    let parent = path.syntax().parent()?;
+    let kind = match_ast! {
+        match parent {
+            ast::PathType(it) => make_path_kind_type(it.into()),
+            ast::PathExpr(it) => {
+                if let Some(p) = it.syntax().parent() {
+                    if ast::ExprStmt::can_cast(p.kind()) {
+                        if let Some(kind) = inbetween_body_and_decl_check(p) {
+                            return Some(make_res(NameRefKind::Keyword(kind)));
+                        }
+                    }
+                }
 
-        // calculate the qualifier context
-        if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
-            path_ctx.use_tree_parent = use_tree_parent;
-            if !use_tree_parent && segment.coloncolon_token().is_some() {
-                path_ctx.qualified = Qualified::Absolute;
-            } else {
-                let qualifier = qualifier
-                    .segment()
-                    .and_then(|it| find_node_in_file(original_file, &it))
-                    .map(|it| it.parent_path());
-                if let Some(qualifier) = qualifier {
-                    let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
-                        Some(ast::PathSegmentKind::Type {
-                            type_ref: Some(type_ref),
-                            trait_ref,
-                        }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
-                        _ => None,
-                    };
+                path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+
+                make_path_kind_expr(it.into())
+            },
+            ast::TupleStructPat(it) => {
+                path_ctx.has_call_parens = true;
+                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+            },
+            ast::RecordPat(it) => {
+                path_ctx.has_call_parens = true;
+                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+            },
+            ast::PathPat(it) => {
+                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+            },
+            ast::MacroCall(it) => {
+                // A macro call in this position is usually a result of parsing recovery, so check that
+                if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+                    return Some(make_res(NameRefKind::Keyword(kind)));
+                }
 
-                    path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
-                        let ty = match ty {
-                            ast::Type::InferType(_) => None,
-                            ty => sema.resolve_type(&ty),
-                        };
-                        let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
-                        Qualified::TypeAnchor { ty, trait_ }
-                    } else {
-                        let res = sema.resolve_path(&qualifier);
-
-                        // For understanding how and why super_chain_len is calculated the way it
-                        // is check the documentation at it's definition
-                        let mut segment_count = 0;
-                        let super_count =
-                            iter::successors(Some(qualifier.clone()), |p| p.qualifier())
-                                .take_while(|p| {
-                                    p.segment()
-                                        .and_then(|s| {
-                                            segment_count += 1;
-                                            s.super_token()
-                                        })
-                                        .is_some()
-                                })
-                                .count();
+                kind_macro_call(it)?
+            },
+            ast::Meta(meta) => make_path_kind_attr(meta)?,
+            ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+            ast::UseTree(_) => PathKind::Use,
+            // completing inside a qualifier
+            ast::Path(parent) => {
+                path_ctx.parent = Some(parent.clone());
+                let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
+                match_ast! {
+                    match parent {
+                        ast::PathType(it) => make_path_kind_type(it.into()),
+                        ast::PathExpr(it) => {
+                            path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+
+                            make_path_kind_expr(it.into())
+                        },
+                        ast::TupleStructPat(it) => {
+                            path_ctx.has_call_parens = true;
+                            PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                        },
+                        ast::RecordPat(it) => {
+                            path_ctx.has_call_parens = true;
+                            PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                        },
+                        ast::PathPat(it) => {
+                            PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                        },
+                        ast::MacroCall(it) => {
+                            kind_macro_call(it)?
+                        },
+                        ast::Meta(meta) => make_path_kind_attr(meta)?,
+                        ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                        ast::UseTree(_) => PathKind::Use,
+                        ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+                        _ => return None,
+                    }
+                }
+            },
+            ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+            _ => return None,
+        }
+    };
 
-                        let super_chain_len =
-                            if segment_count > super_count { None } else { Some(super_count) };
+    path_ctx.kind = kind;
+    path_ctx.has_type_args = segment.generic_arg_list().is_some();
 
-                        Qualified::With { path: qualifier, resolution: res, super_chain_len }
+    // calculate the qualifier context
+    if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
+        path_ctx.use_tree_parent = use_tree_parent;
+        if !use_tree_parent && segment.coloncolon_token().is_some() {
+            path_ctx.qualified = Qualified::Absolute;
+        } else {
+            let qualifier = qualifier
+                .segment()
+                .and_then(|it| find_node_in_file(original_file, &it))
+                .map(|it| it.parent_path());
+            if let Some(qualifier) = qualifier {
+                let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
+                    Some(ast::PathSegmentKind::Type { type_ref: Some(type_ref), trait_ref })
+                        if qualifier.qualifier().is_none() =>
+                    {
+                        Some((type_ref, trait_ref))
                     }
+                    _ => None,
                 };
-            }
-        } else if let Some(segment) = path.segment() {
-            if segment.coloncolon_token().is_some() {
-                path_ctx.qualified = Qualified::Absolute;
-            }
-        }
 
-        let mut qualifier_ctx = QualifierCtx::default();
-        if path_ctx.is_trivial_path() {
-            // fetch the full expression that may have qualifiers attached to it
-            let top_node = match path_ctx.kind {
-                PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => {
-                    parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
-                        let parent = p.parent()?;
-                        if ast::StmtList::can_cast(parent.kind()) {
-                            Some(p)
-                        } else if ast::ExprStmt::can_cast(parent.kind()) {
-                            Some(parent)
-                        } else {
-                            None
-                        }
-                    })
-                }
-                PathKind::Item { .. } => {
-                    parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
+                path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
+                    let ty = match ty {
+                        ast::Type::InferType(_) => None,
+                        ty => sema.resolve_type(&ty),
+                    };
+                    let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
+                    Qualified::TypeAnchor { ty, trait_ }
+                } else {
+                    let res = sema.resolve_path(&qualifier);
+
+                    // For understanding how and why super_chain_len is calculated the way it
+                    // is check the documentation at it's definition
+                    let mut segment_count = 0;
+                    let super_count = iter::successors(Some(qualifier.clone()), |p| p.qualifier())
+                        .take_while(|p| {
+                            p.segment()
+                                .and_then(|s| {
+                                    segment_count += 1;
+                                    s.super_token()
+                                })
+                                .is_some()
+                        })
+                        .count();
+
+                    let super_chain_len =
+                        if segment_count > super_count { None } else { Some(super_count) };
+
+                    Qualified::With { path: qualifier, resolution: res, super_chain_len }
                 }
-                _ => None,
             };
-            if let Some(top) = top_node {
-                if let Some(NodeOrToken::Node(error_node)) =
-                    syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev)
-                {
-                    if error_node.kind() == SyntaxKind::ERROR {
-                        qualifier_ctx.unsafe_tok = error_node
-                            .children_with_tokens()
-                            .filter_map(NodeOrToken::into_token)
-                            .find(|it| it.kind() == T![unsafe]);
-                        qualifier_ctx.vis_node =
-                            error_node.children().find_map(ast::Visibility::cast);
+        }
+    } else if let Some(segment) = path.segment() {
+        if segment.coloncolon_token().is_some() {
+            path_ctx.qualified = Qualified::Absolute;
+        }
+    }
+
+    let mut qualifier_ctx = QualifierCtx::default();
+    if path_ctx.is_trivial_path() {
+        // fetch the full expression that may have qualifiers attached to it
+        let top_node = match path_ctx.kind {
+            PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => {
+                parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
+                    let parent = p.parent()?;
+                    if ast::StmtList::can_cast(parent.kind()) {
+                        Some(p)
+                    } else if ast::ExprStmt::can_cast(parent.kind()) {
+                        Some(parent)
+                    } else {
+                        None
                     }
+                })
+            }
+            PathKind::Item { .. } => {
+                parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
+            }
+            _ => None,
+        };
+        if let Some(top) = top_node {
+            if let Some(NodeOrToken::Node(error_node)) =
+                syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev)
+            {
+                if error_node.kind() == SyntaxKind::ERROR {
+                    qualifier_ctx.unsafe_tok = error_node
+                        .children_with_tokens()
+                        .filter_map(NodeOrToken::into_token)
+                        .find(|it| it.kind() == T![unsafe]);
+                    qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast);
                 }
+            }
 
-                if let PathKind::Item { .. } = path_ctx.kind {
-                    if qualifier_ctx.none() {
-                        if let Some(t) = top.first_token() {
-                            if let Some(prev) = t
-                                .prev_token()
-                                .and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev))
-                            {
-                                if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) {
-                                    // This was inferred to be an item position path, but it seems
-                                    // to be part of some other broken node which leaked into an item
-                                    // list
-                                    return None;
-                                }
+            if let PathKind::Item { .. } = path_ctx.kind {
+                if qualifier_ctx.none() {
+                    if let Some(t) = top.first_token() {
+                        if let Some(prev) = t
+                            .prev_token()
+                            .and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev))
+                        {
+                            if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) {
+                                // This was inferred to be an item position path, but it seems
+                                // to be part of some other broken node which leaked into an item
+                                // list
+                                return None;
                             }
                         }
                     }
                 }
             }
         }
-        Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
     }
+    Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
 }
 
 fn pattern_context_for(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index 8d21f4fce0a..9d0044e55f5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -183,6 +183,7 @@ pub fn completions(
             CompletionAnalysis::String { original, expanded: Some(expanded) } => {
                 completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
                 completions::format_string::format_string(acc, ctx, original, expanded);
+                completions::env_vars::complete_cargo_env_vars(acc, ctx, expanded);
             }
             CompletionAnalysis::UnexpandedAttrTT {
                 colon_prefix,
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index 30272bc16f6..cf0bcd5c96b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -15,9 +15,9 @@ tracing = "0.1.35"
 rayon = "1.5.3"
 fst = { version = "0.4.7", default-features = false }
 rustc-hash = "1.1.0"
-once_cell = "1.12.0"
+once_cell = "1.15.0"
 either = "1.7.0"
-itertools = "0.10.3"
+itertools = "0.10.5"
 arrayvec = "0.7.2"
 indexmap = "1.9.1"
 memchr = "2.5.0"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
index f48a5700866..2d6927cee99 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
@@ -1,7 +1,8 @@
 //! Tools to work with format string literals for the `format_args!` family of macros.
+use crate::syntax_helpers::node_ext::macro_call_for_string_token;
 use syntax::{
     ast::{self, IsString},
-    AstNode, AstToken, TextRange, TextSize,
+    TextRange, TextSize,
 };
 
 pub fn is_format_string(string: &ast::String) -> bool {
@@ -14,8 +15,7 @@ pub fn is_format_string(string: &ast::String) -> bool {
     // This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
     // strings. It still fails for `concat!("{", "}")`, but that is rare.
     (|| {
-        let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
-        let name = macro_call.path()?.segment()?.name_ref()?;
+        let name = macro_call_for_string_token(string)?.path()?.segment()?.name_ref()?;
 
         if !matches!(
             name.text().as_str(),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index b890e2b58df..39710b8f13e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -2,8 +2,8 @@
 use itertools::Itertools;
 use parser::T;
 use syntax::{
-    ast::{self, HasLoopBody, PathSegmentKind, VisibilityKind},
-    AstNode, Preorder, RustLanguage, WalkEvent,
+    ast::{self, HasLoopBody, MacroCall, PathSegmentKind, VisibilityKind},
+    AstNode, AstToken, Preorder, RustLanguage, WalkEvent,
 };
 
 pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
@@ -457,3 +457,8 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Pat
         .collect();
     Some(paths)
 }
+
+pub fn macro_call_for_string_token(string: &ast::String) -> Option<MacroCall> {
+    let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
+    Some(macro_call)
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index 9b9e21a4ddb..e1d146f4ee5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -11,11 +11,9 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.3"
-
-
 either = "1.7.0"
-serde_json = "1.0.82"
+itertools = "0.10.5"
+serde_json = "1.0.86"
 
 profile = { path = "../profile", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
new file mode 100644
index 00000000000..085d8d32598
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
@@ -0,0 +1,37 @@
+use hir::InFile;
+
+use crate::{Diagnostic, DiagnosticsContext};
+
+// Diagnostic: incorrect-try-target
+//
+// This diagnostic is triggered if a question mark operator was used in a context where it is not applicable.
+pub(crate) fn incorrect_try_expr(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::IncorrectTryExpr,
+) -> Diagnostic {
+    Diagnostic::new(
+        "incorrect-try-target",
+        format!("the return type of the containing function does not implement `FromResidual`"),
+        ctx.sema
+            .diagnostics_display_range(InFile::new(d.expr.file_id, d.expr.value.clone().into()))
+            .range,
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn try_ops_diag() {
+        check_diagnostics(
+            r#"
+//- minicore: try
+fn test() {
+    core::ops::ControlFlow::<u32, f32>::Continue(1.0)?;
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the return type of the containing function does not implement `FromResidual`
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs
new file mode 100644
index 00000000000..3bf6a423229
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs
@@ -0,0 +1,35 @@
+use hir::{db::DefDatabase, HirDisplay};
+
+use crate::{Diagnostic, DiagnosticsContext};
+
+// Diagnostic: not-implemented
+//
+// This diagnostic is triggered if a type doesn't implement a necessary trait.
+pub(crate) fn not_implemented(ctx: &DiagnosticsContext<'_>, d: &hir::NotImplemented) -> Diagnostic {
+    Diagnostic::new(
+        "not-implemented",
+        format!(
+            "the trait `{}` is not implemented for `{}`",
+            ctx.sema.db.trait_data(d.trait_).name,
+            d.ty.display(ctx.sema.db)
+        ),
+        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn missing_try_impl() {
+        check_diagnostics(
+            r#"
+//- minicore: try
+fn main() {
+    ()?;
+} //^^ error: the trait `Try` is not implemented for `()`
+"#,
+        )
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index ae299f05841..4577072149a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -29,6 +29,7 @@ mod handlers {
     pub(crate) mod break_outside_of_loop;
     pub(crate) mod inactive_code;
     pub(crate) mod incorrect_case;
+    pub(crate) mod incorrect_try_expr;
     pub(crate) mod invalid_derive_target;
     pub(crate) mod macro_error;
     pub(crate) mod malformed_derive;
@@ -36,6 +37,7 @@ mod handlers {
     pub(crate) mod missing_fields;
     pub(crate) mod missing_match_arms;
     pub(crate) mod missing_unsafe;
+    pub(crate) mod not_implemented;
     pub(crate) mod no_such_field;
     pub(crate) mod replace_filter_map_next_with_find_map;
     pub(crate) mod type_mismatch;
@@ -225,12 +227,14 @@ pub fn diagnostics(
         let d = match diag {
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
+            AnyDiagnostic::IncorrectTryExpr(d) => handlers::incorrect_try_expr::incorrect_try_expr(&ctx, &d),
             AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
             AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
             AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
             AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
             AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
             AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
+            AnyDiagnostic::NotImplemented(d) => handlers::not_implemented::not_implemented(&ctx, &d),
             AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
             AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
             AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
index 73314e0f330..4baf786c455 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
@@ -12,8 +12,7 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-
-itertools = "0.10.3"
+itertools = "0.10.5"
 
 text-edit = { path = "../text-edit", version = "0.0.0" }
 parser = { path = "../parser", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index 0e9771cd2eb..712459a7ee9 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -13,12 +13,12 @@ doctest = false
 cov-mark = "2.0.0-pre.1"
 crossbeam-channel = "0.5.5"
 either = "1.7.0"
-itertools = "0.10.3"
+itertools = "0.10.5"
 tracing = "0.1.35"
 oorandom = "11.1.3"
-pulldown-cmark-to-cmark = "10.0.1"
+pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.1", default-features = false }
-url = "2.2.2"
+url = "2.3.1"
 dot = "0.1.4"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index f86ea61d158..d0be1b3f404 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -48,10 +48,14 @@ pub(crate) fn goto_definition(
             _ => 1,
         })?;
     if let Some(doc_comment) = token_as_doc_comment(&original_token) {
-        return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| {
-            let nav = def.try_to_nav(db)?;
-            Some(RangeInfo::new(original_token.text_range(), vec![nav]))
-        });
+        return doc_comment.get_definition_with_descend_at(
+            sema,
+            position.offset,
+            |def, _, link_range| {
+                let nav = def.try_to_nav(db)?;
+                Some(RangeInfo::new(link_range, vec![nav]))
+            },
+        );
     }
     let navs = sema
         .descend_into_macros(original_token.clone())
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index eb997e6fef8..5cab017a58d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -4913,6 +4913,22 @@ fn foo() -> NotResult<(), Short> {
                 ```
             "#]],
     );
+    check_hover_range(
+        r#"
+//- minicore: try
+use core::ops::ControlFlow;
+fn foo() -> ControlFlow<()> {
+    $0ControlFlow::Break(())?$0;
+    ControlFlow::Continue(())
+}
+"#,
+        expect![[r#"
+            ```text
+            Try Target Type: ControlFlow<(), {unknown}>
+            Propagated as:          ControlFlow<(), ()>
+            ```
+        "#]],
+    );
 }
 
 #[test]
@@ -4928,9 +4944,9 @@ fn foo() -> Option<()> {
 }
 "#,
         expect![[r#"
-                ```rust
-                <Option<i32> as Try>::Output
-                ```"#]],
+            ```rust
+            i32
+            ```"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml
index 5ff3448a19c..13cd8901031 100644
--- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
 [dependencies]
 cov-mark = "2.0.0-pre.1"
 rustc-hash = "1.1.0"
-smallvec = "1.9.0"
+smallvec = "1.10.0"
 tracing = "0.1.35"
 
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index ac691578d88..9c92bae6a19 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -8,7 +8,7 @@ use syntax::{
 use test_utils::{bench, bench_fixture, skip_slow_tests};
 
 use crate::{
-    parser::{Op, RepeatKind, Separator},
+    parser::{MetaVarKind, Op, RepeatKind, Separator},
     syntax_node_to_token_tree, DeclarativeMacro,
 };
 
@@ -111,35 +111,35 @@ fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(Stri
 
     fn collect_from_op(op: &Op, parent: &mut tt::Subtree, seed: &mut usize) {
         return match op {
-            Op::Var { kind, .. } => match kind.as_ref().map(|it| it.as_str()) {
-                Some("ident") => parent.token_trees.push(make_ident("foo")),
-                Some("ty") => parent.token_trees.push(make_ident("Foo")),
-                Some("tt") => parent.token_trees.push(make_ident("foo")),
-                Some("vis") => parent.token_trees.push(make_ident("pub")),
-                Some("pat") => parent.token_trees.push(make_ident("foo")),
-                Some("path") => parent.token_trees.push(make_ident("foo")),
-                Some("literal") => parent.token_trees.push(make_literal("1")),
-                Some("expr") => parent.token_trees.push(make_ident("foo")),
-                Some("lifetime") => {
+            Op::Var { kind, .. } => match kind.as_ref() {
+                Some(MetaVarKind::Ident) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Ty) => parent.token_trees.push(make_ident("Foo")),
+                Some(MetaVarKind::Tt) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Vis) => parent.token_trees.push(make_ident("pub")),
+                Some(MetaVarKind::Pat) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Path) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Literal) => parent.token_trees.push(make_literal("1")),
+                Some(MetaVarKind::Expr) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Lifetime) => {
                     parent.token_trees.push(make_punct('\''));
                     parent.token_trees.push(make_ident("a"));
                 }
-                Some("block") => {
+                Some(MetaVarKind::Block) => {
                     parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
                 }
-                Some("item") => {
+                Some(MetaVarKind::Item) => {
                     parent.token_trees.push(make_ident("fn"));
                     parent.token_trees.push(make_ident("foo"));
                     parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
                     parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
                 }
-                Some("meta") => {
+                Some(MetaVarKind::Meta) => {
                     parent.token_trees.push(make_ident("foo"));
                     parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
                 }
 
                 None => (),
-                Some(kind) => panic!("Unhandled kind {}", kind),
+                Some(kind) => panic!("Unhandled kind {:?}", kind),
             },
             Op::Leaf(leaf) => parent.token_trees.push(leaf.clone().into()),
             Op::Repeat { tokens, kind, separator } => {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
index 1e1bfa55055..100ec6bfb93 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
@@ -8,7 +8,7 @@ mod transcriber;
 use rustc_hash::FxHashMap;
 use syntax::SmolStr;
 
-use crate::{ExpandError, ExpandResult};
+use crate::{parser::MetaVarKind, ExpandError, ExpandResult};
 
 pub(crate) fn expand_rules(
     rules: &[crate::Rule],
@@ -104,6 +104,7 @@ enum Binding {
     Fragment(Fragment),
     Nested(Vec<Binding>),
     Empty,
+    Missing(MetaVarKind),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
index 139a8cb8cbe..3f656df25f7 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
@@ -66,7 +66,7 @@ use syntax::SmolStr;
 
 use crate::{
     expander::{Binding, Bindings, ExpandResult, Fragment},
-    parser::{Op, RepeatKind, Separator},
+    parser::{MetaVarKind, Op, RepeatKind, Separator},
     tt_iter::TtIter,
     ExpandError, MetaTemplate,
 };
@@ -119,6 +119,7 @@ pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match {
             .map(|it| match it {
                 Binding::Fragment(_) => 1,
                 Binding::Empty => 1,
+                Binding::Missing(_) => 1,
                 Binding::Nested(it) => count(it.iter()),
             })
             .sum()
@@ -130,6 +131,7 @@ enum BindingKind {
     Empty(SmolStr),
     Optional(SmolStr),
     Fragment(SmolStr, Fragment),
+    Missing(SmolStr, MetaVarKind),
     Nested(usize, usize),
 }
 
@@ -190,6 +192,10 @@ impl BindingsBuilder {
             .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment))));
     }
 
+    fn push_missing(&mut self, idx: &mut BindingsIdx, var: &SmolStr, kind: MetaVarKind) {
+        self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Missing(var.clone(), kind))));
+    }
+
     fn push_nested(&mut self, parent: &mut BindingsIdx, child: &BindingsIdx) {
         let BindingsIdx(idx, nidx) = self.copy(child);
         self.nodes[parent.0].push(LinkNode::Node(Rc::new(BindingKind::Nested(idx, nidx))));
@@ -222,6 +228,9 @@ impl BindingsBuilder {
                 BindingKind::Fragment(name, fragment) => {
                     bindings.inner.insert(name.clone(), Binding::Fragment(fragment.clone()));
                 }
+                BindingKind::Missing(name, kind) => {
+                    bindings.inner.insert(name.clone(), Binding::Missing(*kind));
+                }
                 BindingKind::Nested(idx, nested_idx) => {
                     let mut nested_nodes = Vec::new();
                     self.collect_nested(*idx, *nested_idx, &mut nested_nodes);
@@ -458,9 +467,9 @@ fn match_loop_inner<'t>(
                 }
             }
             OpDelimited::Op(Op::Var { kind, name, .. }) => {
-                if let Some(kind) = kind {
+                if let &Some(kind) = kind {
                     let mut fork = src.clone();
-                    let match_res = match_meta_var(kind.as_str(), &mut fork);
+                    let match_res = match_meta_var(kind, &mut fork);
                     match match_res.err {
                         None => {
                             // Some meta variables are optional (e.g. vis)
@@ -475,8 +484,15 @@ fn match_loop_inner<'t>(
                         }
                         Some(err) => {
                             res.add_err(err);
-                            if let Some(fragment) = match_res.value {
-                                bindings_builder.push_fragment(&mut item.bindings, name, fragment);
+                            match match_res.value {
+                                Some(fragment) => bindings_builder.push_fragment(
+                                    &mut item.bindings,
+                                    name,
+                                    fragment,
+                                ),
+                                None => {
+                                    bindings_builder.push_missing(&mut item.bindings, name, kind)
+                                }
                             }
                             item.is_error = true;
                             error_items.push(item);
@@ -668,20 +684,20 @@ fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter<'_>) -> Result<(), ExpandError> {
     }
 }
 
-fn match_meta_var(kind: &str, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
+fn match_meta_var(kind: MetaVarKind, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
     let fragment = match kind {
-        "path" => parser::PrefixEntryPoint::Path,
-        "ty" => parser::PrefixEntryPoint::Ty,
+        MetaVarKind::Path => parser::PrefixEntryPoint::Path,
+        MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
         // FIXME: These two should actually behave differently depending on the edition.
         //
         // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html
-        "pat" | "pat_param" => parser::PrefixEntryPoint::Pat,
-        "stmt" => parser::PrefixEntryPoint::Stmt,
-        "block" => parser::PrefixEntryPoint::Block,
-        "meta" => parser::PrefixEntryPoint::MetaItem,
-        "item" => parser::PrefixEntryPoint::Item,
-        "vis" => parser::PrefixEntryPoint::Vis,
-        "expr" => {
+        MetaVarKind::Pat | MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
+        MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
+        MetaVarKind::Block => parser::PrefixEntryPoint::Block,
+        MetaVarKind::Meta => parser::PrefixEntryPoint::MetaItem,
+        MetaVarKind::Item => parser::PrefixEntryPoint::Item,
+        MetaVarKind::Vis => parser::PrefixEntryPoint::Vis,
+        MetaVarKind::Expr => {
             // `expr` should not match underscores.
             // HACK: Macro expansion should not be done using "rollback and try another alternative".
             // rustc [explicitly checks the next token][0].
@@ -698,17 +714,17 @@ fn match_meta_var(kind: &str, input: &mut TtIter<'_>) -> ExpandResult<Option<Fra
         }
         _ => {
             let tt_result = match kind {
-                "ident" => input
+                MetaVarKind::Ident => input
                     .expect_ident()
                     .map(|ident| tt::Leaf::from(ident.clone()).into())
                     .map_err(|()| ExpandError::binding_error("expected ident")),
-                "tt" => input
+                MetaVarKind::Tt => input
                     .expect_tt()
                     .map_err(|()| ExpandError::binding_error("expected token tree")),
-                "lifetime" => input
+                MetaVarKind::Lifetime => input
                     .expect_lifetime()
                     .map_err(|()| ExpandError::binding_error("expected lifetime")),
-                "literal" => {
+                MetaVarKind::Literal => {
                     let neg = input.eat_char('-');
                     input
                         .expect_literal()
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 7bcc84740f1..cbb59ab8e67 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -6,7 +6,7 @@ use tt::{Delimiter, Subtree};
 
 use crate::{
     expander::{Binding, Bindings, Fragment},
-    parser::{Op, RepeatKind, Separator},
+    parser::{MetaVarKind, Op, RepeatKind, Separator},
     ExpandError, ExpandResult, MetaTemplate,
 };
 
@@ -15,7 +15,7 @@ impl Bindings {
         self.inner.contains_key(name)
     }
 
-    fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
+    fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<Fragment, ExpandError> {
         macro_rules! binding_err {
             ($($arg:tt)*) => { ExpandError::binding_error(format!($($arg)*)) };
         }
@@ -26,6 +26,7 @@ impl Bindings {
             nesting_state.hit = true;
             b = match b {
                 Binding::Fragment(_) => break,
+                Binding::Missing(_) => break,
                 Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
                     nesting_state.at_end = true;
                     binding_err!("could not find nested binding `{name}`")
@@ -37,7 +38,55 @@ impl Bindings {
             };
         }
         match b {
-            Binding::Fragment(it) => Ok(it),
+            Binding::Fragment(it) => Ok(it.clone()),
+            // emit some reasonable default expansion for missing bindings,
+            // this gives better recovery than emitting the `$fragment-name` verbatim
+            Binding::Missing(it) => Ok(match it {
+                MetaVarKind::Stmt => {
+                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+                        id: tt::TokenId::unspecified(),
+                        char: ';',
+                        spacing: tt::Spacing::Alone,
+                    })))
+                }
+                MetaVarKind::Block => Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
+                    delimiter: Some(tt::Delimiter {
+                        id: tt::TokenId::unspecified(),
+                        kind: tt::DelimiterKind::Brace,
+                    }),
+                    token_trees: vec![],
+                })),
+                // FIXME: Meta and Item should get proper defaults
+                MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
+                    Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
+                        delimiter: None,
+                        token_trees: vec![],
+                    }))
+                }
+                MetaVarKind::Path
+                | MetaVarKind::Ty
+                | MetaVarKind::Pat
+                | MetaVarKind::PatParam
+                | MetaVarKind::Expr
+                | MetaVarKind::Ident => {
+                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                        text: SmolStr::new_inline("missing"),
+                        id: tt::TokenId::unspecified(),
+                    })))
+                }
+                MetaVarKind::Lifetime => {
+                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                        text: SmolStr::new_inline("'missing"),
+                        id: tt::TokenId::unspecified(),
+                    })))
+                }
+                MetaVarKind::Literal => {
+                    Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+                        text: SmolStr::new_inline("\"missing\""),
+                        id: tt::TokenId::unspecified(),
+                    })))
+                }
+            }),
             Binding::Nested(_) => {
                 Err(binding_err!("expected simple binding, found nested binding `{name}`"))
             }
@@ -157,7 +206,7 @@ fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandRe
     } else {
         ctx.bindings.get(v, &mut ctx.nesting).map_or_else(
             |e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) },
-            |b| ExpandResult::ok(b.clone()),
+            |it| ExpandResult::ok(it),
         )
     }
 }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index 79da84f4a02..c4f0fa20d6d 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -21,7 +21,7 @@ mod token_map;
 use std::fmt;
 
 use crate::{
-    parser::{MetaTemplate, Op},
+    parser::{MetaTemplate, MetaVarKind, Op},
     tt_iter::TtIter,
 };
 
@@ -291,9 +291,9 @@ fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
                 // Checks that no repetition which could match an empty token
                 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558
                 let lsh_is_empty_seq = separator.is_none() && subtree.iter().all(|child_op| {
-                    match child_op {
+                    match *child_op {
                         // vis is optional
-                        Op::Var { kind: Some(kind), .. } => kind == "vis",
+                        Op::Var { kind: Some(kind), .. } => kind == MetaVarKind::Vis,
                         Op::Repeat {
                             kind: parser::RepeatKind::ZeroOrMore | parser::RepeatKind::ZeroOrOne,
                             ..
diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
index acb4be5846d..351c359b73c 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
@@ -50,7 +50,7 @@ impl MetaTemplate {
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum Op {
-    Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId },
+    Var { name: SmolStr, kind: Option<MetaVarKind>, id: tt::TokenId },
     Ignore { name: SmolStr, id: tt::TokenId },
     Index { depth: u32 },
     Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
@@ -65,6 +65,24 @@ pub(crate) enum RepeatKind {
     ZeroOrOne,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum MetaVarKind {
+    Path,
+    Ty,
+    Pat,
+    PatParam,
+    Stmt,
+    Block,
+    Meta,
+    Item,
+    Vis,
+    Expr,
+    Ident,
+    Tt,
+    Lifetime,
+    Literal,
+}
+
 #[derive(Clone, Debug, Eq)]
 pub(crate) enum Separator {
     Literal(tt::Literal),
@@ -179,13 +197,30 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
     Ok(res)
 }
 
-fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<SmolStr>, ParseError> {
+fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<MetaVarKind>, ParseError> {
     if let Mode::Pattern = mode {
         src.expect_char(':').map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
         let ident = src
             .expect_ident()
             .map_err(|()| ParseError::unexpected("missing fragment specifier"))?;
-        return Ok(Some(ident.text.clone()));
+        let kind = match ident.text.as_str() {
+            "path" => MetaVarKind::Path,
+            "ty" => MetaVarKind::Ty,
+            "pat" => MetaVarKind::Pat,
+            "pat_param" => MetaVarKind::PatParam,
+            "stmt" => MetaVarKind::Stmt,
+            "block" => MetaVarKind::Block,
+            "meta" => MetaVarKind::Meta,
+            "item" => MetaVarKind::Item,
+            "vis" => MetaVarKind::Vis,
+            "expr" => MetaVarKind::Expr,
+            "ident" => MetaVarKind::Ident,
+            "tt" => MetaVarKind::Tt,
+            "lifetime" => MetaVarKind::Lifetime,
+            "literal" => MetaVarKind::Literal,
+            _ => return Ok(None),
+        };
+        return Ok(Some(kind));
     };
     Ok(None)
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
index 85a1c13fe7d..54879c1870c 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
@@ -19,7 +19,7 @@ object = { version = "0.29.0", default-features = false, features = [
 ] }
 serde = { version = "1.0.137", features = ["derive"] }
 serde_json = { version = "1.0.81", features = ["unbounded_depth"] }
-tracing = "0.1.35"
+tracing = "0.1.37"
 memmap2 = "0.5.4"
 snap = "1.0.5"
 
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index 0b78a45a24b..5697aea964f 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -10,9 +10,9 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-once_cell = "1.12.0"
+once_cell = "1.15.0"
 cfg-if = "1.0.0"
-libc = "0.2.126"
+libc = "0.2.135"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 countme = { version = "3.0.1", features = ["enable"] }
 jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true }
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index bc75d6faa38..6fd7c3166f8 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -13,10 +13,10 @@ doctest = false
 tracing = "0.1.35"
 rustc-hash = "1.1.0"
 cargo_metadata = "0.15.0"
-semver = "1.0.10"
+semver = "1.0.14"
 serde = { version = "1.0.137", features = ["derive"] }
-serde_json = "1.0.81"
-anyhow = "1.0.57"
+serde_json = "1.0.86"
+anyhow = "1.0.62"
 expect-test = "1.4.0"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index 32db42f1db7..d9f09c03495 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -154,6 +154,8 @@ impl WorkspaceBuildScripts {
                             Some(&it) => it,
                             None => return,
                         };
+                        progress(format!("running build-script: {}", workspace[package].name));
+
                         let cfgs = {
                             let mut acc = Vec::new();
                             for cfg in message.cfgs {
@@ -189,7 +191,7 @@ impl WorkspaceBuildScripts {
                             None => return,
                         };
 
-                        progress(format!("metadata {}", message.target.name));
+                        progress(format!("building proc-macros: {}", message.target.name));
 
                         if message.target.kind.iter().any(|k| k == "proc-macro") {
                             // Skip rmeta file
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index a4e6550984e..5445028536c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -18,10 +18,10 @@ name = "rust-analyzer"
 path = "src/bin/main.rs"
 
 [dependencies]
-anyhow = "1.0.57"
+anyhow = "1.0.62"
 crossbeam-channel = "0.5.5"
 dissimilar = "1.0.4"
-itertools = "0.10.3"
+itertools = "0.10.5"
 scip = "0.1.1"
 lsp-types = { version = "0.93.1", features = ["proposed"] }
 parking_lot = "0.12.1"
@@ -33,10 +33,10 @@ serde_json = { version = "1.0.81", features = ["preserve_order"] }
 threadpool = "1.8.1"
 rayon = "1.5.3"
 num_cpus = "1.13.1"
-mimalloc = { version = "0.1.29", default-features = false, optional = true }
+mimalloc = { version = "0.1.30", default-features = false, optional = true }
 lsp-server = { version = "0.7.0", path = "../../lib/lsp-server" }
 tracing = "0.1.35"
-tracing-subscriber = { version = "0.3.14", default-features = false, features = [
+tracing-subscriber = { version = "0.3.16", default-features = false, features = [
     "env-filter",
     "registry",
     "fmt",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 58099a58de0..24e68eca676 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -177,6 +177,7 @@ fn check_licenses() {
     let sh = &Shell::new().unwrap();
 
     let expected = "
+(MIT OR Apache-2.0) AND Unicode-DFS-2016
 0BSD OR MIT OR Apache-2.0
 Apache-2.0
 Apache-2.0 OR BSL-1.0
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 092b99ae515..e0657ab0f6d 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -10,7 +10,7 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-libc = "0.2.126"
+libc = "0.2.135"
 backtrace = { version = "0.3.65", optional = true }
 always-assert = { version = "0.1.2", features = ["log"] }
 # Think twice before adding anything here
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index 0e2dec386ff..1ef903371cf 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -12,11 +12,11 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.3"
-rowan = "0.15.8"
+itertools = "0.10.5"
+rowan = "0.15.10"
 rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
-once_cell = "1.12.0"
+once_cell = "1.15.0"
 indexmap = "1.9.1"
 smol_str = "0.1.23"
 
@@ -28,7 +28,7 @@ profile = { path = "../profile", version = "0.0.0" }
 [dev-dependencies]
 rayon = "1.5.3"
 expect-test = "1.4.0"
-proc-macro2 = "1.0.39"
+proc-macro2 = "1.0.47"
 quote = "1.0.20"
 ungrammar = "1.16.1"
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index eadebbe8a21..229e7419b73 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -235,6 +235,24 @@ impl ast::GenericParamList {
             }
         }
     }
+
+    /// Constructs a matching [`ast::GenericArgList`]
+    pub fn to_generic_args(&self) -> ast::GenericArgList {
+        let args = self.generic_params().filter_map(|param| match param {
+            ast::GenericParam::LifetimeParam(it) => {
+                Some(ast::GenericArg::LifetimeArg(make::lifetime_arg(it.lifetime()?)))
+            }
+            ast::GenericParam::TypeParam(it) => {
+                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
+            }
+            ast::GenericParam::ConstParam(it) => {
+                // Name-only const params get parsed as `TypeArg`s
+                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
+            }
+        });
+
+        make::generic_arg_list(args)
+    }
 }
 
 impl ast::WhereClause {
@@ -248,6 +266,42 @@ impl ast::WhereClause {
     }
 }
 
+impl ast::TypeParam {
+    pub fn remove_default(&self) {
+        if let Some((eq, last)) = self
+            .syntax()
+            .children_with_tokens()
+            .find(|it| it.kind() == T![=])
+            .zip(self.syntax().last_child_or_token())
+        {
+            ted::remove_all(eq..=last);
+
+            // remove any trailing ws
+            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
+                last.detach();
+            }
+        }
+    }
+}
+
+impl ast::ConstParam {
+    pub fn remove_default(&self) {
+        if let Some((eq, last)) = self
+            .syntax()
+            .children_with_tokens()
+            .find(|it| it.kind() == T![=])
+            .zip(self.syntax().last_child_or_token())
+        {
+            ted::remove_all(eq..=last);
+
+            // remove any trailing ws
+            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
+                last.detach();
+            }
+        }
+    }
+}
+
 pub trait Removable: AstNode {
     fn remove(&self);
 }
@@ -264,7 +318,7 @@ impl Removable for ast::TypeBoundList {
 impl ast::PathSegment {
     pub fn get_or_create_generic_arg_list(&self) -> ast::GenericArgList {
         if self.generic_arg_list().is_none() {
-            let arg_list = make::generic_arg_list().clone_for_update();
+            let arg_list = make::generic_arg_list(empty()).clone_for_update();
             ted::append_child(self.syntax(), arg_list.syntax());
         }
         self.generic_arg_list().unwrap()
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 83f8bbac588..4057a75e7c1 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -88,6 +88,9 @@ pub mod ext {
         block_expr(None, None)
     }
 
+    pub fn ty_name(name: ast::Name) -> ast::Type {
+        ty_path(ident_path(&name.to_string()))
+    }
     pub fn ty_bool() -> ast::Type {
         ty_path(ident_path("bool"))
     }
@@ -160,6 +163,7 @@ pub fn assoc_item_list() -> ast::AssocItemList {
     ast_from_text("impl C for D {}")
 }
 
+// FIXME: `ty_params` should be `ast::GenericArgList`
 pub fn impl_(
     ty: ast::Path,
     params: Option<ast::GenericParamList>,
@@ -185,10 +189,6 @@ pub fn impl_trait(
     ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
 }
 
-pub(crate) fn generic_arg_list() -> ast::GenericArgList {
-    ast_from_text("const S: T<> = ();")
-}
-
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
     ast_from_text(&format!("type __ = {name_ref};"))
 }
@@ -718,6 +718,21 @@ pub fn generic_param_list(
     ast_from_text(&format!("fn f<{args}>() {{ }}"))
 }
 
+pub fn type_arg(ty: ast::Type) -> ast::TypeArg {
+    ast_from_text(&format!("const S: T<{ty}> = ();"))
+}
+
+pub fn lifetime_arg(lifetime: ast::Lifetime) -> ast::LifetimeArg {
+    ast_from_text(&format!("const S: T<{lifetime}> = ();"))
+}
+
+pub(crate) fn generic_arg_list(
+    args: impl IntoIterator<Item = ast::GenericArg>,
+) -> ast::GenericArgList {
+    let args = args.into_iter().join(", ");
+    ast_from_text(&format!("const S: T<{args}> = ();"))
+}
+
 pub fn visibility_pub_crate() -> ast::Visibility {
     ast_from_text("pub(crate) struct S")
 }
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
index 8c806e7925b..c824f5af725 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -61,6 +61,8 @@
 //! "
 //! ```
 
+use std::iter;
+
 use rustc_hash::FxHashMap;
 use stdx::trim_indent;
 
@@ -259,7 +261,7 @@ impl MiniCore {
             if res.has_flag(entry) {
                 panic!("duplicate minicore flag: {:?}", entry);
             }
-            res.activated_flags.push(entry.to_string());
+            res.activated_flags.push(entry.to_owned());
         }
 
         res
@@ -273,35 +275,34 @@ impl MiniCore {
         let raw_mini_core = include_str!("./minicore.rs");
         let mut lines = raw_mini_core.split_inclusive('\n');
 
-        let mut parsing_flags = false;
         let mut implications = Vec::new();
 
         // Parse `//!` preamble and extract flags and dependencies.
-        for line in lines.by_ref() {
-            let line = match line.strip_prefix("//!") {
-                Some(it) => it,
-                None => {
-                    assert!(line.trim().is_empty());
-                    break;
-                }
-            };
-
-            if parsing_flags {
-                let (flag, deps) = line.split_once(':').unwrap();
-                let flag = flag.trim();
-                self.valid_flags.push(flag.to_string());
-                for dep in deps.split(", ") {
-                    let dep = dep.trim();
-                    if !dep.is_empty() {
-                        self.assert_valid_flag(dep);
-                        implications.push((flag, dep));
-                    }
-                }
+        let trim_doc: fn(&str) -> Option<&str> = |line| match line.strip_prefix("//!") {
+            Some(it) => Some(it),
+            None => {
+                assert!(line.trim().is_empty(), "expected empty line after minicore header");
+                None
             }
+        };
+        for line in lines
+            .by_ref()
+            .map_while(trim_doc)
+            .skip_while(|line| !line.contains("Available flags:"))
+            .skip(1)
+        {
+            let (flag, deps) = line.split_once(':').unwrap();
+            let flag = flag.trim();
+
+            self.valid_flags.push(flag.to_string());
+            implications.extend(
+                iter::repeat(flag)
+                    .zip(deps.split(", ").map(str::trim).filter(|dep| !dep.is_empty())),
+            );
+        }
 
-            if line.contains("Available flags:") {
-                parsing_flags = true;
-            }
+        for (_, dep) in &implications {
+            self.assert_valid_flag(dep);
         }
 
         for flag in &self.activated_flags {
@@ -332,7 +333,7 @@ impl MiniCore {
             }
             if let Some(region) = trimmed.strip_prefix("// endregion:") {
                 let prev = active_regions.pop().unwrap();
-                assert_eq!(prev, region);
+                assert_eq!(prev, region, "unbalanced region pairs");
                 continue;
             }
 
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 10386b5b7bc..59b1c147d7f 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -8,36 +8,37 @@
 //! We then strip all the code marked with other flags.
 //!
 //! Available flags:
-//!     sized:
-//!     unsize: sized
+//!     add:
+//!     as_ref: sized
+//!     bool_impl: option, fn
+//!     clone: sized
 //!     coerce_unsized: unsize
-//!     slice:
-//!     range:
-//!     deref: sized
+//!     copy: clone
+//!     default: sized
 //!     deref_mut: deref
-//!     index: sized
+//!     deref: sized
+//!     derive:
+//!     drop:
+//!     eq: sized
+//!     fmt: result
 //!     fn:
-//!     try:
-//!     pin:
+//!     from: sized
 //!     future: pin
-//!     option:
-//!     result:
+//!     generator: pin
+//!     hash:
+//!     index: sized
+//!     infallible:
 //!     iterator: option
 //!     iterators: iterator, fn
-//!     default: sized
-//!     hash:
-//!     clone: sized
-//!     copy: clone
-//!     from: sized
-//!     eq: sized
+//!     option:
 //!     ord: eq, option
-//!     derive:
-//!     fmt: result
-//!     bool_impl: option, fn
-//!     add:
-//!     as_ref: sized
-//!     drop:
-//!     generator: pin
+//!     pin:
+//!     range:
+//!     result:
+//!     sized:
+//!     slice:
+//!     try: infallible
+//!     unsize: sized
 
 pub mod marker {
     // region:sized
@@ -150,6 +151,9 @@ pub mod convert {
         fn as_ref(&self) -> &T;
     }
     // endregion:as_ref
+    // region:infallible
+    pub enum Infallible {}
+    // endregion:infallible
 }
 
 pub mod ops {
@@ -326,7 +330,7 @@ pub mod ops {
             Continue(C),
             Break(B),
         }
-        pub trait FromResidual<R = Self::Residual> {
+        pub trait FromResidual<R = <Self as Try>::Residual> {
             #[lang = "from_residual"]
             fn from_residual(residual: R) -> Self;
         }
@@ -342,13 +346,13 @@ pub mod ops {
 
         impl<B, C> Try for ControlFlow<B, C> {
             type Output = C;
-            type Residual = ControlFlow<B, convert::Infallible>;
+            type Residual = ControlFlow<B, crate::convert::Infallible>;
             fn from_output(output: Self::Output) -> Self {}
             fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {}
         }
 
         impl<B, C> FromResidual for ControlFlow<B, C> {
-            fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {}
+            fn from_residual(residual: ControlFlow<B, crate::convert::Infallible>) -> Self {}
         }
     }
     pub use self::try_::{ControlFlow, FromResidual, Try};
@@ -469,6 +473,33 @@ pub mod option {
             }
         }
     }
+    // region:try
+    impl<T> crate::ops::Try for Option<T> {
+        type Output = T;
+        type Residual = Option<crate::convert::Infallible>;
+
+        #[inline]
+        fn from_output(output: Self::Output) -> Self {
+            Some(output)
+        }
+
+        #[inline]
+        fn branch(self) -> crate::ops::ControlFlow<Self::Residual, Self::Output> {
+            match self {
+                Some(v) => crate::ops::ControlFlow::Continue(v),
+                None => crate::ops::ControlFlow::Break(None),
+            }
+        }
+    }
+    impl<T> crate::ops::FromResidual for Option<T> {
+        #[inline]
+        fn from_residual(residual: Option<crate::convert::Infallible>) -> Self {
+            match residual {
+                None => None,
+            }
+        }
+    }
+    // endregion:try
 }
 // endregion:option
 
@@ -584,7 +615,7 @@ pub mod iter {
             }
         }
     }
-    pub use self::adapters::{Take, FilterMap};
+    pub use self::adapters::{FilterMap, Take};
 
     mod sources {
         mod repeat {
diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
index cf14bbd3c3e..7a90d64a98b 100644
--- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
@@ -10,5 +10,5 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-itertools = "0.10.3"
+itertools = "0.10.5"
 text-size = "1.1.0"
diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
index 7d3b9e09ece..3e0f31f19c5 100644
--- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
@@ -10,4 +10,4 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-home = "0.5.3"
+home = "0.5.4"
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
index fcc693a7dda..df5dc24e2cd 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
@@ -14,7 +14,7 @@ tracing = "0.1.35"
 jod-thread = "0.1.2"
 walkdir = "2.3.2"
 crossbeam-channel = "0.5.5"
-notify = "=5.0.0-pre.16"
+notify = "5.0"
 
 vfs = { path = "../vfs", version = "0.0.0" }
 paths = { path = "../paths", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/docs/dev/guide.md b/src/tools/rust-analyzer/docs/dev/guide.md
index c9ff0b6c29e..52a13da31c5 100644
--- a/src/tools/rust-analyzer/docs/dev/guide.md
+++ b/src/tools/rust-analyzer/docs/dev/guide.md
@@ -88,9 +88,8 @@ is lower than Cargo's model of packages: each Cargo package consists of several
 targets, each of which is a separate crate (or several crates, if you try
 different feature combinations).
 
-Procedural macros should become inputs as well, but currently they are not
-supported. Procedural macro will be a black box `Box<dyn Fn(TokenStream) -> TokenStream>`
-function, and will be inserted into the crate graph just like dependencies.
+Procedural macros are inputs as well, roughly modeled as a crate with a bunch of
+additional black box `dyn Fn(TokenStream) -> TokenStream` functions.
 
 Soon we'll talk how we build an LSP server on top of `Analysis`, but first,
 let's deal with that paths issue.
diff --git a/src/tools/rust-analyzer/docs/dev/syntax.md b/src/tools/rust-analyzer/docs/dev/syntax.md
index 30e13701383..97e376787c8 100644
--- a/src/tools/rust-analyzer/docs/dev/syntax.md
+++ b/src/tools/rust-analyzer/docs/dev/syntax.md
@@ -8,10 +8,10 @@ This guide describes the current state of syntax trees and parsing in rust-analy
 
 The things described are implemented in three places
 
-* [rowan](https://github.com/rust-analyzer/rowan/tree/v0.9.0) -- a generic library for rowan syntax trees.
-* [ra_syntax](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/ra_syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API.
+* [rowan](https://github.com/rust-analyzer/rowan/tree/v0.15.10) -- a generic library for rowan syntax trees.
+* [syntax](https://github.com/rust-lang/rust-analyzer/tree/36a70b7435c48837018c71576d7bb4e8f763f501/crates/syntax) crate inside rust-analyzer which wraps `rowan` into rust-analyzer specific API.
   Nothing in rust-analyzer except this crate knows about `rowan`.
-* [parser](https://github.com/rust-lang/rust-analyzer/tree/cf5bdf464cad7ceb9a67e07985a3f4d3799ec0b6/crates/parser) crate parses input tokens into an `ra_syntax` tree
+* [parser](https://github.com/rust-lang/rust-analyzer/tree/36a70b7435c48837018c71576d7bb4e8f763f501/crates/parser) crate parses input tokens into a `syntax` tree
 
 ## Design Goals
 
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 9bd3b6a692b..c30838e5f5e 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -174,14 +174,25 @@ On Unix, running the editor from a shell or changing the `.desktop` file to set
 
 ==== `rustup`
 
-`rust-analyzer` is available in `rustup`, but only in the nightly toolchain:
+`rust-analyzer` is available in `rustup`:
 
 [source,bash]
 ----
-$ rustup +nightly component add rust-analyzer-preview
+$ rustup component add rust-analyzer
 ----
 
-However, in contrast to `component add clippy` or `component add rustfmt`, this does not actually place a `rust-analyzer` binary in `~/.cargo/bin`, see https://github.com/rust-lang/rustup/issues/2411[this issue].
+However, in contrast to `component add clippy` or `component add rustfmt`, this does not actually place a `rust-analyzer` binary in `~/.cargo/bin`, see https://github.com/rust-lang/rustup/issues/2411[this issue]. You can find the path to the binary using:
+[source,bash]
+----
+$ rustup which --toolchain stable rust-analyzer
+----
+You can link to there from `~/.cargo/bin` or configure your editor to use the full path.
+
+Alternatively you might be able to configure your editor to start `rust-analyzer` using the command:
+[source,bash]
+----
+$ rustup run stable rust-analyzer
+----
 
 ==== Arch Linux
 
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index a9c0f079b3d..15846a5e864 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -133,7 +133,21 @@ export class Config {
     }
 
     get runnableEnv() {
-        return this.get<RunnableEnvCfg>("runnableEnv");
+        const item = this.get<any>("runnableEnv");
+        if (!item) return item;
+        const fixRecord = (r: Record<string, any>) => {
+            for (const key in r) {
+                if (typeof r[key] !== "string") {
+                    r[key] = String(r[key]);
+                }
+            }
+        };
+        if (item instanceof Array) {
+            item.forEach((x) => fixRecord(x.env));
+        } else {
+            fixRecord(item);
+        }
+        return item;
     }
 
     get restartServerOnConfigChange() {
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index b236b156cf9..5922bbfdb48 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -8,7 +8,7 @@ edition = "2021"
 
 [dependencies]
 log = "0.4.17"
-serde_json = "1.0.85"
+serde_json = "1.0.86"
 serde = { version = "1.0.144", features = ["derive"] }
 crossbeam-channel = "0.5.6"
 
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index 14816912b72..0be0bf920de 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 rust-version = "1.57"
 
 [dependencies]
-anyhow = "1.0.57"
+anyhow = "1.0.62"
 flate2 = "1.0.24"
 write-json = "0.1.2"
 xshell = "0.2.2"
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 3815259c9aa..c600f99c2c4 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -8,7 +8,7 @@ use std::path::Path;
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
 const ROOT_ENTRY_LIMIT: usize = 948;
-const ISSUES_ENTRY_LIMIT: usize = 2126;
+const ISSUES_ENTRY_LIMIT: usize = 2117;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
diff --git a/triagebot.toml b/triagebot.toml
index 69bd4939409..04c2a0507ac 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -183,6 +183,11 @@ trigger_files = [
     "x.ps1",
     "src/bootstrap",
     "src/tools/rust-installer",
+    "configure",
+    "Cargo.toml",
+    "Cargo.lock",
+    "config.toml.example",
+    "src/stage0.json"
 ]
 
 [autolabel."T-infra"]
@@ -210,6 +215,37 @@ trigger_files = [
     "compiler/rustc_macros/src/query.rs"
 ]
 
+[autolabel."A-testsuite"]
+trigger_files = [
+    "src/ci",
+    "src/tools/compiletest",
+    "src/tools/cargotest",
+    "src/tools/tidy",
+    "src/tools/remote-test-server",
+    "src/tools/remote-test-client",
+    "src/tools/tier-check"
+]
+
+[autolabel."A-meta"]
+trigger_files = [
+    "triagebot.toml",
+    "rustfmt.toml",
+    "LICENSES",
+    "README.md",
+    "CONTRIBUTING.md",
+    ".reuse",
+    ".mailmap",
+    ".git-blame-ignore-revs",
+    ".editorconfig"
+]
+
+[autolabel."T-release"]
+trigger_files = [
+    "RELEASES.md",
+    "src/stage0.json",
+    "src/version"
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"