about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.mailmap4
-rw-r--r--Cargo.lock2
-rw-r--r--compiler/rustc_ast/src/ast.rs4
-rw-r--r--compiler/rustc_ast/src/token.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs28
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs4
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs14
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/semantics.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs9
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs54
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/parser.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs11
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs43
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs10
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs30
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl4
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs71
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock84
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml24
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch69
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml17
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs131
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs47
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs12
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs10
-rw-r--r--compiler/rustc_error_messages/Cargo.toml1
-rw-r--r--compiler/rustc_error_messages/src/lib.rs8
-rw-r--r--compiler/rustc_errors/src/json.rs1
-rw-r--r--compiler/rustc_errors/src/timings.rs47
-rw-r--r--compiler/rustc_expand/messages.ftl2
-rw-r--r--compiler/rustc_expand/src/config.rs1
-rw-r--r--compiler/rustc_expand/src/errors.rs3
-rw-r--r--compiler/rustc_expand/src/mbe.rs10
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs12
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs53
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs49
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs128
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs45
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs22
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs4
-rw-r--r--compiler/rustc_interface/src/interface.rs13
-rw-r--r--compiler/rustc_interface/src/passes.rs5
-rw-r--r--compiler/rustc_interface/src/queries.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs9
-rw-r--r--compiler/rustc_interface/src/util.rs36
-rw-r--r--compiler/rustc_lint/src/context.rs14
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/lints.rs19
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs107
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs1
-rw-r--r--compiler/rustc_metadata/src/locator.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs37
-rw-r--r--compiler/rustc_middle/src/middle/exported_symbols.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs49
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs47
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs7
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs7
-rw-r--r--compiler/rustc_passes/src/check_attr.rs15
-rw-r--r--compiler/rustc_passes/src/input_stats.rs61
-rw-r--r--compiler/rustc_resolve/src/imports.rs18
-rw-r--r--compiler/rustc_session/Cargo.toml1
-rw-r--r--compiler/rustc_session/src/config.rs31
-rw-r--r--compiler/rustc_session/src/filesearch.rs18
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/session.rs16
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs24
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs18
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs20
-rw-r--r--library/alloc/src/ffi/c_str.rs109
-rw-r--r--library/core/src/ffi/c_str.rs14
-rw-r--r--library/core/src/iter/adapters/fuse.rs24
-rw-r--r--library/core/src/macros/mod.rs39
-rw-r--r--library/core/src/marker/variance.rs2
-rw-r--r--library/core/src/prelude/v1.rs3
-rw-r--r--library/core/src/str/mod.rs6
-rw-r--r--library/std/src/lib.rs6
-rw-r--r--library/std/src/net/tcp.rs6
-rw-r--r--library/std/src/os/unix/net/stream.rs23
-rw-r--r--library/std/src/prelude/v1.rs3
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs8
-rw-r--r--library/std/src/sys/random/uefi.rs169
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs1
-rw-r--r--src/bootstrap/src/utils/exec.rs5
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-1/Dockerfile2
-rwxr-xr-xsrc/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh20
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile1
-rw-r--r--src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md6
-rw-r--r--src/doc/unstable-book/src/library-features/concat-idents.md27
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/config.rs14
-rw-r--r--src/librustdoc/doctest.rs7
-rw-r--r--src/librustdoc/html/static/js/main.js30
-rw-r--r--src/librustdoc/json/conversions.rs29
-rw-r--r--src/tools/compiletest/src/errors.rs46
-rw-r--r--src/tools/compiletest/src/header.rs2
-rw-r--r--src/tools/compiletest/src/json.rs40
-rw-r--r--src/tools/compiletest/src/runtest.rs147
-rw-r--r--src/tools/run-make-support/src/lib.rs2
-rw-r--r--src/tools/run-make-support/src/targets.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs227
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs138
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/has_source.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs448
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs41
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs98
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs207
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs149
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs326
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs112
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs89
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs59
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs124
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/search.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs88
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs2
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs26
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs90
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs58
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs13
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs150
-rw-r--r--src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/variance.rs270
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs7
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs40
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs15
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md13
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json12
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts14
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-installer/install-template.sh8
-rw-r--r--src/tools/rustfmt/src/expr.rs2
-rw-r--r--src/tools/rustfmt/tests/source/pin_sugar.rs10
-rw-r--r--src/tools/rustfmt/tests/target/pin_sugar.rs7
-rw-r--r--src/tools/tidy/src/deps.rs3
-rw-r--r--src/tools/tidy/src/error_codes.rs32
-rw-r--r--src/tools/tidy/src/issues.txt2
-rw-r--r--src/tools/tidy/src/lib.rs61
-rw-r--r--src/tools/tidy/src/main.rs8
-rw-r--r--src/tools/tidy/src/rustdoc_json.rs48
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/auxiliary/minicore.rs7
-rw-r--r--tests/codegen/min-function-alignment.rs10
-rw-r--r--tests/crashes/132430.rs10
-rw-r--r--tests/crashes/138738.rs7
-rw-r--r--tests/incremental/issue-61323.rs2
-rw-r--r--tests/pretty/pin-ergonomics-hir.pp44
-rw-r--r--tests/pretty/pin-ergonomics-hir.rs40
-rw-r--r--tests/pretty/pin-ergonomics.rs13
-rw-r--r--tests/run-make/arm64ec-import-export-static/export.rs27
-rw-r--r--tests/run-make/arm64ec-import-export-static/import.rs12
-rw-r--r--tests/run-make/arm64ec-import-export-static/rmake.rs15
-rw-r--r--tests/run-make/c-link-to-rust-va-list-fn/rmake.rs1
-rw-r--r--tests/run-make/reproducible-build-2/rmake.rs36
-rw-r--r--tests/run-make/sanitizer-dylib-link/program.rs2
-rw-r--r--tests/rustdoc-js/big-result.rs1
-rw-r--r--tests/rustdoc-json/attrs/cold.rs3
-rw-r--r--tests/rustdoc-json/attrs/optimize.rs13
-rw-r--r--tests/rustdoc-json/generic-args.rs3
-rw-r--r--tests/ui-fulldeps/run-compiler-twice.rs6
-rw-r--r--tests/ui/abi/cannot-be-called.avr.stderr131
-rw-r--r--tests/ui/abi/cannot-be-called.i686.stderr127
-rw-r--r--tests/ui/abi/cannot-be-called.msp430.stderr131
-rw-r--r--tests/ui/abi/cannot-be-called.riscv32.stderr109
-rw-r--r--tests/ui/abi/cannot-be-called.riscv64.stderr109
-rw-r--r--tests/ui/abi/cannot-be-called.rs30
-rw-r--r--tests/ui/abi/cannot-be-called.x64.stderr127
-rw-r--r--tests/ui/abi/cannot-be-called.x64_win.stderr127
-rw-r--r--tests/ui/abi/unsupported-abi-transmute.rs15
-rw-r--r--tests/ui/abi/unsupported-abi-transmute.stderr9
-rw-r--r--tests/ui/abi/unsupported-varargs-fnptr.rs18
-rw-r--r--tests/ui/abi/unsupported-varargs-fnptr.stderr9
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr447
-rw-r--r--tests/ui/abi/unsupported.arm.stderr407
-rw-r--r--tests/ui/abi/unsupported.i686.stderr253
-rw-r--r--tests/ui/abi/unsupported.riscv32.stderr427
-rw-r--r--tests/ui/abi/unsupported.riscv64.stderr427
-rw-r--r--tests/ui/abi/unsupported.rs83
-rw-r--r--tests/ui/abi/unsupported.x64.stderr393
-rw-r--r--tests/ui/abi/unsupported.x64_win.stderr363
-rw-r--r--tests/ui/argument-suggestions/issue-100478.rs4
-rw-r--r--tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed2
-rw-r--r--tests/ui/async-await/incorrect-move-async-order-issue-79694.rs2
-rw-r--r--tests/ui/attributes/rustc_skip_during_method_dispatch.rs38
-rw-r--r--tests/ui/attributes/rustc_skip_during_method_dispatch.stderr76
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs4
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr23
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs4
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr12
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr6
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr6
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr6
-rw-r--r--tests/ui/compiletest-self-test/line-annotation-mismatches.rs42
-rw-r--r--tests/ui/compiletest-self-test/line-annotation-mismatches.stderr61
-rw-r--r--tests/ui/deprecation/deprecated_no_stack_check.rs2
-rw-r--r--tests/ui/deprecation/deprecated_no_stack_check.stderr4
-rw-r--r--tests/ui/derives/nonsense-input-to-debug.rs12
-rw-r--r--tests/ui/derives/nonsense-input-to-debug.stderr30
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr8
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr103
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr8
-rw-r--r--tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-cfi_encoding.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents.rs11
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents.stderr23
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents2.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents2.stderr20
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents3.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents3.stderr23
-rw-r--r--tests/ui/feature-gates/feature-gate-coverage-attribute.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-coverage-attribute.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.rs28
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr70
-rw-r--r--tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs2
-rw-r--r--tests/ui/feature-gates/gated-bad-feature.rs1
-rw-r--r--tests/ui/feature-gates/gated-bad-feature.stderr16
-rw-r--r--tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs2
-rw-r--r--tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr6
-rw-r--r--tests/ui/hygiene/no_implicit_prelude.stderr2
-rw-r--r--tests/ui/impl-header-lifetime-elision/assoc-type.rs2
-rw-r--r--tests/ui/impl-trait/in-bindings/lifetime-equality.rs19
-rw-r--r--tests/ui/impl-trait/in-bindings/region-lifetimes.rs17
-rw-r--r--tests/ui/imports/issue-28134.rs2
-rw-r--r--tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr (renamed from tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr)2
-rw-r--r--tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr8
-rw-r--r--tests/ui/imports/multiple-extern-by-macro-for-underscore.rs4
-rw-r--r--tests/ui/inference/hint-closure-signature-119266.rs2
-rw-r--r--tests/ui/integral-indexing.rs16
-rw-r--r--tests/ui/issues/issue-32950.rs10
-rw-r--r--tests/ui/issues/issue-32950.stderr15
-rw-r--r--tests/ui/issues/issue-50403.rs6
-rw-r--r--tests/ui/issues/issue-50403.stderr8
-rw-r--r--tests/ui/issues/issue-92741.rs6
-rw-r--r--tests/ui/lifetimes/no_lending_iterators.rs6
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs2
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr2
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.fixed44
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.rs44
-rw-r--r--tests/ui/lint/lint-non-uppercase-usages.stderr39
-rw-r--r--tests/ui/macros/macro-comma-support-rpass.rs12
-rw-r--r--tests/ui/macros/macro-match-nonterminal.rs3
-rw-r--r--tests/ui/macros/macro-match-nonterminal.stderr11
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/empty-input.rs12
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr19
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.rs9
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.stderr58
-rw-r--r--tests/ui/macros/macro-missing-fragment.rs1
-rw-r--r--tests/ui/macros/macro-missing-fragment.stderr12
-rw-r--r--tests/ui/macros/macro-reexport-removed.rs1
-rw-r--r--tests/ui/macros/macro-reexport-removed.stderr6
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.rs5
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.stderr68
-rw-r--r--tests/ui/macros/missing-writer-issue-139830.rs9
-rw-r--r--tests/ui/macros/missing-writer-issue-139830.stderr23
-rw-r--r--tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs8
-rw-r--r--tests/ui/parser/macro/issue-33569.rs3
-rw-r--r--tests/ui/parser/macro/issue-33569.stderr23
-rw-r--r--tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr238
-rw-r--r--tests/ui/pin-ergonomics/borrow-unpin.rs143
-rw-r--r--tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr136
-rw-r--r--tests/ui/pin-ergonomics/borrow.rs38
-rw-r--r--tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs (renamed from tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.rs)0
-rw-r--r--tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr (renamed from tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.stderr)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-arg.rs (renamed from tests/ui/async-await/pin-ergonomics/reborrow-arg.rs)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-const-as-mut.rs (renamed from tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.rs)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-const-as-mut.stderr (renamed from tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.stderr)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-once.rs (renamed from tests/ui/async-await/pin-ergonomics/reborrow-once.rs)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-once.stderr (renamed from tests/ui/async-await/pin-ergonomics/reborrow-once.stderr)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-self.rs (renamed from tests/ui/async-await/pin-ergonomics/reborrow-self.rs)0
-rw-r--r--tests/ui/pin-ergonomics/reborrow-shorter.rs (renamed from tests/ui/async-await/pin-ergonomics/reborrow-shorter.rs)0
-rw-r--r--tests/ui/pin-ergonomics/sugar-ambiguity.rs (renamed from tests/ui/async-await/pin-ergonomics/sugar-ambiguity.rs)0
-rw-r--r--tests/ui/pin-ergonomics/sugar-no-const.rs (renamed from tests/ui/async-await/pin-ergonomics/sugar-no-const.rs)0
-rw-r--r--tests/ui/pin-ergonomics/sugar-no-const.stderr (renamed from tests/ui/async-await/pin-ergonomics/sugar-no-const.stderr)0
-rw-r--r--tests/ui/pin-ergonomics/sugar-self.rs (renamed from tests/ui/async-await/pin-ergonomics/sugar-self.rs)0
-rw-r--r--tests/ui/pin-ergonomics/sugar.rs (renamed from tests/ui/async-await/pin-ergonomics/sugar.rs)0
-rw-r--r--tests/ui/rustdoc/renamed-features-rustdoc_internals.rs2
-rw-r--r--tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr8
-rw-r--r--tests/ui/sanitizer/cfi/invalid-attr-encoding.rs2
-rw-r--r--tests/ui/stats/input-stats.stderr196
-rw-r--r--tests/ui/suggestions/issue-105645.rs2
-rw-r--r--tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs2
-rw-r--r--tests/ui/syntax-extension-minor.rs15
-rw-r--r--tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs1
-rw-r--r--tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr6
-rw-r--r--tests/ui/type/option-ref-advice.rs4
-rw-r--r--tests/ui/typeck/issue-100246.rs2
-rw-r--r--tests/ui/typeck/issue-89275.rs2
-rw-r--r--tests/ui/underscore-imports/issue-110164.ed2015.stderr (renamed from tests/ui/underscore-imports/issue-110164.stderr)36
-rw-r--r--tests/ui/underscore-imports/issue-110164.ed2021.stderr39
-rw-r--r--tests/ui/underscore-imports/issue-110164.rs7
-rw-r--r--tests/ui/underscore-imports/multiple-uses.ed2015.stderr49
-rw-r--r--tests/ui/underscore-imports/multiple-uses.ed2021.stderr49
-rw-r--r--tests/ui/underscore-imports/multiple-uses.rs16
-rw-r--r--tests/ui/unpretty/exhaustive.expanded.stdout10
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stderr40
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stdout10
-rw-r--r--tests/ui/unpretty/exhaustive.rs11
-rw-r--r--tests/ui/unsized-locals/yote.rs2
-rw-r--r--tests/ui/unsized-locals/yote.stderr4
413 files changed, 7620 insertions, 5489 deletions
diff --git a/.mailmap b/.mailmap
index f55200c3fe9..2a53cbf9eff 100644
--- a/.mailmap
+++ b/.mailmap
@@ -162,8 +162,10 @@ David Carlier <devnexen@gmail.com>
 David Klein <david.klein@baesystemsdetica.com>
 David Manescu <david.manescu@gmail.com> <dman2626@uni.sydney.edu.au>
 David Ross <daboross@daboross.net>
-David Wood <david@davidtw.co> <david.wood@huawei.com>
+David Wood <david@davidtw.co> <Q0KPU0H1YOEPHRY1R2SN5B5RL@david.davidtw.co>
+David Wood <david@davidtw.co> <agile.lion3441@fuligin.ink>
 David Wood <david@davidtw.co> <david.wood2@arm.com>
+David Wood <david@davidtw.co> <david.wood@huawei.com>
 Deadbeef <ent3rm4n@gmail.com>
 Deadbeef <ent3rm4n@gmail.com> <fee1-dead-beef@protonmail.com>
 dependabot[bot] <dependabot[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
diff --git a/Cargo.lock b/Cargo.lock
index dfe1cd8852f..04b8c86b634 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3655,7 +3655,6 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
- "smallvec",
  "tracing",
  "unic-langid",
 ]
@@ -4447,7 +4446,6 @@ dependencies = [
  "rustc_serialize",
  "rustc_span",
  "rustc_target",
- "smallvec",
  "termize",
  "tracing",
  "windows",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 11afd359e5a..ab8dac16026 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -904,6 +904,10 @@ pub enum BorrowKind {
     /// The resulting type is either `*const T` or `*mut T`
     /// where `T = typeof($expr)`.
     Raw,
+    /// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
+    /// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
+    /// where `T = typeof($expr)` and `'a` is some lifetime.
+    Pin,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 54781e8235e..9b4535dcfbc 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -1085,6 +1085,7 @@ pub enum NtExprKind {
     Expr2021 { inferred: bool },
 }
 
+/// A macro nonterminal, known in documentation as a fragment specifier.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
 pub enum NonterminalKind {
     Item,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ef27d0ef69b..8acb5105773 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::def::{DefKind, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin};
@@ -1644,9 +1644,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
             self.error_on_invalid_abi(abi_str);
             ExternAbi::Rust
         });
-        let sess = self.tcx.sess;
-        let features = self.tcx.features();
-        gate_unstable_abi(sess, features, span, extern_abi);
+        let tcx = self.tcx;
+
+        // we can't do codegen for unsupported ABIs, so error now so we won't get farther
+        if !tcx.sess.target.is_abi_supported(extern_abi) {
+            let mut err = struct_span_code_err!(
+                tcx.dcx(),
+                span,
+                E0570,
+                "{extern_abi} is not a supported ABI for the current target",
+            );
+
+            if let ExternAbi::Stdcall { unwind } = extern_abi {
+                let c_abi = ExternAbi::C { unwind };
+                let system_abi = ExternAbi::System { unwind };
+                err.help(format!("if you need `extern {extern_abi}` on win32 and `extern {c_abi}` everywhere else, \
+                    use `extern {system_abi}`"
+                ));
+            }
+            err.emit();
+        }
+        // Show required feature gate even if we already errored, as the user is likely to build the code
+        // for the actually intended target next and then they will need the feature gate.
+        gate_unstable_abi(tcx.sess, tcx.features(), span, extern_abi);
         extern_abi
     }
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index f6b5ff404db..7651e8365a2 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -357,6 +357,10 @@ impl<'a> State<'a> {
                 self.word_nbsp("raw");
                 self.print_mutability(mutability, true);
             }
+            ast::BorrowKind::Pin => {
+                self.word_nbsp("pin");
+                self.print_mutability(mutability, true);
+            }
         }
         self.print_expr_cond_paren(
             expr,
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 4995b855f32..c4b377d80e2 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -265,6 +265,9 @@ pub enum AttributeKind {
     /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
     Repr(ThinVec<(ReprAttr, Span)>),
 
+    /// Represents `#[rustc_skip_during_method_dispatch]`.
+    SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
+
     /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
     Stability {
         stability: Stability,
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 24c40c301fe..0fa69c40154 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -50,8 +50,8 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
     const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if !args.no_args() {
-            cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
             return None;
         }
 
@@ -67,8 +67,8 @@ pub(crate) struct NakedParser {
 impl<S: Stage> AttributeParser<S> for NakedParser {
     const ATTRIBUTES: AcceptMapping<Self, S> =
         &[(&[sym::naked], template!(Word), |this, cx, args| {
-            if !args.no_args() {
-                cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
+            if let Err(span) = args.no_args() {
+                cx.expected_no_args(span);
                 return;
             }
 
@@ -175,10 +175,10 @@ impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
     const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if !args.no_args() {
-            cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
             return None;
-        };
+        }
 
         Some(AttributeKind::NoMangle(cx.attr_span))
     }
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 4cfd9a82ce8..1c8fc5079da 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -14,8 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(Word);
 
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
-        // FIXME: check that there's no args (this is currently checked elsewhere)
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
+        }
         Some(AttributeKind::AsPtr(cx.attr_span))
     }
 }
@@ -27,8 +29,10 @@ impl<S: Stage> SingleAttributeParser<S> for PubTransparentParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(Word);
 
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
-        // FIXME: check that there's no args (this is currently checked elsewhere)
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
+        }
         Some(AttributeKind::PubTransparent(cx.attr_span))
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index bc18ec8a9c0..d407669cb41 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -37,6 +37,7 @@ pub(crate) mod must_use;
 pub(crate) mod repr;
 pub(crate) mod semantics;
 pub(crate) mod stability;
+pub(crate) mod traits;
 pub(crate) mod transparency;
 pub(crate) mod util;
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
index 071574a5612..54f50445fbd 100644
--- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
@@ -13,7 +13,10 @@ impl<S: Stage> SingleAttributeParser<S> for MayDangleParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
     const TEMPLATE: AttributeTemplate = template!(Word);
 
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
+        }
         Some(AttributeKind::MayDangle(cx.attr_span))
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 6871ff4ec9f..37104855623 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -139,7 +139,10 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
     const TEMPLATE: AttributeTemplate = template!(Word);
 
-    fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
+        }
         Some(AttributeKind::ConstStabilityIndirect)
     }
 }
@@ -361,8 +364,8 @@ pub(crate) fn parse_unstability<S: Stage>(
                 };
             }
             Some(sym::soft) => {
-                if !param.args().no_args() {
-                    cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() });
+                if let Err(span) = args.no_args() {
+                    cx.emit_err(session_diagnostics::SoftNoArgs { span });
                 }
                 is_soft = true;
             }
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
new file mode 100644
index 00000000000..83a98c53c7f
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -0,0 +1,54 @@
+use core::mem;
+
+use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Symbol, sym};
+
+use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct SkipDuringMethodDispatchParser;
+
+impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
+    const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+
+    const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let mut array = false;
+        let mut boxed_slice = false;
+        let Some(args) = args.list() else {
+            cx.expected_list(cx.attr_span);
+            return None;
+        };
+        if args.is_empty() {
+            cx.expected_at_least_one_argument(args.span);
+            return None;
+        }
+        for arg in args.mixed() {
+            let Some(arg) = arg.meta_item() else {
+                cx.unexpected_literal(arg.span());
+                continue;
+            };
+            if let Err(span) = arg.args().no_args() {
+                cx.expected_no_args(span);
+            }
+            let path = arg.path();
+            let (key, skip): (Symbol, &mut bool) = match path.word_sym() {
+                Some(key @ sym::array) => (key, &mut array),
+                Some(key @ sym::boxed_slice) => (key, &mut boxed_slice),
+                _ => {
+                    cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]);
+                    continue;
+                }
+            };
+            if mem::replace(skip, true) {
+                cx.duplicate_key(arg.span(), key);
+            }
+        }
+        Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index c89ee8131bb..e0391065d53 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -27,6 +27,7 @@ use crate::attributes::semantics::MayDangleParser;
 use crate::attributes::stability::{
     BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
 };
+use crate::attributes::traits::SkipDuringMethodDispatchParser;
 use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single};
 use crate::parser::{ArgParser, MetaItemParser, PathParser};
@@ -122,6 +123,7 @@ attribute_parsers!(
         Single<OptimizeParser>,
         Single<PubTransparentParser>,
         Single<RustcForceInlineParser>,
+        Single<SkipDuringMethodDispatchParser>,
         Single<TransparencyParser>,
         // tidy-alphabetical-end
     ];
@@ -328,6 +330,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         })
     }
 
+    pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
+        })
+    }
+
     pub(crate) fn expected_specific_argument(
         &self,
         span: Span,
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index e02dc098127..aecaae947c9 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -169,9 +169,15 @@ impl<'a> ArgParser<'a> {
         }
     }
 
-    /// Asserts that there are no arguments
-    pub fn no_args(&self) -> bool {
-        matches!(self, Self::NoArgs)
+    /// Assert that there were no args.
+    /// If there were, get a span to the arguments
+    /// (to pass to [`AcceptContext::expected_no_args`](crate::context::AcceptContext::expected_no_args)).
+    pub fn no_args(&self) -> Result<(), Span> {
+        match self {
+            Self::NoArgs => Ok(()),
+            Self::List(args) => Err(args.span),
+            Self::NameValue(args) => Err(args.eq_span.to(args.value_span)),
+        }
     }
 }
 
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 808e452799d..263b323e3eb 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -496,6 +496,7 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
 pub(crate) enum AttributeParseErrorReason {
     ExpectedNoArgs,
     ExpectedStringLiteral { byte_string: Option<Span> },
+    ExpectedAtLeastOneArgument,
     ExpectedSingleArgument,
     ExpectedList,
     UnexpectedLiteral,
@@ -539,6 +540,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                 diag.span_label(self.span, "expected a single argument here");
                 diag.code(E0805);
             }
+            AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
+                diag.span_label(self.span, "expected at least 1 argument here");
+            }
             AttributeParseErrorReason::ExpectedList => {
                 diag.span_label(self.span, "expected this to be a list");
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 095c0df98ac..f9e52239d6f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -71,7 +71,6 @@ impl<'tcx> BorrowExplanation<'tcx> {
     ) {
         let tcx = cx.infcx.tcx;
         let body = cx.body;
-        let local_names = &cx.local_names;
 
         if let Some(span) = borrow_span {
             let def_id = body.source.def_id();
@@ -220,7 +219,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                     _ => ("destructor", format!("type `{}`", local_decl.ty)),
                 };
 
-                match local_names[dropped_local] {
+                match cx.local_name(dropped_local) {
                     Some(local_name) if !local_decl.from_compiler_desugaring() => {
                         let message = format!(
                             "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \
@@ -670,10 +669,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
 
             Some(Cause::DropVar(local, location)) => {
                 let mut should_note_order = false;
-                if self.local_names[local].is_some()
+                if self.local_name(local).is_some()
                     && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
                     && let Some(borrowed_local) = place.as_local()
-                    && self.local_names[borrowed_local].is_some()
+                    && self.local_name(borrowed_local).is_some()
                     && local != borrowed_local
                 {
                     should_note_order = true;
@@ -748,7 +747,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
                         Operand::Copy(place) | Operand::Move(place) => {
                             if let Some(l) = place.as_local() {
                                 let local_decl = &self.body.local_decls[l];
-                                if self.local_names[l].is_none() {
+                                if self.local_name(l).is_none() {
                                     local_decl.source_info.span
                                 } else {
                                     span
@@ -793,7 +792,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
                             Operand::Copy(place) | Operand::Move(place) => {
                                 if let Some(l) = place.as_local() {
                                     let local_decl = &self.body.local_decls[l];
-                                    if self.local_names[l].is_none() {
+                                    if self.local_name(l).is_none() {
                                         local_decl.source_info.span
                                     } else {
                                         span
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 5e3f3ffa2ea..7b4e38969ee 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -7,17 +7,17 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::{self as hir, CoroutineKind, LangItem};
-use rustc_index::IndexSlice;
+use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin};
 use rustc_infer::traits::SelectionError;
-use rustc_middle::bug;
 use rustc_middle::mir::{
     AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
     LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement,
-    StatementKind, Terminator, TerminatorKind, find_self_call,
+    StatementKind, Terminator, TerminatorKind, VarDebugInfoContents, find_self_call,
 };
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Spanned;
@@ -190,6 +190,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     ) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
         self.diags_buffer.buffered_move_errors.get(move_out_indices)
     }
+
+    /// Uses `body.var_debug_info` to find the symbol
+    fn local_name(&self, index: Local) -> Option<Symbol> {
+        *self.local_names().get(index)?
+    }
+
+    fn local_names(&self) -> &IndexSlice<Local, Option<Symbol>> {
+        self.local_names.get_or_init(|| {
+            let mut local_names = IndexVec::from_elem(None, &self.body.local_decls);
+            for var_debug_info in &self.body.var_debug_info {
+                if let VarDebugInfoContents::Place(place) = var_debug_info.value {
+                    if let Some(local) = place.as_local() {
+                        if let Some(prev_name) = local_names[local]
+                            && var_debug_info.name != prev_name
+                        {
+                            span_bug!(
+                                var_debug_info.source_info.span,
+                                "local {:?} has many names (`{}` vs `{}`)",
+                                local,
+                                prev_name,
+                                var_debug_info.name
+                            );
+                        }
+                        local_names[local] = Some(var_debug_info.name);
+                    }
+                }
+            }
+            local_names
+        })
+    }
 }
 
 impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
@@ -430,7 +460,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
     /// a name, or its name was generated by the compiler, then `Err` is returned
     fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
         let decl = &self.body.local_decls[local];
-        match self.local_names[local] {
+        match self.local_name(local) {
             Some(name) if !decl.from_compiler_desugaring() => {
                 buf.push_str(name.as_str());
                 Ok(())
@@ -1500,4 +1530,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             }
         }
     }
+
+    /// Skip over locals that begin with an underscore or have no name
+    pub(crate) fn local_excluded_from_unused_mut_lint(&self, index: Local) -> bool {
+        self.local_name(index).is_none_or(|name| name.as_str().starts_with('_'))
+    }
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 0394a42ea9c..b21d348183f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -465,11 +465,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         if let PlaceRef { local, projection: [] } = deref_base {
             let decl = &self.body.local_decls[local];
+            let local_name = self.local_name(local).map(|sym| format!("`{sym}`"));
             if decl.is_ref_for_guard() {
                 return self
                     .cannot_move_out_of(
                         span,
-                        &format!("`{}` in pattern guard", self.local_names[local].unwrap()),
+                        &format!(
+                            "{} in pattern guard",
+                            local_name.as_deref().unwrap_or("the place")
+                        ),
                     )
                     .with_note(
                         "variables bound in patterns cannot be moved from \
@@ -825,7 +829,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             }
 
             if binds_to.len() == 1 {
-                let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
+                let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`"));
 
                 if let Some(expr) = self.find_expr(binding_span) {
                     self.suggest_cloning(err, bind_to.ty, expr, None);
@@ -834,7 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                     is_partial_move: false,
                     ty: bind_to.ty,
-                    place: place_desc,
+                    place: place_desc.as_deref().unwrap_or("the place"),
                     span: binding_span,
                 });
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a5c9bad3ac2..fd8a2a6bc35 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -60,7 +60,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 if access_place.as_local().is_some() {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
-                    let name = self.local_names[local].expect("immutable unnamed local");
+                    let name = self.local_name(local).expect("immutable unnamed local");
                     reason = format!(", as `{name}` is not declared as mutable");
                 }
             }
@@ -285,7 +285,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     .body
                     .local_decls
                     .get(local)
-                    .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) =>
+                    .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) =>
             {
                 let decl = &self.body.local_decls[local];
                 err.span_label(span, format!("cannot {act}"));
@@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 let (pointer_sigil, pointer_desc) =
                     if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
 
-                match self.local_names[local] {
+                match self.local_name(local) {
                     Some(name) if !local_decl.from_compiler_desugaring() => {
                         err.span_label(
                             span,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 3bec07afa0f..d27e08573e0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -664,14 +664,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
             self.infcx.tcx,
             self.body,
-            &self.local_names,
+            &self.local_names(),
             &self.upvars,
             errci.fr,
         );
         let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region(
             self.infcx.tcx,
             self.body,
-            &self.local_names,
+            &self.local_names(),
             &self.upvars,
             errci.outlived_fr,
         );
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 487f78058a8..1ad629ad167 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -399,7 +399,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
             [implicit_inputs + argument_index];
         let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
             self.body,
-            &self.local_names,
+            self.local_names(),
             argument_index,
         );
 
@@ -973,7 +973,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
         {
             let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region(
                 self.body,
-                &self.local_names,
+                self.local_names(),
                 arg_index,
             );
             let region_name = self.synthesize_region_name();
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 4d85f109020..82b300dcb17 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -16,7 +16,7 @@
 // tidy-alphabetical-end
 
 use std::borrow::Cow;
-use std::cell::RefCell;
+use std::cell::{OnceCell, RefCell};
 use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref};
 
@@ -391,7 +391,7 @@ fn do_mir_borrowck<'tcx>(
             used_mut_upvars: SmallVec::new(),
             borrow_set: &borrow_set,
             upvars: &[],
-            local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
+            local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
             region_names: RefCell::default(),
             next_region_name: RefCell::new(1),
             polonius_output: None,
@@ -414,26 +414,6 @@ fn do_mir_borrowck<'tcx>(
         promoted_mbcx.report_move_errors();
     }
 
-    let mut local_names = IndexVec::from_elem(None, &body.local_decls);
-    for var_debug_info in &body.var_debug_info {
-        if let VarDebugInfoContents::Place(place) = var_debug_info.value {
-            if let Some(local) = place.as_local() {
-                if let Some(prev_name) = local_names[local]
-                    && var_debug_info.name != prev_name
-                {
-                    span_bug!(
-                        var_debug_info.source_info.span,
-                        "local {:?} has many names (`{}` vs `{}`)",
-                        local,
-                        prev_name,
-                        var_debug_info.name
-                    );
-                }
-                local_names[local] = Some(var_debug_info.name);
-            }
-        }
-    }
-
     let mut mbcx = MirBorrowckCtxt {
         root_cx,
         infcx: &infcx,
@@ -450,7 +430,7 @@ fn do_mir_borrowck<'tcx>(
         used_mut_upvars: SmallVec::new(),
         borrow_set: &borrow_set,
         upvars: tcx.closure_captures(def),
-        local_names,
+        local_names: OnceCell::new(),
         region_names: RefCell::default(),
         next_region_name: RefCell::new(1),
         move_errors: Vec::new(),
@@ -682,7 +662,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
     upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
 
     /// Names of local (user) variables (extracted from `var_debug_info`).
-    local_names: IndexVec<Local, Option<Symbol>>,
+    local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,
 
     /// Record the region names generated for each region in the given
     /// MIR def so that we can reuse them later in help/error messages.
@@ -2610,7 +2590,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             };
 
             // Skip over locals that begin with an underscore or have no name
-            if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) {
+            if self.local_excluded_from_unused_mut_lint(local) {
                 continue;
             }
 
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index c5d1f2ad2de..3594c7ec210 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -118,10 +118,6 @@ builtin_macros_concat_bytes_oob = numeric literal is out of bounds
 builtin_macros_concat_bytestr = cannot concatenate a byte string literal
 builtin_macros_concat_c_str_lit = cannot concatenate a C string literal
 
-builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
-
-builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
-builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
 builtin_macros_concat_missing_literal = expected a literal
     .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
 
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
deleted file mode 100644
index a721f5b84c5..00000000000
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_ast::{AttrVec, DUMMY_NODE_ID, Expr, ExprKind, Path, Ty, TyKind};
-use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
-use rustc_span::{Ident, Span, Symbol};
-
-use crate::errors;
-
-pub(crate) fn expand_concat_idents<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> MacroExpanderResult<'cx> {
-    if tts.is_empty() {
-        let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
-        return ExpandResult::Ready(DummyResult::any(sp, guar));
-    }
-
-    let mut res_str = String::new();
-    for (i, e) in tts.iter().enumerate() {
-        if i & 1 == 1 {
-            match e {
-                TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
-                _ => {
-                    let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
-                    return ExpandResult::Ready(DummyResult::any(sp, guar));
-                }
-            }
-        } else {
-            if let TokenTree::Token(token, _) = e {
-                if let Some((ident, _)) = token.ident() {
-                    res_str.push_str(ident.name.as_str());
-                    continue;
-                }
-            }
-
-            let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
-            return ExpandResult::Ready(DummyResult::any(sp, guar));
-        }
-    }
-
-    let ident = Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp));
-
-    struct ConcatIdentsResult {
-        ident: Ident,
-    }
-
-    impl MacResult for ConcatIdentsResult {
-        fn make_expr(self: Box<Self>) -> Option<P<Expr>> {
-            Some(P(Expr {
-                id: DUMMY_NODE_ID,
-                kind: ExprKind::Path(None, Path::from_ident(self.ident)),
-                span: self.ident.span,
-                attrs: AttrVec::new(),
-                tokens: None,
-            }))
-        }
-
-        fn make_ty(self: Box<Self>) -> Option<P<Ty>> {
-            Some(P(Ty {
-                id: DUMMY_NODE_ID,
-                kind: TyKind::Path(None, Path::from_ident(self.ident)),
-                span: self.ident.span,
-                tokens: None,
-            }))
-        }
-    }
-
-    ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
-}
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index b7ecfd2285c..fe34cf5d6fa 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -300,27 +300,6 @@ pub(crate) struct ConcatBytesBadRepeat {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_concat_idents_missing_args)]
-pub(crate) struct ConcatIdentsMissingArgs {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_concat_idents_missing_comma)]
-pub(crate) struct ConcatIdentsMissingComma {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_concat_idents_ident_args)]
-pub(crate) struct ConcatIdentsIdentArgs {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(builtin_macros_bad_derive_target, code = E0774)]
 pub(crate) struct BadDeriveTarget {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 9e7d0ec9e81..9b6dea21438 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -36,7 +36,6 @@ mod cfg_eval;
 mod compile_error;
 mod concat;
 mod concat_bytes;
-mod concat_idents;
 mod define_opaque;
 mod derive;
 mod deriving;
@@ -84,7 +83,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         compile_error: compile_error::expand_compile_error,
         concat: concat::expand_concat,
         concat_bytes: concat_bytes::expand_concat_bytes,
-        concat_idents: concat_idents::expand_concat_idents,
         const_format_args: format::expand_format_args,
         core_panic: edition_panic::expand_panic,
         env: env::expand_env,
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index a906bec8b7e..b893a2be9a2 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -43,42 +43,42 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-assembler-x64"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ff8e35182c7372df00447cb90a04e584e032c42b9b9b6e8c50ddaaf0d7900d5"
+checksum = "f6f53499803b1607b6ee0ba0de4ba036e6da700c2e489fe8f9d0f683d0b84d31"
 dependencies = [
  "cranelift-assembler-x64-meta",
 ]
 
 [[package]]
 name = "cranelift-assembler-x64-meta"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14220f9c2698015c3b94dc6b84ae045c1c45509ddc406e43c6139252757fdb7a"
+checksum = "1aadaa5bc8430d0e7bb999459369bedd0e5816ad4a82a0e20748341c4e333eda"
 dependencies = [
  "cranelift-srcgen",
 ]
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d372ef2777ceefd75829e1390211ac240e9196bc60699218f7ea2419038288ee"
+checksum = "2005fda2fc52a2dbce58229b4fb4483b70cbc806ba8ecc11b3f050c1a2d26cac"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-bitset"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56323783e423818fa89ce8078e90a3913d2a6e0810399bfce8ebd7ee87baa81f"
+checksum = "56935e02452ca1249d39ad5c45a96304d0b4300a158a391fd113451e0cd4483d"
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74ffb780aab6186c6e9ba26519654b1ac55a09c0a866f6088a4efbbd84da68ed"
+checksum = "62612786bf00e10999f50217d6f455d02b31591155881a45a903d1a95d1a4043"
 dependencies = [
  "bumpalo",
  "cranelift-assembler-x64",
@@ -97,13 +97,14 @@ dependencies = [
  "serde",
  "smallvec",
  "target-lexicon",
+ "wasmtime-math",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c23ef13814d3b39c869650d5961128cbbecad83fbdff4e6836a03ecf6862d7ed"
+checksum = "07bae789df91ef236079733af9df11d852256c64af196f0bc6471ea0f5f301be"
 dependencies = [
  "cranelift-assembler-x64-meta",
  "cranelift-codegen-shared",
@@ -112,33 +113,33 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9f623300657679f847803ce80811454bfff89cea4f6bf684be5c468d4a73631"
+checksum = "1be319616d36527782558a8312508757815f64deb19b094c7b8f4337229a9bc6"
 
 [[package]]
 name = "cranelift-control"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31f4168af69989aa6b91fab46799ed4df6096f3209f4a6c8fb4358f49c60188f"
+checksum = "8810ee1ab5e9bd5cff4c0c8d240e2009cb5c2b79888fde1d5256d605712314b7"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6fa9bae1c8de26d71ac2162f069447610fd91e7780cb480ee0d76ac81eabb8"
+checksum = "086452c97cfbe116bf17dbe622dc5fdf2ea97299c7d4ce42460f284387c9928a"
 dependencies = [
  "cranelift-bitset",
 ]
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8219205608aa0b0e6769b580284a7e055c7e0c323c1041cde7ca078add3e412"
+checksum = "4c27947010ab759330f252610c17a8cd64d123358be4f33164233d04fcd77b80"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -148,15 +149,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "588d0c5964f10860b04043e55aab26d7f7a206b0fd4f10c5260e8aa5773832bd"
+checksum = "ec67bfb8bd55b1e9760eb9f5186dca8d81bd4d86110f8d5af01154a044c91802"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56bd917ddc524f84f4066f954062875bdfc0dffea068ee94e906d98de5ac7c33"
+checksum = "d67cdfc447f2abdb46bb30a6582cce189539c3c051c1d5330692376e1400edff"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -174,9 +175,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68a03c057d8a992e06596c871341e446af43ff9224f941e5b8adea39137a5391"
+checksum = "e4597eaa52bca1ed111986c7a7f70cdbe192f83d271d627201365078e37b7e84"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -185,9 +186,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ed3c94cb97b14f92b6a94a1d45ef8c851f6a2ad9114e5d91d233f7da638fed"
+checksum = "75a9b63edea46e013fce459c46e500462cb03a0490fdd9c18fe42b1dd7b93aa1"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -196,9 +197,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a64dacef362a69375a604f6636e5e9a174fb96dba3b273646fcd9fa85c1d0997"
+checksum = "ce706f0166d5b7f31693dff521e87cb9858e12adf22ffcde93c4a2826f8f04a9"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -211,9 +212,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-srcgen"
-version = "0.120.0"
+version = "0.121.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85256fac1519a7d25a040c1d850fba67478f3f021ad5fdf738ba4425ee862dbf"
+checksum = "7d5870e266df8237b56cc98b04f5739c228565c92dd629ec6c66efa87271a158"
 
 [[package]]
 name = "crc32fast"
@@ -289,6 +290,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "libm"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
+
+[[package]]
 name = "log"
 version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -446,9 +453,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "33.0.0"
+version = "34.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "175e924dbc944c185808466d1e90b5a7feb610f3b9abdfe26f8ee25fd1086d1c"
+checksum = "2eedc0324e37cf39b049f4dca0c30997eaab49f09006d5f4c1994e64e7b7dba8"
 dependencies = [
  "anyhow",
  "cfg-if",
@@ -457,6 +464,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "wasmtime-math"
+version = "34.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cd35fae4cf51d2b4a9bd2ef04b0eb309fa1849cab6a6ab5ac27cbd054ea284d"
+dependencies = [
+ "libm",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 94fcbd0a502..9066e4dbbb5 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.120.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] }
-cranelift-frontend = { version = "0.120.0" }
-cranelift-module = { version = "0.120.0" }
-cranelift-native = { version = "0.120.0" }
-cranelift-jit = { version = "0.120.0", optional = true }
-cranelift-object = { version = "0.120.0" }
+cranelift-codegen = { version = "0.121.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] }
+cranelift-frontend = { version = "0.121.0" }
+cranelift-module = { version = "0.121.0" }
+cranelift-native = { version = "0.121.0" }
+cranelift-jit = { version = "0.121.0", optional = true }
+cranelift-object = { version = "0.121.0" }
 target-lexicon = "0.13"
 gimli = { version = "0.31", default-features = false, features = ["write"] }
 object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
@@ -24,12 +24,12 @@ smallvec = "1.8.1"
 
 [patch.crates-io]
 # Uncomment to use an unreleased version of cranelift
-#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" }
-#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" }
-#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" }
-#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" }
-#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" }
-#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" }
+#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" }
+#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" }
+#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" }
+#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" }
+#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" }
+#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" }
 
 # Uncomment to use local checkout of cranelift
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
index 674acfbd309..43025137bc6 100644
--- a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
@@ -6,8 +6,8 @@ use crate::{CodegenBackend, SysrootKind, build_sysroot};
 static ABI_CAFE_REPO: GitRepo = GitRepo::github(
     "Gankra",
     "abi-cafe",
-    "f1220cfd13b57f5c0082c26529163865ee25e115",
-    "fe93a9acd461425d",
+    "94d38030419eb00a1ba80e5e2b4d763dcee58db4",
+    "6efb4457893c8670",
     "abi-cafe",
 );
 
@@ -46,6 +46,10 @@ pub(crate) fn run(
     let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
     cmd.arg("--");
 
+    cmd.arg("--debug");
+
+    cmd.arg("--rules").arg(dirs.source_dir.join("scripts/abi-cafe-rules.toml"));
+
     // stdcall, vectorcall and such don't work yet
     cmd.arg("--conventions").arg("c").arg("--conventions").arg("rust");
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch b/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch
deleted file mode 100644
index 01b6a990b72..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0002-abi-cafe-Disable-broken-tests.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001
-From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
-Date: Tue, 9 Jul 2024 11:25:14 +0000
-Subject: [PATCH] Disable broken tests
-
----
- src/report.rs | 36 ++++++++++++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
-
-diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs
-index 0c50f7a..bfde2b1 100644
---- a/src/toolchains/rust.rs
-+++ b/src/toolchains/rust.rs
-@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain {
-             .arg(out_dir)
-             .arg("--target")
-             .arg(built_info::TARGET)
-+            .arg("-g")
-             .arg(format!("-Cmetadata={lib_name}"))
-             .arg(src_path);
-         if let Some(codegen_backend) = &self.codegen_backend {
-diff --git a/src/report.rs b/src/report.rs
-index 958ab43..dcf1044 100644
---- a/src/report.rs
-+++ b/src/report.rs
-@@ -48,6 +48,40 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc
-     //
-     // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
- 
-+    if cfg!(all(target_arch = "aarch64", target_os = "linux")) {
-+        if test.test == "F32Array" && test.options.convention == CallingConvention::C {
-+            result.check = Busted(Check);
-+        }
-+    }
-+
-+    if cfg!(all(target_arch = "aarch64", target_os = "macos")) {
-+        if test.test == "SingleVariantUnion" && test.options.convention == CallingConvention::C && test.options.repr == LangRepr::C {
-+            result.check = Busted(Check);
-+        }
-+
-+        if test.test == "OptionU128" && test.caller == "rustc" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
-+            result.check = Busted(Run);
-+        }
-+
-+        if test.test == "OptionU128" && test.caller == "cgclif" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C {
-+            result.check = Busted(Check);
-+        }
-+    }
-+
-+    if cfg!(all(target_arch = "x86_64", windows)) {
-+        if test.test == "simple" && test.options.convention == CallingConvention::Rust {
-+            result.check = Busted(Check);
-+        }
-+
-+        if test.test == "simple" && test.options.convention == CallingConvention::Rust && test.caller == "rustc" {
-+            result.check = Busted(Run);
-+        }
-+    }
-+
-+    if test.test == "f16" || test.test == "f128" {
-+        result.run = Skip;
-+    }
-+
-     // END OF VENDOR RESERVED AREA
-     //
-     //
--- 
-2.34.1
-
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index af4bd6dc6b8..150bb562f74 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2025-05-25"
+channel = "nightly-2025-06-24"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
 profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml b/compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml
new file mode 100644
index 00000000000..54f9445c8e5
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/scripts/abi-cafe-rules.toml
@@ -0,0 +1,17 @@
+[target.'cfg(all(target_arch = "aarch64", target_os = "linux"))']
+'F32Array::conv_c'.busted = "check"
+
+[target.'cfg(all(target_arch = "aarch64", target_os = "macos"))']
+'SingleVariantUnion::conv_c::repr_c'.busted = "check"
+'OptionU128::conv_rust::repr_c::rustc_caller'.busted = "run"
+'OptionU128::conv_rust::repr_c::cgclif_caller'.busted = "check"
+
+[target.'cfg(all(target_arch = "x86_64", windows))']
+'simple::conv_rust'.busted = "check"
+'simple::conv_rust::rustc_caller'.busted = "run"
+
+[target.'*'.'f16']
+run = "skip"
+
+[target.'*'.'f128']
+run = "skip"
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index c8527c3a57d..3a62cd52a9d 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -228,7 +228,7 @@ fn pointer_for_allocation<'tcx>(
     crate::pointer::Pointer::new(global_ptr)
 }
 
-pub(crate) fn data_id_for_alloc_id(
+fn data_id_for_alloc_id(
     cx: &mut ConstantCx,
     module: &mut dyn Module,
     alloc_id: AllocId,
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 615f6c47d90..37fbe4be1b0 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -202,9 +202,10 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             };
             let x = codegen_operand(fx, &x.node);
             let y = codegen_operand(fx, &y.node);
-            let kind = match &kind.node {
-                Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0,
-                Operand::Copy(_) | Operand::Move(_) => unreachable!("{kind:?}"),
+            let kind = if let Some(const_) = kind.node.constant() {
+                crate::constant::eval_mir_constant(fx, const_).0
+            } else {
+                unreachable!("{kind:?}")
             };
 
             let flt_cc = match kind
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 46a441488fa..68ff0b622c8 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -205,9 +205,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             // Find a way to reuse `immediate_const_vector` from `codegen_ssa` instead.
             let indexes = {
                 use rustc_middle::mir::interpret::*;
-                let idx_const = match &idx.node {
-                    Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0,
-                    Operand::Copy(_) | Operand::Move(_) => unreachable!("{idx:?}"),
+                let idx_const = if let Some(const_) = idx.node.constant() {
+                    crate::constant::eval_mir_constant(fx, const_).0
+                } else {
+                    unreachable!("{idx:?}")
                 };
 
                 let idx_bytes = match idx_const {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8882ba359b7..4a2425967e4 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -865,7 +865,7 @@ fn link_natively(
                     command: cmd,
                     escaped_output,
                     verbose: sess.opts.verbose,
-                    sysroot_dir: sess.sysroot.clone(),
+                    sysroot_dir: sess.opts.sysroot.path().to_owned(),
                 };
                 sess.dcx().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
@@ -1249,10 +1249,10 @@ fn link_sanitizer_runtime(
         if path.exists() {
             sess.target_tlib_path.dir.clone()
         } else {
-            let default_sysroot = filesearch::get_or_default_sysroot();
-            let default_tlib =
-                filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.tuple());
-            default_tlib
+            filesearch::make_target_lib_path(
+                &sess.opts.sysroot.default,
+                sess.opts.target_triple.tuple(),
+            )
         }
     }
 
@@ -1758,7 +1758,7 @@ fn detect_self_contained_mingw(sess: &Session, linker: &Path) -> bool {
     for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
         let full_path = dir.join(&linker_with_extension);
         // If linker comes from sysroot assume self-contained mode
-        if full_path.is_file() && !full_path.starts_with(&sess.sysroot) {
+        if full_path.is_file() && !full_path.starts_with(sess.opts.sysroot.path()) {
             return false;
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 8fc83908efb..cd08c0fc30f 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -337,7 +337,12 @@ pub(crate) trait Linker {
     fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    );
     fn subsystem(&mut self, subsystem: &str);
     fn linker_plugin_lto(&mut self);
     fn add_eh_frame_header(&mut self) {}
@@ -770,7 +775,12 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         // Symbol visibility in object files typically takes care of this.
         if crate_type == CrateType::Executable {
             let should_export_executable_symbols =
@@ -799,7 +809,7 @@ impl<'a> Linker for GccLinker<'a> {
             // Write a plain, newline-separated list of symbols
             let res: io::Result<()> = try {
                 let mut f = File::create_buffered(&path)?;
-                for sym in symbols {
+                for (sym, _) in symbols {
                     debug!("  _{sym}");
                     writeln!(f, "_{sym}")?;
                 }
@@ -814,11 +824,12 @@ impl<'a> Linker for GccLinker<'a> {
                 // .def file similar to MSVC one but without LIBRARY section
                 // because LD doesn't like when it's empty
                 writeln!(f, "EXPORTS")?;
-                for symbol in symbols {
+                for (symbol, kind) in symbols {
+                    let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
                     debug!("  _{symbol}");
                     // Quote the name in case it's reserved by linker in some way
                     // (this accounts for names with dots in particular).
-                    writeln!(f, "  \"{symbol}\"")?;
+                    writeln!(f, "  \"{symbol}\"{kind_marker}")?;
                 }
             };
             if let Err(error) = res {
@@ -831,7 +842,7 @@ impl<'a> Linker for GccLinker<'a> {
                 writeln!(f, "{{")?;
                 if !symbols.is_empty() {
                     writeln!(f, "  global:")?;
-                    for sym in symbols {
+                    for (sym, _) in symbols {
                         debug!("    {sym};");
                         writeln!(f, "    {sym};")?;
                     }
@@ -1059,7 +1070,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.link_arg("/PDBALTPATH:%_PDB%");
 
         // This will cause the Microsoft linker to embed .natvis info into the PDB file
-        let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
+        let natvis_dir_path = self.sess.opts.sysroot.path().join("lib\\rustlib\\etc");
         if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
             for entry in natvis_dir {
                 match entry {
@@ -1098,7 +1109,12 @@ impl<'a> Linker for MsvcLinker<'a> {
     // crates. Upstream rlibs may be linked statically to this dynamic library,
     // in which case they may continue to transitively be used and hence need
     // their symbols exported.
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         // Symbol visibility takes care of this typically
         if crate_type == CrateType::Executable {
             let should_export_executable_symbols =
@@ -1116,9 +1132,10 @@ impl<'a> Linker for MsvcLinker<'a> {
             // straight to exports.
             writeln!(f, "LIBRARY")?;
             writeln!(f, "EXPORTS")?;
-            for symbol in symbols {
+            for (symbol, kind) in symbols {
+                let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
                 debug!("  _{symbol}");
-                writeln!(f, "  {symbol}")?;
+                writeln!(f, "  {symbol}{kind_marker}")?;
             }
         };
         if let Err(error) = res {
@@ -1259,14 +1276,19 @@ impl<'a> Linker for EmLinker<'a> {
         self.cc_arg("-nodefaultlibs");
     }
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         debug!("EXPORTED SYMBOLS:");
 
         self.cc_arg("-s");
 
         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
         let encoded = serde_json::to_string(
-            &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
+            &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
         )
         .unwrap();
         debug!("{encoded}");
@@ -1428,8 +1450,13 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn no_default_libraries(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
-        for sym in symbols {
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
+        for (sym, _) in symbols {
             self.link_args(&["--export", sym]);
         }
 
@@ -1563,7 +1590,7 @@ impl<'a> Linker for L4Bender<'a> {
         self.cc_arg("-nostdlib");
     }
 
-    fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
+    fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
         // ToDo, not implemented, copy from GCC
         self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
     }
@@ -1720,12 +1747,17 @@ impl<'a> Linker for AixLinker<'a> {
 
     fn no_default_libraries(&mut self) {}
 
-    fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         let path = tmpdir.join("list.exp");
         let res: io::Result<()> = try {
             let mut f = File::create_buffered(&path)?;
             // FIXME: use llvm-nm to generate export list.
-            for symbol in symbols {
+            for (symbol, _) in symbols {
                 debug!("  _{symbol}");
                 writeln!(f, "  {symbol}")?;
             }
@@ -1769,9 +1801,23 @@ fn for_each_exported_symbols_include_dep<'tcx>(
     }
 }
 
-pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
+pub(crate) fn exported_symbols(
+    tcx: TyCtxt<'_>,
+    crate_type: CrateType,
+) -> Vec<(String, SymbolExportKind)> {
     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
-        return exports.iter().map(ToString::to_string).collect();
+        return exports
+            .iter()
+            .map(|name| {
+                (
+                    name.to_string(),
+                    // FIXME use the correct export kind for this symbol. override_export_symbols
+                    // can't directly specify the SymbolExportKind as it is defined in rustc_middle
+                    // which rustc_target can't depend on.
+                    SymbolExportKind::Text,
+                )
+            })
+            .collect();
     }
 
     if let CrateType::ProcMacro = crate_type {
@@ -1781,7 +1827,10 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
     }
 }
 
-fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
+fn exported_symbols_for_non_proc_macro(
+    tcx: TyCtxt<'_>,
+    crate_type: CrateType,
+) -> Vec<(String, SymbolExportKind)> {
     let mut symbols = Vec::new();
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
     for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
@@ -1789,8 +1838,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
         // from any cdylib. The latter doesn't work anyway as we use hidden visibility for
         // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
         if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
-            symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
-                tcx, symbol, cnum,
+            symbols.push((
+                symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+                info.kind,
             ));
             symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
         }
@@ -1799,7 +1849,7 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
     symbols
 }
 
-fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
+fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
     // `exported_symbols` will be empty when !should_codegen.
     if !tcx.sess.opts.output_types.should_codegen() {
         return Vec::new();
@@ -1809,7 +1859,10 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
     let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
     let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
 
-    vec![proc_macro_decls_name, metadata_symbol_name]
+    vec![
+        (proc_macro_decls_name, SymbolExportKind::Data),
+        (metadata_symbol_name, SymbolExportKind::Data),
+    ]
 }
 
 pub(crate) fn linked_symbols(
@@ -1831,7 +1884,9 @@ pub(crate) fn linked_symbols(
             || info.used
         {
             symbols.push((
-                symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+                symbol_export::linking_symbol_name_for_instance_in_crate(
+                    tcx, symbol, info.kind, cnum,
+                ),
                 info.kind,
             ));
         }
@@ -1906,7 +1961,13 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn ehcont_guard(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        _symbols: &[(String, SymbolExportKind)],
+    ) {
+    }
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
@@ -1975,10 +2036,15 @@ impl<'a> Linker for LlbcLinker<'a> {
 
     fn ehcont_guard(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         match _crate_type {
             CrateType::Cdylib => {
-                for sym in symbols {
+                for (sym, _) in symbols {
                     self.link_args(&["--export-symbol", sym]);
                 }
             }
@@ -2052,11 +2118,16 @@ impl<'a> Linker for BpfLinker<'a> {
 
     fn ehcont_guard(&mut self) {}
 
-    fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         let path = tmpdir.join("symbols");
         let res: io::Result<()> = try {
             let mut f = File::create_buffered(&path)?;
-            for sym in symbols {
+            for (sym, _) in symbols {
                 writeln!(f, "{sym}")?;
             }
         };
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index d0b6c7470fb..19c005d418e 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -680,6 +680,7 @@ fn calling_convention_for_symbol<'tcx>(
 pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
     tcx: TyCtxt<'tcx>,
     symbol: ExportedSymbol<'tcx>,
+    export_kind: SymbolExportKind,
     instantiating_crate: CrateNum,
 ) -> String {
     let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
@@ -700,8 +701,9 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
     let prefix = match &target.arch[..] {
         "x86" => Some('_'),
         "x86_64" => None,
-        "arm64ec" => Some('#'),
-        // Only x86/64 use symbol decorations.
+        // Only functions are decorated for arm64ec.
+        "arm64ec" if export_kind == SymbolExportKind::Text => Some('#'),
+        // Only x86/64 and arm64ec use symbol decorations.
         _ => return undecorated,
     };
 
@@ -741,7 +743,7 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
 /// Add it to the symbols list for all kernel functions, so that it is exported in the linked
 /// object.
 pub(crate) fn extend_exported_symbols<'tcx>(
-    symbols: &mut Vec<String>,
+    symbols: &mut Vec<(String, SymbolExportKind)>,
     tcx: TyCtxt<'tcx>,
     symbol: ExportedSymbol<'tcx>,
     instantiating_crate: CrateNum,
@@ -755,7 +757,9 @@ pub(crate) fn extend_exported_symbols<'tcx>(
     let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
 
     // Add the symbol for the kernel descriptor (with .kd suffix)
-    symbols.push(format!("{undecorated}.kd"));
+    // Per https://llvm.org/docs/AMDGPUUsage.html#symbols these will always be `STT_OBJECT` so
+    // export as data.
+    symbols.push((format!("{undecorated}.kd"), SymbolExportKind::Data));
 }
 
 fn maybe_emutls_symbol_name<'tcx>(
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index a3d6c73ba85..cc90271cd0c 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -12,9 +12,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
 use rustc_data_structures::unord::UnordMap;
-use rustc_hir::ItemId;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ItemId, Target};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
 use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
@@ -1003,21 +1003,35 @@ impl CrateInfo {
         // by the compiler, but that's ok because all this stuff is unstable anyway.
         let target = &tcx.sess.target;
         if !are_upstream_rust_objects_already_included(tcx.sess) {
-            let missing_weak_lang_items: FxIndexSet<Symbol> = info
+            let add_prefix = match (target.is_like_windows, target.arch.as_ref()) {
+                (true, "x86") => |name: String, _: SymbolExportKind| format!("_{name}"),
+                (true, "arm64ec") => {
+                    // Only functions are decorated for arm64ec.
+                    |name: String, export_kind: SymbolExportKind| match export_kind {
+                        SymbolExportKind::Text => format!("#{name}"),
+                        _ => name,
+                    }
+                }
+                _ => |name: String, _: SymbolExportKind| name,
+            };
+            let missing_weak_lang_items: FxIndexSet<(Symbol, SymbolExportKind)> = info
                 .used_crates
                 .iter()
                 .flat_map(|&cnum| tcx.missing_lang_items(cnum))
                 .filter(|l| l.is_weak())
                 .filter_map(|&l| {
                     let name = l.link_name()?;
-                    lang_items::required(tcx, l).then_some(name)
+                    let export_kind = match l.target() {
+                        Target::Fn => SymbolExportKind::Text,
+                        Target::Static => SymbolExportKind::Data,
+                        _ => bug!(
+                            "Don't know what the export kind is for lang item of kind {:?}",
+                            l.target()
+                        ),
+                    };
+                    lang_items::required(tcx, l).then_some((name, export_kind))
                 })
                 .collect();
-            let prefix = match (target.is_like_windows, target.arch.as_ref()) {
-                (true, "x86") => "_",
-                (true, "arm64ec") => "#",
-                _ => "",
-            };
 
             // This loop only adds new items to values of the hash map, so the order in which we
             // iterate over the values is not important.
@@ -1030,10 +1044,13 @@ impl CrateInfo {
                 .for_each(|(_, linked_symbols)| {
                     let mut symbols = missing_weak_lang_items
                         .iter()
-                        .map(|item| {
+                        .map(|(item, export_kind)| {
                             (
-                                format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())),
-                                SymbolExportKind::Text,
+                                add_prefix(
+                                    mangle_internal_symbol(tcx, item.as_str()),
+                                    *export_kind,
+                                ),
+                                *export_kind,
                             )
                         })
                         .collect::<Vec<_>>();
@@ -1048,12 +1065,12 @@ impl CrateInfo {
                         // errors.
                         linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
                             (
-                                format!(
-                                    "{prefix}{}",
+                                add_prefix(
                                     mangle_internal_symbol(
                                         tcx,
-                                        global_fn_name(method.name).as_str()
-                                    )
+                                        global_fn_name(method.name).as_str(),
+                                    ),
+                                    SymbolExportKind::Text,
                                 ),
                                 SymbolExportKind::Text,
                             )
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index fbcfcaa706c..f769b393528 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -146,12 +146,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             }
         }
 
-        // Apply the minimum function alignment here, so that individual backends don't have to.
-        codegen_fn_attrs.alignment = Ord::max(
-            codegen_fn_attrs.alignment,
-            tcx.sess.opts.unstable_opts.min_function_alignment,
-        );
-
         let Some(Ident { name, .. }) = attr.ident() else {
             continue;
         };
@@ -454,6 +448,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
     mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
 
+    // Apply the minimum function alignment here, so that individual backends don't have to.
+    codegen_fn_attrs.alignment =
+        Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);
+
     let inline_span;
     (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) =
         find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span))
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 523c9f2ad1c..23ed387a3ff 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -218,7 +218,7 @@ pub struct CrateInfo {
     pub target_cpu: String,
     pub target_features: Vec<String>,
     pub crate_types: Vec<CrateType>,
-    pub exported_symbols: UnordMap<CrateType, Vec<String>>,
+    pub exported_symbols: UnordMap<CrateType, Vec<(String, SymbolExportKind)>>,
     pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>,
     pub local_crate_name: Symbol,
     pub compiler_builtins: Option<CrateNum>,
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 887275e7294..f5b7a6066c8 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -600,11 +600,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(E0764),
             }),
-            hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
-                span,
-                kind: ccx.const_kind(),
-                teach: ccx.tcx.sess.teach(E0764),
-            }),
+            hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
+                ccx.dcx().create_err(errors::MutableRefEscaping {
+                    span,
+                    kind: ccx.const_kind(),
+                    teach: ccx.tcx.sess.teach(E0764),
+                })
+            }
         }
     }
 }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index daeca43169d..4855fc58d03 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -53,13 +53,13 @@ use rustc_metadata::locator;
 use rustc_middle::ty::TyCtxt;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::config::{
-    CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType,
+    CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, Sysroot,
     UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple,
 };
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::output::{CRATE_TYPES, collect_crate_types, invalid_output_for_target};
-use rustc_session::{EarlyDiagCtxt, Session, config, filesearch};
+use rustc_session::{EarlyDiagCtxt, Session, config};
 use rustc_span::FileName;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_target::json::ToJson;
@@ -662,7 +662,7 @@ fn print_crate_info(
                 println_info!("{}", targets.join("\n"));
             }
             HostTuple => println_info!("{}", rustc_session::config::host_tuple()),
-            Sysroot => println_info!("{}", sess.sysroot.display()),
+            Sysroot => println_info!("{}", sess.opts.sysroot.path().display()),
             TargetLibdir => println_info!("{}", sess.target_tlib_path.dir.display()),
             TargetSpecJson => {
                 println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
@@ -1114,8 +1114,8 @@ fn get_backend_from_raw_matches(
     let debug_flags = matches.opt_strs("Z");
     let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
     let target = parse_target_triple(early_dcx, matches);
-    let sysroot = filesearch::materialize_sysroot(matches.opt_str("sysroot").map(PathBuf::from));
-    let target = config::build_target_config(early_dcx, &target, &sysroot);
+    let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
+    let target = config::build_target_config(early_dcx, &target, sysroot.path());
 
     get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
 }
diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml
index 5dc582b9c3a..0951859fa53 100644
--- a/compiler/rustc_error_messages/Cargo.toml
+++ b/compiler/rustc_error_messages/Cargo.toml
@@ -16,7 +16,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 unic-langid = { version = "0.9.0", features = ["macros"] }
 # tidy-alphabetical-end
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 194fc2450ba..4e4345cfe0f 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -8,7 +8,7 @@
 
 use std::borrow::Cow;
 use std::error::Error;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::sync::{Arc, LazyLock};
 use std::{fmt, fs, io};
 
@@ -21,7 +21,6 @@ use intl_memoizer::concurrent::IntlLangMemoizer;
 use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
 use rustc_macros::{Decodable, Encodable};
 use rustc_span::Span;
-use smallvec::SmallVec;
 use tracing::{instrument, trace};
 pub use unic_langid::{LanguageIdentifier, langid};
 
@@ -107,7 +106,7 @@ impl From<Vec<FluentError>> for TranslationBundleError {
 /// (overriding any conflicting messages).
 #[instrument(level = "trace")]
 pub fn fluent_bundle(
-    sysroot_candidates: SmallVec<[PathBuf; 2]>,
+    sysroot_candidates: &[&Path],
     requested_locale: Option<LanguageIdentifier>,
     additional_ftl_path: Option<&Path>,
     with_directionality_markers: bool,
@@ -141,7 +140,8 @@ pub fn fluent_bundle(
     // If the user requests the default locale then don't try to load anything.
     if let Some(requested_locale) = requested_locale {
         let mut found_resources = false;
-        for mut sysroot in sysroot_candidates {
+        for sysroot in sysroot_candidates {
+            let mut sysroot = sysroot.to_path_buf();
             sysroot.push("share");
             sysroot.push("locale");
             sysroot.push(requested_locale.to_string());
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 6d600f896a0..4348610be0a 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -129,6 +129,7 @@ impl Emitter for JsonEmitter {
         };
         let name = match record.section {
             TimingSection::Linking => "link",
+            TimingSection::Codegen => "codegen",
         };
         let data = SectionTimestamp { name, event, timestamp: record.timestamp };
         let result = self.emit(EmitTyped::SectionTiming(data));
diff --git a/compiler/rustc_errors/src/timings.rs b/compiler/rustc_errors/src/timings.rs
index 27fc9df8d79..0d82f3e8db8 100644
--- a/compiler/rustc_errors/src/timings.rs
+++ b/compiler/rustc_errors/src/timings.rs
@@ -1,10 +1,15 @@
 use std::time::Instant;
 
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lock;
+
 use crate::DiagCtxtHandle;
 
 /// A high-level section of the compilation process.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum TimingSection {
+    /// Time spent doing codegen.
+    Codegen,
     /// Time spent linking.
     Linking,
 }
@@ -36,23 +41,59 @@ pub struct TimingSectionHandler {
     /// Time when the compilation session started.
     /// If `None`, timing is disabled.
     origin: Option<Instant>,
+    /// Sanity check to ensure that we open and close sections correctly.
+    opened_sections: Lock<FxHashSet<TimingSection>>,
 }
 
 impl TimingSectionHandler {
     pub fn new(enabled: bool) -> Self {
         let origin = if enabled { Some(Instant::now()) } else { None };
-        Self { origin }
+        Self { origin, opened_sections: Lock::new(FxHashSet::default()) }
     }
 
     /// Returns a RAII guard that will immediately emit a start the provided section, and then emit
     /// its end when it is dropped.
-    pub fn start_section<'a>(
+    pub fn section_guard<'a>(
         &self,
         diag_ctxt: DiagCtxtHandle<'a>,
         section: TimingSection,
     ) -> TimingSectionGuard<'a> {
+        if self.is_enabled() && self.opened_sections.borrow().contains(&section) {
+            diag_ctxt
+                .bug(format!("Section `{section:?}` was started again before it was finished"));
+        }
+
         TimingSectionGuard::create(diag_ctxt, section, self.origin)
     }
+
+    /// Start the provided section.
+    pub fn start_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) {
+        if let Some(origin) = self.origin {
+            let mut opened = self.opened_sections.borrow_mut();
+            if !opened.insert(section) {
+                diag_ctxt
+                    .bug(format!("Section `{section:?}` was started again before it was finished"));
+            }
+
+            diag_ctxt.emit_timing_section_start(TimingRecord::from_origin(origin, section));
+        }
+    }
+
+    /// End the provided section.
+    pub fn end_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) {
+        if let Some(origin) = self.origin {
+            let mut opened = self.opened_sections.borrow_mut();
+            if !opened.remove(&section) {
+                diag_ctxt.bug(format!("Section `{section:?}` was ended before being started"));
+            }
+
+            diag_ctxt.emit_timing_section_end(TimingRecord::from_origin(origin, section));
+        }
+    }
+
+    fn is_enabled(&self) -> bool {
+        self.origin.is_some()
+    }
 }
 
 /// RAII wrapper for starting and ending section timings.
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 8b7c47dad99..b7555bba28e 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -62,7 +62,7 @@ expand_feature_not_allowed =
 expand_feature_removed =
     feature has been removed
     .label = feature has been removed
-    .note = removed in {$removed_rustc_version} (you are using {$current_rustc_version}){$pull_note}
+    .note = removed in {$removed_rustc_version}{$pull_note}
     .reason = {$reason}
 
 expand_glob_delegation_outside_impls =
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 9a359e9b031..170ac39d1ec 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -92,7 +92,6 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
                     span: mi.span(),
                     reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
                     removed_rustc_version: f.feature.since,
-                    current_rustc_version: sess.cfg_version,
                     pull_note,
                 });
                 continue;
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 714ba3bf0f4..fe4d2af97a0 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -162,7 +162,6 @@ pub(crate) struct FeatureRemoved<'a> {
     #[subdiagnostic]
     pub reason: Option<FeatureRemovedReason<'a>>,
     pub removed_rustc_version: &'a str,
-    pub current_rustc_version: &'a str,
     pub pull_note: String,
 }
 
@@ -444,7 +443,7 @@ pub(crate) struct InvalidFragmentSpecifier {
     #[primary_span]
     pub span: Span,
     pub fragment: Ident,
-    pub help: String,
+    pub help: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs
index 4ff8c02bcdb..3082c881a7a 100644
--- a/compiler/rustc_expand/src/mbe.rs
+++ b/compiler/rustc_expand/src/mbe.rs
@@ -78,7 +78,13 @@ enum TokenTree {
     /// only covers the ident, e.g. `var`.)
     MetaVar(Span, Ident),
     /// e.g., `$var:expr`. Only appears on the LHS.
-    MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
+    MetaVarDecl {
+        span: Span,
+        /// Name to bind.
+        name: Ident,
+        /// The fragment specifier.
+        kind: NonterminalKind,
+    },
     /// A meta-variable expression inside `${...}`.
     MetaVarExpr(DelimSpan, MetaVarExpr),
 }
@@ -102,7 +108,7 @@ impl TokenTree {
         match *self {
             TokenTree::Token(Token { span, .. })
             | TokenTree::MetaVar(span, _)
-            | TokenTree::MetaVarDecl(span, _, _) => span,
+            | TokenTree::MetaVarDecl { span, .. } => span,
             TokenTree::Delimited(span, ..)
             | TokenTree::MetaVarExpr(span, _)
             | TokenTree::Sequence(span, _) => span.entire(),
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 698492f42e2..99aa376626d 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -24,6 +24,7 @@ pub(super) fn failed_to_match_macro(
     arg: TokenStream,
     lhses: &[Vec<MatcherLoc>],
 ) -> (Span, ErrorGuaranteed) {
+    debug!("failed to match macro");
     // An error occurred, try the expansion again, tracking the expansion closely for better
     // diagnostics.
     let mut tracker = CollectTrackerAndEmitter::new(psess.dcx(), sp);
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 3cd803c3e84..dc2d46c4a14 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -117,7 +117,6 @@ use rustc_session::parse::ParseSess;
 use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
 use smallvec::SmallVec;
 
-use super::quoted::VALID_FRAGMENT_NAMES_MSG;
 use crate::errors;
 use crate::mbe::{KleeneToken, TokenTree};
 
@@ -263,14 +262,7 @@ fn check_binders(
             }
         }
         // Similarly, this can only happen when checking a toplevel macro.
-        TokenTree::MetaVarDecl(span, name, kind) => {
-            if kind.is_none() && node_id != DUMMY_NODE_ID {
-                psess.dcx().emit_err(errors::MissingFragmentSpecifier {
-                    span,
-                    add_span: span.shrink_to_hi(),
-                    valid: VALID_FRAGMENT_NAMES_MSG,
-                });
-            }
+        TokenTree::MetaVarDecl { span, name, .. } => {
             if !macros.is_empty() {
                 psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");
             }
@@ -339,7 +331,7 @@ fn check_occurrences(
 ) {
     match *rhs {
         TokenTree::Token(..) => {}
-        TokenTree::MetaVarDecl(span, _name, _kind) => {
+        TokenTree::MetaVarDecl { span, .. } => {
             psess.dcx().span_bug(span, "unexpected MetaVarDecl in rhs")
         }
         TokenTree::MetaVar(span, name) => {
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index c78beb40688..802e43209a5 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -122,7 +122,7 @@ pub(crate) enum MatcherLoc {
     MetaVarDecl {
         span: Span,
         bind: Ident,
-        kind: Option<NonterminalKind>,
+        kind: NonterminalKind,
         next_metavar: usize,
         seq_depth: usize,
     },
@@ -151,12 +151,7 @@ impl Display for MatcherLoc {
                 write!(f, "{}", token_descr(token))
             }
             MatcherLoc::MetaVarDecl { bind, kind, .. } => {
-                write!(f, "meta-variable `${bind}")?;
-                if let Some(kind) = kind {
-                    write!(f, ":{kind}")?;
-                }
-                write!(f, "`")?;
-                Ok(())
+                write!(f, "meta-variable `${bind}:{kind}`")
             }
             MatcherLoc::Eof => f.write_str("end of macro"),
 
@@ -220,7 +215,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
                         seq_depth,
                     };
                 }
-                &TokenTree::MetaVarDecl(span, bind, kind) => {
+                &TokenTree::MetaVarDecl { span, name: bind, kind } => {
                     locs.push(MatcherLoc::MetaVarDecl {
                         span,
                         bind,
@@ -330,7 +325,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
     matcher
         .iter()
         .map(|tt| match tt {
-            TokenTree::MetaVarDecl(..) => 1,
+            TokenTree::MetaVarDecl { .. } => 1,
             TokenTree::Sequence(_, seq) => seq.num_captures,
             TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts),
             TokenTree::Token(..) => 0,
@@ -551,18 +546,12 @@ impl TtParser {
                     mp.idx = idx_first;
                     self.cur_mps.push(mp);
                 }
-                &MatcherLoc::MetaVarDecl { span, kind, .. } => {
+                &MatcherLoc::MetaVarDecl { kind, .. } => {
                     // Built-in nonterminals never start with these tokens, so we can eliminate
                     // them from consideration. We use the span of the metavariable declaration
                     // to determine any edition-specific matching behavior for non-terminals.
-                    if let Some(kind) = kind {
-                        if Parser::nonterminal_may_begin_with(kind, token) {
-                            self.bb_mps.push(mp);
-                        }
-                    } else {
-                        // E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
-                        // Both this check and the one in `nameize` are necessary, surprisingly.
-                        return Some(Error(span, "missing fragment specifier".to_string()));
+                    if Parser::nonterminal_may_begin_with(kind, token) {
+                        self.bb_mps.push(mp);
                     }
                 }
                 MatcherLoc::Eof => {
@@ -666,11 +655,7 @@ impl TtParser {
                     let mut mp = self.bb_mps.pop().unwrap();
                     let loc = &matcher[mp.idx];
                     if let &MatcherLoc::MetaVarDecl {
-                        span,
-                        kind: Some(kind),
-                        next_metavar,
-                        seq_depth,
-                        ..
+                        span, kind, next_metavar, seq_depth, ..
                     } = loc
                     {
                         // We use the span of the metavariable declaration to determine any
@@ -715,7 +700,7 @@ impl TtParser {
             .bb_mps
             .iter()
             .map(|mp| match &matcher[mp.idx] {
-                MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
+                MatcherLoc::MetaVarDecl { bind, kind, .. } => {
                     format!("{kind} ('{bind}')")
                 }
                 _ => unreachable!(),
@@ -745,19 +730,13 @@ impl TtParser {
         // `NamedParseResult`. Otherwise, it's an error.
         let mut ret_val = FxHashMap::default();
         for loc in matcher {
-            if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc {
-                if kind.is_some() {
-                    match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
-                        Vacant(spot) => spot.insert(res.next().unwrap()),
-                        Occupied(..) => {
-                            return Error(span, format!("duplicated bind name: {bind}"));
-                        }
-                    };
-                } else {
-                    // E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
-                    // Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
-                    return Error(span, "missing fragment specifier".to_string());
-                }
+            if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc {
+                match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
+                    Vacant(spot) => spot.insert(res.next().unwrap()),
+                    Occupied(..) => {
+                        return Error(span, format!("duplicated bind name: {bind}"));
+                    }
+                };
             }
         }
         Success(ret_val)
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 783f061ec6c..432ab324740 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -392,7 +392,7 @@ pub fn compile_declarative_macro(
 
     let lhs_nm = Ident::new(sym::lhs, span);
     let rhs_nm = Ident::new(sym::rhs, span);
-    let tt_spec = Some(NonterminalKind::TT);
+    let tt_spec = NonterminalKind::TT;
     let macro_rules = macro_def.macro_rules;
 
     // Parse the macro_rules! invocation
@@ -407,9 +407,9 @@ pub fn compile_declarative_macro(
             DelimSpan::dummy(),
             mbe::SequenceRepetition {
                 tts: vec![
-                    mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec),
+                    mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec },
                     mbe::TokenTree::token(token::FatArrow, span),
-                    mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec),
+                    mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec },
                 ],
                 separator: Some(Token::new(
                     if macro_rules { token::Semi } else { token::Comma },
@@ -448,6 +448,7 @@ pub fn compile_declarative_macro(
         match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
             Success(m) => m,
             Failure(()) => {
+                debug!("failed to parse macro tt");
                 // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it
                 // with another one that gives us the information we need.
                 // For this we need to reclone the macro body as the previous parser consumed it.
@@ -616,7 +617,7 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
         let mut iter = seq.tts.iter().peekable();
         while let Some(tt) = iter.next() {
             match tt {
-                mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
+                mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. } => {}
                 mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
                     let mut now = t;
                     while let Some(&mbe::TokenTree::Token(
@@ -651,7 +652,7 @@ fn check_redundant_vis_repetition(
 ) {
     let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
     let is_vis = seq.tts.first().map_or(false, |tt| {
-        matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
+        matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
     });
 
     if is_vis && is_zero_or_one {
@@ -678,7 +679,7 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
         match tt {
             TokenTree::Token(..)
             | TokenTree::MetaVar(..)
-            | TokenTree::MetaVarDecl(..)
+            | TokenTree::MetaVarDecl { .. }
             | TokenTree::MetaVarExpr(..) => (),
             TokenTree::Delimited(.., del) => check_lhs_no_empty_seq(sess, &del.tts)?,
             TokenTree::Sequence(span, seq) => {
@@ -777,7 +778,7 @@ impl<'tt> FirstSets<'tt> {
                 match tt {
                     TokenTree::Token(..)
                     | TokenTree::MetaVar(..)
-                    | TokenTree::MetaVarDecl(..)
+                    | TokenTree::MetaVarDecl { .. }
                     | TokenTree::MetaVarExpr(..) => {
                         first.replace_with(TtHandle::TtRef(tt));
                     }
@@ -845,7 +846,7 @@ impl<'tt> FirstSets<'tt> {
             match tt {
                 TokenTree::Token(..)
                 | TokenTree::MetaVar(..)
-                | TokenTree::MetaVarDecl(..)
+                | TokenTree::MetaVarDecl { .. }
                 | TokenTree::MetaVarExpr(..) => {
                     first.add_one(TtHandle::TtRef(tt));
                     return first;
@@ -1084,7 +1085,7 @@ fn check_matcher_core<'tt>(
         match token {
             TokenTree::Token(..)
             | TokenTree::MetaVar(..)
-            | TokenTree::MetaVarDecl(..)
+            | TokenTree::MetaVarDecl { .. }
             | TokenTree::MetaVarExpr(..) => {
                 if token_can_be_followed_by_any(token) {
                     // don't need to track tokens that work with any,
@@ -1152,7 +1153,7 @@ fn check_matcher_core<'tt>(
         // Now `last` holds the complete set of NT tokens that could
         // end the sequence before SUFFIX. Check that every one works with `suffix`.
         for tt in &last.tokens {
-            if let &TokenTree::MetaVarDecl(span, name, Some(kind)) = tt.get() {
+            if let &TokenTree::MetaVarDecl { span, name, kind } = tt.get() {
                 for next_token in &suffix_first.tokens {
                     let next_token = next_token.get();
 
@@ -1172,11 +1173,11 @@ fn check_matcher_core<'tt>(
                         )
                     {
                         // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
-                        let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
+                        let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl {
                             span,
                             name,
-                            Some(NonterminalKind::Pat(PatParam { inferred: false })),
-                        ));
+                            kind: NonterminalKind::Pat(PatParam { inferred: false }),
+                        });
                         sess.psess.buffer_lint(
                             RUST_2021_INCOMPATIBLE_OR_PATTERNS,
                             span,
@@ -1212,11 +1213,11 @@ fn check_matcher_core<'tt>(
                                 && sess.psess.edition.at_least_rust_2021()
                                 && next_token.is_token(&token::Or)
                             {
-                                let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
+                                let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl {
                                     span,
                                     name,
-                                    Some(NonterminalKind::Pat(PatParam { inferred: false })),
-                                ));
+                                    kind: NonterminalKind::Pat(PatParam { inferred: false }),
+                                });
                                 err.span_suggestion(
                                     span,
                                     "try a `pat_param` fragment specifier instead",
@@ -1254,7 +1255,7 @@ fn check_matcher_core<'tt>(
 }
 
 fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
-    if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
+    if let mbe::TokenTree::MetaVarDecl { kind, .. } = *tok {
         frag_can_be_followed_by_any(kind)
     } else {
         // (Non NT's can always be followed by anything in matchers.)
@@ -1367,7 +1368,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                         }
                         _ => IsInFollow::No(TOKENS),
                     },
-                    TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
+                    TokenTree::MetaVarDecl { kind: NonterminalKind::Block, .. } => IsInFollow::Yes,
                     _ => IsInFollow::No(TOKENS),
                 }
             }
@@ -1400,11 +1401,10 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                             }
                         }
                     },
-                    TokenTree::MetaVarDecl(
-                        _,
-                        _,
-                        Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
-                    ) => IsInFollow::Yes,
+                    TokenTree::MetaVarDecl {
+                        kind: NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path,
+                        ..
+                    } => IsInFollow::Yes,
                     _ => IsInFollow::No(TOKENS),
                 }
             }
@@ -1416,8 +1416,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     match tt {
         mbe::TokenTree::Token(token) => pprust::token_to_string(token).into(),
         mbe::TokenTree::MetaVar(_, name) => format!("${name}"),
-        mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"),
-        mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"),
+        mbe::TokenTree::MetaVarDecl { name, kind, .. } => format!("${name}:{kind}"),
         _ => panic!(
             "{}",
             "unexpected mbe::TokenTree::{Sequence or Delimited} \
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 0c2362f23bc..2daa4e71558 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -54,66 +54,78 @@ pub(super) fn parse(
         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
         let tree = parse_tree(tree, &mut iter, parsing_patterns, sess, node_id, features, edition);
-        match tree {
-            TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
-                // Not consuming the next token immediately, as it may not be a colon
-                let span = match iter.peek() {
-                    Some(&tokenstream::TokenTree::Token(
-                        Token { kind: token::Colon, span: colon_span },
-                        _,
-                    )) => {
-                        // Consume the colon first
-                        iter.next();
-
-                        // It's ok to consume the next tree no matter how,
-                        // since if it's not a token then it will be an invalid declaration.
-                        match iter.next() {
-                            Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
-                                Some((fragment, _)) => {
-                                    let span = token.span.with_lo(start_sp.lo());
-                                    let edition = || {
-                                        // FIXME(#85708) - once we properly decode a foreign
-                                        // crate's `SyntaxContext::root`, then we can replace
-                                        // this with just `span.edition()`. A
-                                        // `SyntaxContext::root()` from the current crate will
-                                        // have the edition of the current crate, and a
-                                        // `SyntaxContext::root()` from a foreign crate will
-                                        // have the edition of that crate (which we manually
-                                        // retrieve via the `edition` parameter).
-                                        if !span.from_expansion() {
-                                            edition
-                                        } else {
-                                            span.edition()
-                                        }
-                                    };
-                                    let kind = NonterminalKind::from_symbol(fragment.name, edition)
-                                        .unwrap_or_else(|| {
-                                            sess.dcx().emit_err(errors::InvalidFragmentSpecifier {
-                                                span,
-                                                fragment,
-                                                help: VALID_FRAGMENT_NAMES_MSG.into(),
-                                            });
-                                            NonterminalKind::Ident
-                                        });
-                                    result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
-                                    continue;
-                                }
-                                _ => token.span,
-                            },
-                            // Invalid, return a nice source location
-                            _ => colon_span.with_lo(start_sp.lo()),
-                        }
-                    }
-                    // Whether it's none or some other tree, it doesn't belong to
-                    // the current meta variable, returning the original span.
-                    _ => start_sp,
-                };
 
-                result.push(TokenTree::MetaVarDecl(span, ident, None));
-            }
+        if !parsing_patterns {
+            // No matchers allowed, nothing to process here
+            result.push(tree);
+            continue;
+        }
+
+        let TokenTree::MetaVar(start_sp, ident) = tree else {
+            // Not a metavariable, just return the tree
+            result.push(tree);
+            continue;
+        };
 
-            // Not a metavar or no matchers allowed, so just return the tree
-            _ => result.push(tree),
+        // Push a metavariable with no fragment specifier at the given span
+        let mut missing_fragment_specifier = |span| {
+            sess.dcx().emit_err(errors::MissingFragmentSpecifier {
+                span,
+                add_span: span.shrink_to_hi(),
+                valid: VALID_FRAGMENT_NAMES_MSG,
+            });
+
+            // Fall back to a `TokenTree` since that will match anything if we continue expanding.
+            result.push(TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT });
+        };
+
+        // Not consuming the next token immediately, as it may not be a colon
+        if let Some(peek) = iter.peek()
+            && let tokenstream::TokenTree::Token(token, _spacing) = peek
+            && let Token { kind: token::Colon, span: colon_span } = token
+        {
+            // Next token is a colon; consume it
+            iter.next();
+
+            // It's ok to consume the next tree no matter how,
+            // since if it's not a token then it will be an invalid declaration.
+            let Some(tokenstream::TokenTree::Token(token, _)) = iter.next() else {
+                // Invalid, return a nice source location as `var:`
+                missing_fragment_specifier(colon_span.with_lo(start_sp.lo()));
+                continue;
+            };
+
+            let Some((fragment, _)) = token.ident() else {
+                // No identifier for the fragment specifier;
+                missing_fragment_specifier(token.span);
+                continue;
+            };
+
+            let span = token.span.with_lo(start_sp.lo());
+            let edition = || {
+                // FIXME(#85708) - once we properly decode a foreign
+                // crate's `SyntaxContext::root`, then we can replace
+                // this with just `span.edition()`. A
+                // `SyntaxContext::root()` from the current crate will
+                // have the edition of the current crate, and a
+                // `SyntaxContext::root()` from a foreign crate will
+                // have the edition of that crate (which we manually
+                // retrieve via the `edition` parameter).
+                if !span.from_expansion() { edition } else { span.edition() }
+            };
+            let kind = NonterminalKind::from_symbol(fragment.name, edition).unwrap_or_else(|| {
+                sess.dcx().emit_err(errors::InvalidFragmentSpecifier {
+                    span,
+                    fragment,
+                    help: VALID_FRAGMENT_NAMES_MSG,
+                });
+                NonterminalKind::TT
+            });
+            result.push(TokenTree::MetaVarDecl { span, name: ident, kind });
+        } else {
+            // Whether it's none or some other tree, it doesn't belong to
+            // the current meta variable, returning the original span.
+            missing_fragment_specifier(start_sp);
         }
     }
     result
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 0520be5fbae..a8c4a9e4b1b 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -283,7 +283,7 @@ pub(super) fn transcribe<'a>(
             }
 
             // There should be no meta-var declarations in the invocation of a macro.
-            mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl`"),
+            mbe::TokenTree::MetaVarDecl { .. } => panic!("unexpected `TokenTree::MetaVarDecl`"),
         }
     }
 }
@@ -776,7 +776,7 @@ fn lockstep_iter_size(
                 size.with(lockstep_iter_size(tt, interpolations, repeats))
             })
         }
-        TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => {
+        TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl { name, .. } => {
             let name = MacroRulesNormalizedIdent::new(*name);
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 85f3f51cfdf..8c0f279e343 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1096,7 +1096,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "the `#[rustc_main]` attribute is used internally to specify test entry point function",
     ),
     rustc_attr!(
-        rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
+        rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), ErrorFollowing,
         EncodeCrossCrate::No,
         "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
         from method dispatch when the receiver is of the following type, for compatibility in \
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 0cd090b25a4..c54b831e244 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -285,4 +285,18 @@ declare_features! (
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
+
+
+    // -------------------------------------------------------------------------
+    // feature-group-start: removed library features
+    // -------------------------------------------------------------------------
+    //
+    // FIXME(#141617): we should have a better way to track removed library features, but we reuse
+    // the infrastructure here so users still get hints. The symbols used here can be remove from
+    // `symbol.rs` when that happens.
+    (removed, concat_idents, "CURRENT_RUSTC_VERSION", Some(29599),
+     Some("use the `${concat(..)}` metavariable expression instead"), 142704),
+    // -------------------------------------------------------------------------
+    // feature-group-end: removed library features
+    // -------------------------------------------------------------------------
 );
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 60b691e0f75..485dd1d2204 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,7 +1,7 @@
 use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
-use rustc_abi::FieldIdx;
+use rustc_abi::{ExternAbi, FieldIdx};
 use rustc_attr_data_structures::ReprAttr::ReprPacked;
 use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
@@ -13,7 +13,6 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_lint_defs::builtin::{
     REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS,
-    UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
 };
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
@@ -53,49 +52,22 @@ fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T
 }
 
 pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
-    // FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix
-    // things like #86232.
+    // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this
+    // currently only guards function imports, function definitions, and function pointer types.
+    // Functions in trait declarations can still use "deprecated" ABIs without any warning.
 
     match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
         AbiMapping::Direct(..) => (),
+        // already erred in rustc_ast_lowering
         AbiMapping::Invalid => {
-            let mut err = struct_span_code_err!(
-                tcx.dcx(),
-                span,
-                E0570,
-                "`{abi}` is not a supported ABI for the current target",
-            );
-            add_abi_diag_help(abi, &mut err);
-            err.emit();
+            tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering"));
         }
         AbiMapping::Deprecated(..) => {
             tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
-                lint.primary_message("use of calling convention not supported on this target");
-                add_abi_diag_help(abi, lint);
-            });
-        }
-    }
-}
-
-pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
-    // This is always an FCW, even for `AbiMapping::Invalid`, since we started linting later than
-    // in `check_abi` above.
-    match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
-        AbiMapping::Direct(..) => (),
-        // This is not a redundant match arm: these ABIs started linting after introducing
-        // UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to
-        // avoid expanding the scope of that lint so it can move to a hard error sooner.
-        AbiMapping::Deprecated(..) => {
-            tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
-                lint.primary_message("use of calling convention not supported on this target");
-                add_abi_diag_help(abi, lint);
-            });
-        }
-        AbiMapping::Invalid => {
-            tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
                 lint.primary_message(format!(
-                    "the calling convention {abi} is not supported on this target"
+                    "{abi} is not a supported ABI for the current target"
                 ));
+                add_abi_diag_help(abi, lint);
             });
         }
     }
@@ -868,6 +840,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
                 return;
             };
+
             check_abi(tcx, it.hir_id(), it.span, abi);
 
             for item in items {
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index bf2d4f662ef..5cec3331bb1 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -72,8 +72,8 @@ pub mod wfcheck;
 
 use std::num::NonZero;
 
-pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
-use rustc_abi::{ExternAbi, VariantIdx};
+pub use check::{check_abi, check_custom_abi};
+use rustc_abi::VariantIdx;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
 use rustc_hir::LangItem;
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 176d955bf03..c967e87bfd8 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -21,6 +21,7 @@ use std::ops::Bound;
 
 use rustc_abi::ExternAbi;
 use rustc_ast::Recovered;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{
@@ -1151,22 +1152,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
     let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
 
-    // FIXME: We could probably do way better attribute validation here.
-    let mut skip_array_during_method_dispatch = false;
-    let mut skip_boxed_slice_during_method_dispatch = false;
-    for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
-        if let Some(lst) = attr.meta_item_list() {
-            for item in lst {
-                if let Some(ident) = item.ident() {
-                    match ident.as_str() {
-                        "array" => skip_array_during_method_dispatch = true,
-                        "boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
-                        _ => (),
-                    }
-                }
-            }
-        }
-    }
+    let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!(
+        tcx.get_all_attrs(def_id),
+        AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice]
+    )
+    .unwrap_or([false; 2]);
 
     let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
         ty::trait_def::TraitSpecializationKind::Marker
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index b99f7b44661..baf3b9b5bc9 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, FulfillmentError};
 use tracing::{debug, instrument};
 
-use crate::check::check_abi_fn_ptr;
+use crate::check::check_abi;
 use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
@@ -2660,7 +2660,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(bare_fn_ty), span, .. }) =
             tcx.hir_node(hir_id)
         {
-            check_abi_fn_ptr(tcx, hir_id, *span, bare_fn_ty.abi);
+            check_abi(tcx, hir_id, *span, bare_fn_ty.abi);
         }
 
         // reject function types that violate cmse ABI requirements
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index d3289e4cc6d..ff87d3dec6e 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1335,6 +1335,10 @@ impl<'a> State<'a> {
                 self.word_nbsp("raw");
                 self.print_mutability(mutability, true);
             }
+            hir::BorrowKind::Pin => {
+                self.word_nbsp("pin");
+                self.print_mutability(mutability, true);
+            }
         }
         self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 672f3bc67ce..2bc9dadb665 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -690,7 +690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_named_place_expr(oprnd);
                 Ty::new_ptr(self.tcx, ty, mutbl)
             }
-            hir::BorrowKind::Ref => {
+            hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
                 // Note: at this point, we cannot say what the best lifetime
                 // is to use for resulting pointer. We want to use the
                 // shortest lifetime possible so as to avoid spurious borrowck
@@ -706,7 +706,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // whose address was taken can actually be made to live as long
                 // as it needs to live.
                 let region = self.next_region_var(infer::BorrowRegion(expr.span));
-                Ty::new_ref(self.tcx, region, ty, mutbl)
+                match kind {
+                    hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),
+                    hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),
+                    _ => unreachable!(),
+                }
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 288d915e85c..b35aef13c52 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1723,8 +1723,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Don't emit a suggestion if we found an actual method
             // that had unsatisfied trait bounds
             if unsatisfied_predicates.is_empty()
-                // ...or if we already suggested that name because of `rustc_confusable` annotation.
+                // ...or if we already suggested that name because of `rustc_confusable` annotation
                 && Some(similar_candidate.name()) != confusable_suggested
+                // and if the we aren't in an expansion.
+                && !span.from_expansion()
             {
                 self.find_likely_intended_associated_item(
                     &mut err,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index d62bf7f85e0..c46e879b976 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -18,7 +18,6 @@ use rustc_parse::parser::attr::AllowLeadingUnsafe;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
 use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
-use rustc_session::filesearch::sysroot_with_fallback;
 use rustc_session::parse::ParseSess;
 use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint};
 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs};
@@ -405,8 +404,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
     crate::callbacks::setup_callbacks();
 
-    let sysroot = config.opts.sysroot.clone();
-    let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot);
+    let target = config::build_target_config(
+        &early_dcx,
+        &config.opts.target_triple,
+        config.opts.sysroot.path(),
+    );
     let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let path_mapping = config.opts.file_path_mapping();
     let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
@@ -426,7 +428,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let codegen_backend = match config.make_codegen_backend {
                 None => util::get_codegen_backend(
                     &early_dcx,
-                    &sysroot,
+                    &config.opts.sysroot,
                     config.opts.unstable_opts.codegen_backend.as_deref(),
                     &target,
                 ),
@@ -440,7 +442,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
 
             let bundle = match rustc_errors::fluent_bundle(
-                sysroot_with_fallback(&config.opts.sysroot),
+                &config.opts.sysroot.all_paths().collect::<Vec<_>>(),
                 config.opts.unstable_opts.translate_lang.clone(),
                 config.opts.unstable_opts.translate_additional_ftl.as_deref(),
                 config.opts.unstable_opts.translate_directionality_markers,
@@ -469,7 +471,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 locale_resources,
                 config.lint_caps,
                 target,
-                sysroot,
                 util::rustc_version_str().unwrap_or("unknown"),
                 config.ice_file,
                 config.using_internal_features,
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 201b7e2b940..e8c23ef997c 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -11,6 +11,7 @@ use rustc_data_structures::jobserver::Proxy;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal};
 use rustc_data_structures::{parallel, thousands};
+use rustc_errors::timings::TimingSection;
 use rustc_expand::base::{ExtCtxt, LintStoreExpand};
 use rustc_feature::Features;
 use rustc_fs_util::try_canonicalize;
@@ -370,7 +371,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
     let mut lint_buffer = resolver.lint_buffer.steal();
 
     if sess.opts.unstable_opts.input_stats {
-        input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats");
+        input_stats::print_ast_stats(tcx, krate);
     }
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
@@ -1176,6 +1177,8 @@ pub(crate) fn start_codegen<'tcx>(
     codegen_backend: &dyn CodegenBackend,
     tcx: TyCtxt<'tcx>,
 ) -> (Box<dyn Any>, EncodedMetadata) {
+    tcx.sess.timings.start_section(tcx.sess.dcx(), TimingSection::Codegen);
+
     // Hook for tests.
     if let Some((def_id, _)) = tcx.entry_fn(())
         && tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query)
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 877440ec7d2..2bc30fa7cb0 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -48,6 +48,7 @@ impl Linker {
         let (codegen_results, work_products) = sess.time("finish_ongoing_codegen", || {
             codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames)
         });
+        sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
 
         sess.dcx().abort_if_errors();
 
@@ -89,7 +90,7 @@ impl Linker {
         }
 
         let _timer = sess.prof.verbose_generic_activity("link_crate");
-        let _timing = sess.timings.start_section(sess.dcx(), TimingSection::Linking);
+        let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
         codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames)
     }
 }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a0012b04c4f..360b5629e9d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -41,9 +41,11 @@ where
 
     let matches = optgroups().parse(args).unwrap();
     let sessopts = build_session_options(&mut early_dcx, &matches);
-    let sysroot = sessopts.sysroot.clone();
-    let target =
-        rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot);
+    let target = rustc_session::config::build_target_config(
+        &early_dcx,
+        &sessopts.target_triple,
+        sessopts.sysroot.path(),
+    );
     let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
     let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm();
     let sm_inputs = Some(SourceMapInputs {
@@ -72,7 +74,6 @@ where
             vec![],
             Default::default(),
             target,
-            sysroot,
             "",
             None,
             &USING_INTERNAL_FEATURES,
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 8a7d6117265..0ca4fcc66ca 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::sync;
 use rustc_metadata::{DylibError, load_symbol_from_dylib};
 use rustc_middle::ty::CurrentGcx;
 use rustc_parse::validate_attr;
-use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, host_tuple};
+use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple};
 use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
 use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
 use rustc_session::{EarlyDiagCtxt, Session, filesearch};
@@ -305,7 +305,7 @@ fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBacken
 /// A name of `None` indicates that the default backend should be used.
 pub fn get_codegen_backend(
     early_dcx: &EarlyDiagCtxt,
-    sysroot: &Path,
+    sysroot: &Sysroot,
     backend_name: Option<&str>,
     target: &Target,
 ) -> Box<dyn CodegenBackend> {
@@ -336,25 +336,24 @@ pub fn get_codegen_backend(
 // This is used for rustdoc, but it uses similar machinery to codegen backend
 // loading, so we leave the code here. It is potentially useful for other tools
 // that want to invoke the rustc binary while linking to rustc as well.
-pub fn rustc_path<'a>() -> Option<&'a Path> {
+pub fn rustc_path<'a>(sysroot: &Sysroot) -> Option<&'a Path> {
     static RUSTC_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
 
-    const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
-
-    RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_deref()
-}
-
-fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
-    let candidate = filesearch::get_or_default_sysroot()
-        .join(bin_path)
-        .join(if cfg!(target_os = "windows") { "rustc.exe" } else { "rustc" });
-    candidate.exists().then_some(candidate)
+    RUSTC_PATH
+        .get_or_init(|| {
+            let candidate = sysroot
+                .default
+                .join(env!("RUSTC_INSTALL_BINDIR"))
+                .join(if cfg!(target_os = "windows") { "rustc.exe" } else { "rustc" });
+            candidate.exists().then_some(candidate)
+        })
+        .as_deref()
 }
 
 #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
 fn get_codegen_sysroot(
     early_dcx: &EarlyDiagCtxt,
-    sysroot: &Path,
+    sysroot: &Sysroot,
     backend_name: &str,
 ) -> MakeBackendFn {
     // For now we only allow this function to be called once as it'll dlopen a
@@ -369,10 +368,9 @@ fn get_codegen_sysroot(
     );
 
     let target = host_tuple();
-    let sysroot_candidates = filesearch::sysroot_with_fallback(&sysroot);
 
-    let sysroot = sysroot_candidates
-        .iter()
+    let sysroot = sysroot
+        .all_paths()
         .map(|sysroot| {
             filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends")
         })
@@ -381,8 +379,8 @@ fn get_codegen_sysroot(
             f.exists()
         })
         .unwrap_or_else(|| {
-            let candidates = sysroot_candidates
-                .iter()
+            let candidates = sysroot
+                .all_paths()
                 .map(|p| p.display().to_string())
                 .collect::<Vec<_>>()
                 .join("\n* ");
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 297b8ef7e76..95663204ec3 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -524,6 +524,20 @@ pub trait LintContext {
         });
     }
 
+    /// Emit a lint at `span` from a lazily-constructed lint struct (some type that implements
+    /// `LintDiagnostic`, typically generated by `#[derive(LintDiagnostic)]`).
+    fn emit_span_lint_lazy<S: Into<MultiSpan>, L: for<'a> LintDiagnostic<'a, ()>>(
+        &self,
+        lint: &'static Lint,
+        span: S,
+        decorator: impl FnOnce() -> L,
+    ) {
+        self.opt_span_lint(lint, Some(span), |lint| {
+            let decorator = decorator();
+            decorator.decorate_lint(lint);
+        });
+    }
+
     /// Emit a lint at the appropriate level, with an associated span.
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 20568f35a47..48982bda0a0 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -608,6 +608,7 @@ fn register_builtins(store: &mut LintStore) {
         "converted into hard error, see issue #127323 \
          <https://github.com/rust-lang/rust/issues/127323> for more information",
     );
+    store.register_removed("unsupported_fn_ptr_calling_conventions", "converted into hard error");
     store.register_removed(
         "undefined_naked_function_abi",
         "converted into hard error, see PR #139001 \
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index abdf8e3853b..4d405d915fb 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1353,6 +1353,8 @@ pub(crate) struct NonUpperCaseGlobal<'a> {
     pub name: &'a str,
     #[subdiagnostic]
     pub sub: NonUpperCaseGlobalSub,
+    #[subdiagnostic]
+    pub usages: Vec<NonUpperCaseGlobalSubTool>,
 }
 
 #[derive(Subdiagnostic)]
@@ -1362,14 +1364,29 @@ pub(crate) enum NonUpperCaseGlobalSub {
         #[primary_span]
         span: Span,
     },
-    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    #[suggestion(lint_suggestion, code = "{replace}")]
     Suggestion {
         #[primary_span]
         span: Span,
+        #[applicability]
+        applicability: Applicability,
         replace: String,
     },
 }
 
+#[derive(Subdiagnostic)]
+#[suggestion(
+    lint_suggestion,
+    code = "{replace}",
+    applicability = "machine-applicable",
+    style = "tool-only"
+)]
+pub(crate) struct NonUpperCaseGlobalSubTool {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) replace: String,
+}
+
 // noop_method_call.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_noop_method_call)]
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index f39e1506390..97e627f2eb2 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,9 +1,12 @@
 use rustc_abi::ExternAbi;
 use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
 use rustc_attr_parsing::AttributeParser;
+use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{FnKind, Visitor};
 use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind};
+use rustc_middle::hir::nested_filter::All;
 use rustc_middle::ty;
 use rustc_session::config::CrateType;
 use rustc_session::{declare_lint, declare_lint_pass};
@@ -13,7 +16,7 @@ use {rustc_ast as ast, rustc_hir as hir};
 
 use crate::lints::{
     NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub,
-    NonUpperCaseGlobal, NonUpperCaseGlobalSub,
+    NonUpperCaseGlobal, NonUpperCaseGlobalSub, NonUpperCaseGlobalSubTool,
 };
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 
@@ -493,22 +496,82 @@ declare_lint! {
 declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]);
 
 impl NonUpperCaseGlobals {
-    fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
+    fn check_upper_case(cx: &LateContext<'_>, sort: &str, did: Option<LocalDefId>, ident: &Ident) {
         let name = ident.name.as_str();
         if name.chars().any(|c| c.is_lowercase()) {
             let uc = NonSnakeCase::to_snake_case(name).to_uppercase();
+
+            // If the item is exported, suggesting changing it's name would be breaking-change
+            // and could break users without a "nice" applicable fix, so let's avoid it.
+            let can_change_usages = if let Some(did) = did {
+                !cx.tcx.effective_visibilities(()).is_exported(did)
+            } else {
+                false
+            };
+
             // We cannot provide meaningful suggestions
             // if the characters are in the category of "Lowercase Letter".
             let sub = if *name != uc {
-                NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc }
+                NonUpperCaseGlobalSub::Suggestion {
+                    span: ident.span,
+                    replace: uc.clone(),
+                    applicability: if can_change_usages {
+                        Applicability::MachineApplicable
+                    } else {
+                        Applicability::MaybeIncorrect
+                    },
+                }
             } else {
                 NonUpperCaseGlobalSub::Label { span: ident.span }
             };
-            cx.emit_span_lint(
-                NON_UPPER_CASE_GLOBALS,
-                ident.span,
-                NonUpperCaseGlobal { sort, name, sub },
-            );
+
+            struct UsageCollector<'a, 'tcx> {
+                cx: &'tcx LateContext<'a>,
+                did: DefId,
+                collected: Vec<Span>,
+            }
+
+            impl<'v, 'tcx> Visitor<'v> for UsageCollector<'v, 'tcx> {
+                type NestedFilter = All;
+
+                fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+                    self.cx.tcx
+                }
+
+                fn visit_path(
+                    &mut self,
+                    path: &rustc_hir::Path<'v>,
+                    _id: rustc_hir::HirId,
+                ) -> Self::Result {
+                    if let Some(final_seg) = path.segments.last()
+                        && final_seg.res.opt_def_id() == Some(self.did)
+                    {
+                        self.collected.push(final_seg.ident.span);
+                    }
+                }
+            }
+
+            cx.emit_span_lint_lazy(NON_UPPER_CASE_GLOBALS, ident.span, || {
+                // Compute usages lazily as it can expansive and useless when the lint is allowed.
+                // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625
+                let usages = if can_change_usages
+                    && *name != uc
+                    && let Some(did) = did
+                {
+                    let mut usage_collector =
+                        UsageCollector { cx, did: did.to_def_id(), collected: Vec::new() };
+                    cx.tcx.hir_walk_toplevel_module(&mut usage_collector);
+                    usage_collector
+                        .collected
+                        .into_iter()
+                        .map(|span| NonUpperCaseGlobalSubTool { span, replace: uc.clone() })
+                        .collect()
+                } else {
+                    vec![]
+                };
+
+                NonUpperCaseGlobal { sort, name, sub, usages }
+            });
         }
     }
 }
@@ -520,10 +583,20 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
             hir::ItemKind::Static(_, ident, ..)
                 if !find_attr!(attrs, AttributeKind::NoMangle(..)) =>
             {
-                NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident);
+                NonUpperCaseGlobals::check_upper_case(
+                    cx,
+                    "static variable",
+                    Some(it.owner_id.def_id),
+                    &ident,
+                );
             }
             hir::ItemKind::Const(ident, ..) => {
-                NonUpperCaseGlobals::check_upper_case(cx, "constant", &ident);
+                NonUpperCaseGlobals::check_upper_case(
+                    cx,
+                    "constant",
+                    Some(it.owner_id.def_id),
+                    &ident,
+                );
             }
             _ => {}
         }
@@ -531,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, ti: &hir::TraitItem<'_>) {
         if let hir::TraitItemKind::Const(..) = ti.kind {
-            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ti.ident);
+            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ti.ident);
         }
     }
 
@@ -539,7 +612,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
         if let hir::ImplItemKind::Const(..) = ii.kind
             && !assoc_item_in_trait_impl(cx, ii)
         {
-            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident);
+            NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ii.ident);
         }
     }
 
@@ -555,6 +628,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
                     NonUpperCaseGlobals::check_upper_case(
                         cx,
                         "constant in pattern",
+                        None,
                         &segment.ident,
                     );
                 }
@@ -564,7 +638,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
         if let GenericParamKind::Const { .. } = param.kind {
-            NonUpperCaseGlobals::check_upper_case(cx, "const parameter", &param.name.ident());
+            NonUpperCaseGlobals::check_upper_case(
+                cx,
+                "const parameter",
+                Some(param.def_id),
+                &param.name.ident(),
+            );
         }
     }
 }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b0ea9689e50..5fa00fcc4a0 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -122,7 +122,6 @@ declare_lint_pass! {
         UNSAFE_OP_IN_UNSAFE_FN,
         UNSTABLE_NAME_COLLISIONS,
         UNSTABLE_SYNTAX_PRE_EXPANSION,
-        UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
         UNUSED_ASSIGNMENTS,
         UNUSED_ASSOCIATED_TYPE_BOUNDS,
         UNUSED_ATTRIBUTES,
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 259bcb1b96d..941f16bd960 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -321,7 +321,7 @@ impl<'a> CrateLocator<'a> {
 
         CrateLocator {
             only_needs_metadata,
-            sysroot: &sess.sysroot,
+            sysroot: sess.opts.sysroot.path(),
             metadata_loader,
             cfg_version: sess.cfg_version,
             crate_name,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 00bd32eb0eb..ed3c18a02a6 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -762,6 +762,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         assert_eq!(total_bytes, computed_total_bytes);
 
         if tcx.sess.opts.unstable_opts.meta_stats {
+            use std::fmt::Write;
+
             self.opaque.flush();
 
             // Rewind and re-read all the metadata to count the zero bytes we wrote.
@@ -777,31 +779,44 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind);
 
             stats.sort_by_key(|&(_, usize)| usize);
+            stats.reverse(); // bigger items first
 
             let prefix = "meta-stats";
             let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
 
-            eprintln!("{prefix} METADATA STATS");
-            eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size");
-            eprintln!("{prefix} ----------------------------------------------------------------");
+            let section_w = 23;
+            let size_w = 10;
+            let banner_w = 64;
+
+            // We write all the text into a string and print it with a single
+            // `eprint!`. This is an attempt to minimize interleaved text if multiple
+            // rustc processes are printing macro-stats at the same time (e.g. with
+            // `RUSTFLAGS='-Zmeta-stats' cargo build`). It still doesn't guarantee
+            // non-interleaving, though.
+            let mut s = String::new();
+            _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+            _ = writeln!(s, "{prefix} METADATA STATS: {}", tcx.crate_name(LOCAL_CRATE));
+            _ = writeln!(s, "{prefix} {:<section_w$}{:>size_w$}", "Section", "Size");
+            _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
             for (label, size) in stats {
-                eprintln!(
-                    "{} {:<23}{:>10} ({:4.1}%)",
-                    prefix,
+                _ = writeln!(
+                    s,
+                    "{prefix} {:<section_w$}{:>size_w$} ({:4.1}%)",
                     label,
                     usize_with_underscores(size),
                     perc(size)
                 );
             }
-            eprintln!("{prefix} ----------------------------------------------------------------");
-            eprintln!(
-                "{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
-                prefix,
+            _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
+            _ = writeln!(
+                s,
+                "{prefix} {:<section_w$}{:>size_w$} (of which {:.1}% are zero bytes)",
                 "Total",
                 usize_with_underscores(total_bytes),
                 perc(zero_bytes)
             );
-            eprintln!("{prefix}");
+            _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+            eprint!("{s}");
         }
 
         root
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
index 1d67d0fe3bb..64a1f2aff15 100644
--- a/compiler/rustc_middle/src/middle/exported_symbols.rs
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -22,7 +22,7 @@ impl SymbolExportLevel {
 }
 
 /// Kind of exported symbols.
-#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable, Hash)]
 pub enum SymbolExportKind {
     Text,
     Data,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 4c970e8e3d7..5197e93fda7 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -481,6 +481,55 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
             }
 
+            // Make `&pin mut $expr` and `&pin const $expr` into
+            // `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`.
+            hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() {
+                &ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => {
+                    let ty = args.type_at(0);
+                    let arg_ty = self.typeck_results.expr_ty(arg_expr);
+                    let mut arg = self.mirror_expr(arg_expr);
+                    // For `&pin mut $place` where `$place` is not `Unpin`, move the place
+                    // `$place` to ensure it will not be used afterwards.
+                    if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) {
+                        let block = self.thir.blocks.push(Block {
+                            targeted_by_break: false,
+                            region_scope: region::Scope {
+                                local_id: arg_expr.hir_id.local_id,
+                                data: region::ScopeData::Node,
+                            },
+                            span: arg_expr.span,
+                            stmts: Box::new([]),
+                            expr: Some(arg),
+                            safety_mode: BlockSafety::Safe,
+                        });
+                        let (temp_lifetime, backwards_incompatible) = self
+                            .rvalue_scopes
+                            .temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id);
+                        arg = self.thir.exprs.push(Expr {
+                            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                            ty: arg_ty,
+                            span: arg_expr.span,
+                            kind: ExprKind::Block { block },
+                        });
+                    }
+                    let expr = self.thir.exprs.push(Expr {
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                        ty,
+                        span: expr.span,
+                        kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
+                    });
+                    ExprKind::Adt(Box::new(AdtExpr {
+                        adt_def,
+                        variant_index: FIRST_VARIANT,
+                        args,
+                        fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
+                        user_ty: None,
+                        base: AdtExprBase::None,
+                    }))
+                }
+                _ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
+            },
+
             hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
 
             hir::ExprKind::Assign(lhs, rhs, _) => {
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 00fd3ba8046..780feb9b827 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -147,13 +147,9 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
     fn evaluate_root_goal(
         &self,
         goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
-        generate_proof_tree: GenerateProofTree,
         span: <Self::Interner as Interner>::Span,
         stalled_on: Option<GoalStalledOn<Self::Interner>>,
-    ) -> (
-        Result<GoalEvaluation<Self::Interner>, NoSolution>,
-        Option<inspect::GoalEvaluation<Self::Interner>>,
-    );
+    ) -> Result<GoalEvaluation<Self::Interner>, NoSolution>;
 
     /// Check whether evaluating `goal` with a depth of `root_depth` may
     /// succeed. This only returns `false` if the goal is guaranteed to
@@ -170,17 +166,16 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
 
     // FIXME: This is only exposed because we need to use it in `analyse.rs`
     // which is not yet uplifted. Once that's done, we should remove this.
-    fn evaluate_root_goal_raw(
+    fn evaluate_root_goal_for_proof_tree(
         &self,
         goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
-        generate_proof_tree: GenerateProofTree,
-        stalled_on: Option<GoalStalledOn<Self::Interner>>,
+        span: <Self::Interner as Interner>::Span,
     ) -> (
         Result<
             (NestedNormalizationGoals<Self::Interner>, GoalEvaluation<Self::Interner>),
             NoSolution,
         >,
-        Option<inspect::GoalEvaluation<Self::Interner>>,
+        inspect::GoalEvaluation<Self::Interner>,
     );
 }
 
@@ -193,13 +188,17 @@ where
     fn evaluate_root_goal(
         &self,
         goal: Goal<I, I::Predicate>,
-        generate_proof_tree: GenerateProofTree,
         span: I::Span,
         stalled_on: Option<GoalStalledOn<I>>,
-    ) -> (Result<GoalEvaluation<I>, NoSolution>, Option<inspect::GoalEvaluation<I>>) {
-        EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| {
-            ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
-        })
+    ) -> Result<GoalEvaluation<I>, NoSolution> {
+        EvalCtxt::enter_root(
+            self,
+            self.cx().recursion_limit(),
+            GenerateProofTree::No,
+            span,
+            |ecx| ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on),
+        )
+        .0
     }
 
     fn root_goal_may_hold_with_depth(
@@ -217,24 +216,22 @@ where
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn evaluate_root_goal_raw(
+    fn evaluate_root_goal_for_proof_tree(
         &self,
         goal: Goal<I, I::Predicate>,
-        generate_proof_tree: GenerateProofTree,
-        stalled_on: Option<GoalStalledOn<I>>,
+        span: I::Span,
     ) -> (
         Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution>,
-        Option<inspect::GoalEvaluation<I>>,
+        inspect::GoalEvaluation<I>,
     ) {
-        EvalCtxt::enter_root(
+        let (result, proof_tree) = EvalCtxt::enter_root(
             self,
             self.cx().recursion_limit(),
-            generate_proof_tree,
-            I::Span::dummy(),
-            |ecx| {
-                ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
-            },
-        )
+            GenerateProofTree::Yes,
+            span,
+            |ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, None),
+        );
+        (result, proof_tree.unwrap())
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 93c76c47f06..4e312aab497 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -847,7 +847,7 @@ impl<'a> Parser<'a> {
         self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
     }
 
-    /// Parse `mut?` or `raw [ const | mut ]`.
+    /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
     fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
         if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
             // `raw [ const | mut ]`.
@@ -855,6 +855,11 @@ impl<'a> Parser<'a> {
             assert!(found_raw);
             let mutability = self.parse_const_or_mut().unwrap();
             (ast::BorrowKind::Raw, mutability)
+        } else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
+            // `pin [ const | mut ]`.
+            // `pin` has been gated in `self.parse_pin_and_mut()` so we don't
+            // need to gate it here.
+            (ast::BorrowKind::Pin, mutbl)
         } else {
             // `mut?`
             (ast::BorrowKind::Ref, self.parse_mutability())
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 8e6442353c3..47e29923ee5 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -286,13 +286,20 @@ fn emit_malformed_attribute(
     if matches!(
         name,
         sym::inline
+            | sym::may_dangle
+            | sym::rustc_as_ptr
+            | sym::rustc_pub_transparent
+            | sym::rustc_const_stable_indirect
             | sym::rustc_force_inline
             | sym::rustc_confusables
+            | sym::rustc_skip_during_method_dispatch
             | sym::repr
             | sym::align
             | sym::deprecated
             | sym::optimize
             | sym::cold
+            | sym::naked
+            | sym::no_mangle
             | sym::must_use
     ) {
         return;
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 3c40b597f41..2dcb0cfedd5 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -118,6 +118,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         for attr in attrs {
             let mut style = None;
             match attr {
+                Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch {
+                    span: attr_span,
+                    ..
+                }) => {
+                    self.check_must_be_applied_to_trait(*attr_span, span, target);
+                }
                 Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
                     self.check_confusables(*first_span, target);
                 }
@@ -256,7 +262,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         | [sym::rustc_must_implement_one_of, ..]
                         | [sym::rustc_deny_explicit_impl, ..]
                         | [sym::rustc_do_not_implement_via_object, ..]
-                        | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
+                        | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
                         [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
                         [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
                         [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
@@ -1811,14 +1817,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if the attribute is applied to a trait.
-    fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) {
+    fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) {
         match target {
             Target::Trait => {}
             _ => {
-                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
-                    attr_span: attr.span(),
-                    defn_span: span,
-                });
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span });
             }
         }
     }
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 46e6c0bf7da..40bc18939d6 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -65,16 +65,16 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) {
         StatCollector { tcx: Some(tcx), nodes: FxHashMap::default(), seen: FxHashSet::default() };
     tcx.hir_walk_toplevel_module(&mut collector);
     tcx.hir_walk_attributes(&mut collector);
-    collector.print("HIR STATS", "hir-stats");
+    collector.print(tcx, "HIR STATS", "hir-stats");
 }
 
-pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) {
+pub fn print_ast_stats(tcx: TyCtxt<'_>, krate: &ast::Crate) {
     use rustc_ast::visit::Visitor;
 
     let mut collector =
         StatCollector { tcx: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
     collector.visit_crate(krate);
-    collector.print(title, prefix);
+    collector.print(tcx, "POST EXPANSION AST STATS", "ast-stats");
 }
 
 impl<'k> StatCollector<'k> {
@@ -116,29 +116,48 @@ impl<'k> StatCollector<'k> {
         }
     }
 
-    fn print(&self, title: &str, prefix: &str) {
+    fn print(&self, tcx: TyCtxt<'_>, title: &str, prefix: &str) {
+        use std::fmt::Write;
+
         // We will soon sort, so the initial order does not matter.
         #[allow(rustc::potential_query_instability)]
         let mut nodes: Vec<_> = self.nodes.iter().collect();
         nodes.sort_by_cached_key(|(label, node)| (node.stats.accum_size(), label.to_owned()));
+        nodes.reverse(); // bigger items first
+
+        let name_w = 18;
+        let acc_size1_w = 10;
+        let acc_size2_w = 8; // " (NN.N%)"
+        let acc_size_w = acc_size1_w + acc_size2_w;
+        let count_w = 14;
+        let item_size_w = 14;
+        let banner_w = name_w + acc_size_w + count_w + item_size_w;
 
         let total_size = nodes.iter().map(|(_, node)| node.stats.accum_size()).sum();
         let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum();
 
-        eprintln!("{prefix} {title}");
-        eprintln!(
-            "{} {:<18}{:>18}{:>14}{:>14}",
-            prefix, "Name", "Accumulated Size", "Count", "Item Size"
+        // We write all the text into a string and print it with a single
+        // `eprint!`. This is an attempt to minimize interleaved text if multiple
+        // rustc processes are printing macro-stats at the same time (e.g. with
+        // `RUSTFLAGS='-Zinput-stats' cargo build`). It still doesn't guarantee
+        // non-interleaving, though.
+        let mut s = String::new();
+        _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+        _ = writeln!(s, "{prefix} {title}: {}", tcx.crate_name(hir::def_id::LOCAL_CRATE));
+        _ = writeln!(
+            s,
+            "{prefix} {:<name_w$}{:>acc_size_w$}{:>count_w$}{:>item_size_w$}",
+            "Name", "Accumulated Size", "Count", "Item Size"
         );
-        eprintln!("{prefix} ----------------------------------------------------------------");
+        _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
 
         let percent = |m, n| (m * 100) as f64 / n as f64;
 
         for (label, node) in nodes {
             let size = node.stats.accum_size();
-            eprintln!(
-                "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
-                prefix,
+            _ = writeln!(
+                s,
+                "{prefix} {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}{:>item_size_w$}",
                 label,
                 usize_with_underscores(size),
                 percent(size, total_size),
@@ -155,9 +174,9 @@ impl<'k> StatCollector<'k> {
 
                 for (label, subnode) in subnodes {
                     let size = subnode.accum_size();
-                    eprintln!(
-                        "{} - {:<18}{:>10} ({:4.1}%){:>14}",
-                        prefix,
+                    _ = writeln!(
+                        s,
+                        "{prefix} - {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}",
                         label,
                         usize_with_underscores(size),
                         percent(size, total_size),
@@ -166,15 +185,17 @@ impl<'k> StatCollector<'k> {
                 }
             }
         }
-        eprintln!("{prefix} ----------------------------------------------------------------");
-        eprintln!(
-            "{} {:<18}{:>10}        {:>14}",
-            prefix,
+        _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
+        _ = writeln!(
+            s,
+            "{prefix} {:<name_w$}{:>acc_size1_w$}{:>acc_size2_w$}{:>count_w$}",
             "Total",
             usize_with_underscores(total_size),
+            "",
             usize_with_underscores(total_count),
         );
-        eprintln!("{prefix}");
+        _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+        eprint!("{s}");
     }
 }
 
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index e989209e177..1b7a2c3bda0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -608,7 +608,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             }
         }
 
-        self.throw_unresolved_import_error(errors, glob_error);
+        if !errors.is_empty() {
+            self.throw_unresolved_import_error(errors, glob_error);
+        }
     }
 
     pub(crate) fn check_hidden_glob_reexports(
@@ -688,14 +690,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false,
             _ => true,
         });
+        errors.retain(|(_import, err)| {
+            // If we've encountered something like `use _;`, we've already emitted an error stating
+            // that `_` is not a valid identifier, so we ignore that resolve error.
+            err.segment != Some(kw::Underscore)
+        });
+
         if errors.is_empty() {
+            self.tcx.dcx().delayed_bug("expected a parse or \"`_` can't be an identifier\" error");
             return;
         }
 
-        /// Upper limit on the number of `span_label` messages.
-        const MAX_LABEL_COUNT: usize = 10;
-
         let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
+
         let paths = errors
             .iter()
             .map(|(import, err)| {
@@ -715,6 +722,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             diag.note(note.clone());
         }
 
+        /// Upper limit on the number of `span_label` messages.
+        const MAX_LABEL_COUNT: usize = 10;
+
         for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
             if let Some(label) = err.label {
                 diag.span_label(err.span, label);
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index f0ee19e3c67..5b88a7017c5 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -22,7 +22,6 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-smallvec = "1.8.1"
 termize = "0.1.1"
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 87e4b0a17aa..c62e4ac30ea 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1296,6 +1296,28 @@ bitflags::bitflags! {
     }
 }
 
+#[derive(Clone, Debug)]
+pub struct Sysroot {
+    pub explicit: Option<PathBuf>,
+    pub default: PathBuf,
+}
+
+impl Sysroot {
+    pub fn new(explicit: Option<PathBuf>) -> Sysroot {
+        Sysroot { explicit, default: filesearch::default_sysroot() }
+    }
+
+    /// Return explicit sysroot if it was passed with `--sysroot`, or default sysroot otherwise.
+    pub fn path(&self) -> &Path {
+        self.explicit.as_deref().unwrap_or(&self.default)
+    }
+
+    /// Returns both explicit sysroot if it was passed with `--sysroot` and the default sysroot.
+    pub fn all_paths(&self) -> impl Iterator<Item = &Path> {
+        self.explicit.as_deref().into_iter().chain(iter::once(&*self.default))
+    }
+}
+
 pub fn host_tuple() -> &'static str {
     // Get the host triple out of the build environment. This ensures that our
     // idea of the host triple is the same as for the set of libraries we've
@@ -1342,7 +1364,7 @@ impl Default for Options {
             describe_lints: false,
             output_types: OutputTypes(BTreeMap::new()),
             search_paths: vec![],
-            sysroot: filesearch::materialize_sysroot(None),
+            sysroot: Sysroot::new(None),
             target_triple: TargetTuple::from_tuple(host_tuple()),
             test: false,
             incremental: None,
@@ -2673,7 +2695,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let cg = cg;
 
-    let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
     let target_triple = parse_target_triple(early_dcx, matches);
     let opt_level = parse_opt_level(early_dcx, matches, &cg);
     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
@@ -2712,10 +2733,10 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let logical_env = parse_logical_env(early_dcx, matches);
 
-    let sysroot = filesearch::materialize_sysroot(sysroot_opt);
+    let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
 
     let real_source_base_dir = |suffix: &str, confirm: &str| {
-        let mut candidate = sysroot.join(suffix);
+        let mut candidate = sysroot.path().join(suffix);
         if let Ok(metadata) = candidate.symlink_metadata() {
             // Replace the symlink bootstrap creates, with its destination.
             // We could try to use `fs::canonicalize` instead, but that might
@@ -2742,7 +2763,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
     let mut search_paths = vec![];
     for s in &matches.opt_strs("L") {
         search_paths.push(SearchPath::from_cli_opt(
-            &sysroot,
+            sysroot.path(),
             &target_triple,
             early_dcx,
             s,
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 4f8c3926207..f64fa86948c 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -5,7 +5,6 @@ use std::{env, fs};
 
 use rustc_fs_util::try_canonicalize;
 use rustc_target::spec::Target;
-use smallvec::{SmallVec, smallvec};
 
 use crate::search_paths::{PathKind, SearchPath};
 
@@ -182,24 +181,9 @@ fn current_dll_path() -> Result<PathBuf, String> {
     Err("current_dll_path is not supported on WASI".to_string())
 }
 
-pub fn sysroot_with_fallback(sysroot: &Path) -> SmallVec<[PathBuf; 2]> {
-    let mut candidates = smallvec![sysroot.to_owned()];
-    let default_sysroot = get_or_default_sysroot();
-    if default_sysroot != sysroot {
-        candidates.push(default_sysroot);
-    }
-    candidates
-}
-
-/// Returns the provided sysroot or calls [`get_or_default_sysroot`] if it's none.
-/// Panics if [`get_or_default_sysroot`]  returns an error.
-pub fn materialize_sysroot(maybe_sysroot: Option<PathBuf>) -> PathBuf {
-    maybe_sysroot.unwrap_or_else(|| get_or_default_sysroot())
-}
-
 /// This function checks if sysroot is found using env::args().next(), and if it
 /// is not found, finds sysroot from current rustc_driver dll.
-pub fn get_or_default_sysroot() -> PathBuf {
+pub(crate) fn default_sysroot() -> PathBuf {
     fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
         let dll = current_dll_path()?;
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 7fef942525b..232531dc673 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -337,7 +337,7 @@ top_level_options!(
         output_types: OutputTypes [TRACKED],
         search_paths: Vec<SearchPath> [UNTRACKED],
         libs: Vec<NativeLib> [TRACKED],
-        sysroot: PathBuf [UNTRACKED],
+        sysroot: Sysroot [UNTRACKED],
 
         target_triple: TargetTuple [TRACKED],
 
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index ad58c3c8f7d..bad2581ae31 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -149,7 +149,6 @@ pub struct Session {
     pub opts: config::Options,
     pub target_tlib_path: Arc<SearchPath>,
     pub psess: ParseSess,
-    pub sysroot: PathBuf,
     /// Input, input file path and output file path to this compilation process.
     pub io: CompilerIO,
 
@@ -456,8 +455,10 @@ impl Session {
     /// directories are also returned, for example if `--sysroot` is used but tools are missing
     /// (#125246): we also add the bin directories to the sysroot where rustc is located.
     pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
-        let search_paths = filesearch::sysroot_with_fallback(&self.sysroot)
-            .into_iter()
+        let search_paths = self
+            .opts
+            .sysroot
+            .all_paths()
             .map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_tuple()));
 
         if self_contained {
@@ -1028,7 +1029,6 @@ pub fn build_session(
     fluent_resources: Vec<&'static str>,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     target: Target,
-    sysroot: PathBuf,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
     using_internal_features: &'static AtomicBool,
@@ -1063,7 +1063,7 @@ pub fn build_session(
     }
 
     let host_triple = TargetTuple::from_tuple(config::host_tuple());
-    let (host, target_warnings) = Target::search(&host_triple, &sysroot)
+    let (host, target_warnings) = Target::search(&host_triple, sopts.sysroot.path())
         .unwrap_or_else(|e| dcx.handle().fatal(format!("Error loading host specification: {e}")));
     for warning in target_warnings.warning_messages() {
         dcx.handle().warn(warning)
@@ -1096,13 +1096,14 @@ pub fn build_session(
     let host_triple = config::host_tuple();
     let target_triple = sopts.target_triple.tuple();
     // FIXME use host sysroot?
-    let host_tlib_path = Arc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple));
+    let host_tlib_path =
+        Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), host_triple));
     let target_tlib_path = if host_triple == target_triple {
         // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary
         // rescanning of the target lib path and an unnecessary allocation.
         Arc::clone(&host_tlib_path)
     } else {
-        Arc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
+        Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), target_triple))
     };
 
     let prof = SelfProfilerRef::new(
@@ -1134,7 +1135,6 @@ pub fn build_session(
         opts: sopts,
         target_tlib_path,
         psess,
-        sysroot,
         io,
         incr_comp_session: RwLock::new(IncrCompSession::NotInitialized),
         prof,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index fb0f63d12c2..c9262d24a17 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -577,6 +577,7 @@ symbols! {
         box_new,
         box_patterns,
         box_syntax,
+        boxed_slice,
         bpf_target_feature,
         braced_empty_structs,
         branch,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index ed99c678a4d..d56042a5ca2 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{
 };
 use rustc_next_trait_solver::delegate::SolverDelegate as _;
 use rustc_next_trait_solver::solve::{
-    GenerateProofTree, GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _,
+    GoalEvaluation, GoalStalledOn, HasChanged, SolverDelegateEvalExt as _,
 };
 use rustc_span::Span;
 use thin_vec::ThinVec;
@@ -106,14 +106,11 @@ impl<'tcx> ObligationStorage<'tcx> {
             self.overflowed.extend(
                 ExtractIf::new(&mut self.pending, |(o, stalled_on)| {
                     let goal = o.as_goal();
-                    let result = <&SolverDelegate<'tcx>>::from(infcx)
-                        .evaluate_root_goal(
-                            goal,
-                            GenerateProofTree::No,
-                            o.cause.span,
-                            stalled_on.take(),
-                        )
-                        .0;
+                    let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
+                        goal,
+                        o.cause.span,
+                        stalled_on.take(),
+                    );
                     matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }))
                 })
                 .map(|(o, _)| o),
@@ -207,14 +204,7 @@ where
                     continue;
                 }
 
-                let result = delegate
-                    .evaluate_root_goal(
-                        goal,
-                        GenerateProofTree::No,
-                        obligation.cause.span,
-                        stalled_on,
-                    )
-                    .0;
+                let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
                 self.inspect_evaluated_obligation(infcx, &obligation, &result);
                 let GoalEvaluation { certainty, has_changed, stalled_on } = match result {
                     Ok(result) => result,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index 36a8ae675c0..fe248b033bb 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -11,9 +11,7 @@ use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_next_trait_solver::solve::{
-    GenerateProofTree, GoalEvaluation, SolverDelegateEvalExt as _,
-};
+use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _};
 use tracing::{instrument, trace};
 
 use crate::solve::delegate::SolverDelegate;
@@ -90,15 +88,11 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>(
     root_obligation: PredicateObligation<'tcx>,
 ) -> FulfillmentError<'tcx> {
     let (code, refine_obligation) = infcx.probe(|_| {
-        match <&SolverDelegate<'tcx>>::from(infcx)
-            .evaluate_root_goal(
-                root_obligation.as_goal(),
-                GenerateProofTree::No,
-                root_obligation.cause.span,
-                None,
-            )
-            .0
-        {
+        match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
+            root_obligation.as_goal(),
+            root_obligation.cause.span,
+            None,
+        ) {
             Ok(GoalEvaluation { certainty: Certainty::Maybe(MaybeCause::Ambiguity), .. }) => {
                 (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
             }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index b0c8fa1f217..80df0fab2d8 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit};
 use rustc_middle::{bug, ty};
 use rustc_next_trait_solver::resolve::eager_resolve_vars;
 use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
-use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
+use rustc_next_trait_solver::solve::{MaybeCause, SolverDelegateEvalExt as _};
 use rustc_span::Span;
 use tracing::instrument;
 
@@ -248,9 +248,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                     // considering the constrained RHS, and pass the resulting certainty to
                     // `InspectGoal::new` so that the goal has the right result (and maintains
                     // the impression that we don't do this normalizes-to infer hack at all).
-                    let (nested, proof_tree) =
-                        infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None);
-                    let proof_tree = proof_tree.unwrap();
+                    let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span);
                     let nested_goals_result = nested.and_then(|(nested, _)| {
                         normalizes_to_term_hack.constrain_and(
                             infcx,
@@ -284,9 +282,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                 // into another candidate who ends up with different inference
                 // constraints, we get an ICE if we already applied the constraints
                 // from the chosen candidate.
-                let proof_tree = infcx
-                    .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes, span, None).1)
-                    .unwrap();
+                let proof_tree =
+                    infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1);
                 InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
             }
         }
@@ -488,13 +485,8 @@ impl<'tcx> InferCtxt<'tcx> {
         depth: usize,
         visitor: &mut V,
     ) -> V::Result {
-        let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal(
-            goal,
-            GenerateProofTree::Yes,
-            visitor.span(),
-            None,
-        );
-        let proof_tree = proof_tree.unwrap();
+        let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self)
+            .evaluate_root_goal_for_proof_tree(goal, visitor.span());
         visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc))
     }
 }
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 48849bf7536..93bdad75380 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -1099,6 +1099,46 @@ impl From<&CStr> for CString {
     }
 }
 
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CStr> for CString {
+    #[inline]
+    fn eq(&self, other: &CStr) -> bool {
+        **self == *other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CStr) -> bool {
+        **self != *other
+    }
+}
+
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<&CStr> for CString {
+    #[inline]
+    fn eq(&self, other: &&CStr) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &&CStr) -> bool {
+        **self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<Cow<'_, CStr>> for CString {
+    #[inline]
+    fn eq(&self, other: &Cow<'_, CStr>) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &Cow<'_, CStr>) -> bool {
+        **self != **other
+    }
+}
+
 #[stable(feature = "cstring_asref", since = "1.7.0")]
 impl ops::Index<ops::RangeFull> for CString {
     type Output = CStr;
@@ -1181,6 +1221,75 @@ impl CStr {
     }
 }
 
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CString> for CStr {
+    #[inline]
+    fn eq(&self, other: &CString) -> bool {
+        *self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CString) -> bool {
+        *self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<Cow<'_, Self>> for CStr {
+    #[inline]
+    fn eq(&self, other: &Cow<'_, Self>) -> bool {
+        *self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &Cow<'_, Self>) -> bool {
+        *self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CStr> for Cow<'_, CStr> {
+    #[inline]
+    fn eq(&self, other: &CStr) -> bool {
+        **self == *other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CStr) -> bool {
+        **self != *other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<&CStr> for Cow<'_, CStr> {
+    #[inline]
+    fn eq(&self, other: &&CStr) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &&CStr) -> bool {
+        **self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CString> for Cow<'_, CStr> {
+    #[inline]
+    fn eq(&self, other: &CString) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CString) -> bool {
+        **self != **other
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl core::error::Error for NulError {
     #[allow(deprecated)]
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index f7a21072f53..1d2e13db218 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -660,6 +660,19 @@ impl CStr {
     }
 }
 
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<&Self> for CStr {
+    #[inline]
+    fn eq(&self, other: &&Self) -> bool {
+        *self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &&Self) -> bool {
+        *self != **other
+    }
+}
+
 // `.to_bytes()` representations are compared instead of the inner `[c_char]`s,
 // because `c_char` is `i8` (not `u8`) on some platforms.
 // That is why this is implemented manually and not derived.
@@ -670,6 +683,7 @@ impl PartialOrd for CStr {
         self.to_bytes().partial_cmp(&other.to_bytes())
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Ord for CStr {
     #[inline]
diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs
index e9765f911a2..0072a95e8df 100644
--- a/library/core/src/iter/adapters/fuse.rs
+++ b/library/core/src/iter/adapters/fuse.rs
@@ -198,8 +198,30 @@ impl<I: Default> Default for Fuse<I> {
     /// let iter: Fuse<slice::Iter<'_, u8>> = Default::default();
     /// assert_eq!(iter.len(), 0);
     /// ```
+    ///
+    /// This is equivalent to `I::default().fuse()`[^fuse_note]; e.g. if
+    /// `I::default()` is not an empty iterator, then this will not be
+    /// an empty iterator.
+    ///
+    /// ```
+    /// # use std::iter::Fuse;
+    /// #[derive(Default)]
+    /// struct Fourever;
+    ///
+    /// impl Iterator for Fourever {
+    ///     type Item = u32;
+    ///     fn next(&mut self) -> Option<u32> {
+    ///         Some(4)
+    ///     }
+    /// }
+    ///
+    /// let mut iter: Fuse<Fourever> = Default::default();
+    /// assert_eq!(iter.next(), Some(4));
+    /// ```
+    ///
+    /// [^fuse_note]: if `I` does not override `Iterator::fuse`'s default implementation
     fn default() -> Self {
-        Fuse { iter: Default::default() }
+        Fuse { iter: Some(I::default()) }
     }
 }
 
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index d7b2ec81555..8035dccc632 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1109,45 +1109,6 @@ pub(crate) mod builtin {
         ($name:expr $(,)?) => {{ /* compiler built-in */ }};
     }
 
-    /// Concatenates identifiers into one identifier.
-    ///
-    /// This macro takes any number of comma-separated identifiers, and
-    /// concatenates them all into one, yielding an expression which is a new
-    /// identifier. Note that hygiene makes it such that this macro cannot
-    /// capture local variables. Also, as a general rule, macros are only
-    /// allowed in item, statement or expression position. That means while
-    /// you may use this macro for referring to existing variables, functions or
-    /// modules etc, you cannot define a new one with it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(concat_idents)]
-    ///
-    /// # fn main() {
-    /// fn foobar() -> u32 { 23 }
-    ///
-    /// let f = concat_idents!(foo, bar);
-    /// println!("{}", f());
-    ///
-    /// // fn concat_idents!(new, fun, name) { } // not usable in this way!
-    /// # }
-    /// ```
-    #[unstable(
-        feature = "concat_idents",
-        issue = "29599",
-        reason = "`concat_idents` is not stable enough for use and is subject to change"
-    )]
-    #[deprecated(
-        since = "1.88.0",
-        note = "use `${concat(...)}` with the `macro_metavar_expr_concat` feature instead"
-    )]
-    #[rustc_builtin_macro]
-    #[macro_export]
-    macro_rules! concat_idents {
-        ($($e:ident),+ $(,)?) => {{ /* compiler built-in */ }};
-    }
-
     /// Concatenates literals into a byte slice.
     ///
     /// This macro takes any number of comma-separated literals, and concatenates them all into
diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs
index f9638fea225..55fdacb014e 100644
--- a/library/core/src/marker/variance.rs
+++ b/library/core/src/marker/variance.rs
@@ -18,7 +18,7 @@ macro_rules! phantom_type {
         pub struct $name:ident <$t:ident> ($($inner:tt)*);
     )*) => {$(
         $(#[$attr])*
-        pub struct $name<$t>($($inner)*) where T: ?Sized;
+        pub struct $name<$t>($($inner)*) where $t: ?Sized;
 
         impl<T> $name<T>
             where T: ?Sized
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 8f1b5275871..7b9e04920d5 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -58,10 +58,9 @@ pub use crate::fmt::macros::Debug;
 pub use crate::hash::macros::Hash;
 
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated)]
 #[doc(no_inline)]
 pub use crate::{
-    assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
+    assert, cfg, column, compile_error, concat, env, file, format_args,
     format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
     stringify, trace_macros,
 };
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 5051b2288fd..d250e1478d8 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -1495,6 +1495,9 @@ impl str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
+    /// If there are no matches the full string slice is returned as the only
+    /// item in the iterator.
+    ///
     /// [`char`]: prim@char
     /// [pattern]: self::pattern
     ///
@@ -1526,6 +1529,9 @@ impl str {
     /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
     /// assert_eq!(v, ["lion", "tiger", "leopard"]);
     ///
+    /// let v: Vec<&str> = "AABBCC".split("DD").collect();
+    /// assert_eq!(v, ["AABBCC"]);
+    ///
     /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
     /// assert_eq!(v, ["abc", "def", "ghi"]);
     ///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 2bb7a63772d..13fb08a9210 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -281,7 +281,6 @@
 #![feature(cfg_target_thread_local)]
 #![feature(cfi_encoding)]
 #![feature(char_max_len)]
-#![feature(concat_idents)]
 #![feature(core_float_math)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
@@ -717,10 +716,9 @@ pub use core::primitive;
 pub use core::todo;
 // Re-export built-in macros defined through core.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated)]
 pub use core::{
-    assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
-    env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
+    assert, assert_matches, cfg, column, compile_error, concat, const_format_args, env, file,
+    format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
     module_path, option_env, stringify, trace_macros,
 };
 // Re-export macros defined in core.
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 6a951426407..10685b49319 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -53,6 +53,12 @@ use crate::time::Duration;
 ///     Ok(())
 /// } // the stream is closed here
 /// ```
+///
+/// # Platform-specific Behavior
+///
+/// On Unix, writes to the underlying socket in `SOCK_STREAM` mode are made with
+/// `MSG_NOSIGNAL` flag. This suppresses the emission of the  `SIGPIPE` signal when writing
+/// to disconnected socket. In some cases, getting a `SIGPIPE` would trigger process termination.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct TcpStream(net_imp::TcpStream);
 
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 1bd3bab5e37..035768a6fab 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -1,3 +1,18 @@
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux", target_os = "android",
+        target_os = "hurd",
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris", target_os = "illumos",
+        target_os = "haiku", target_os = "nto",
+        target_os = "cygwin"))] {
+        use libc::MSG_NOSIGNAL;
+    } else {
+        const MSG_NOSIGNAL: core::ffi::c_int = 0x0;
+    }
+}
+
 use super::{SocketAddr, sockaddr_un};
 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
 use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to};
@@ -41,6 +56,12 @@ use crate::time::Duration;
 ///     Ok(())
 /// }
 /// ```
+///
+/// # `SIGPIPE`
+///
+/// Writes to the underlying socket in `SOCK_STREAM` mode are made with `MSG_NOSIGNAL` flag.
+/// This suppresses the emission of the  `SIGPIPE` signal when writing to disconnected socket.
+/// In some cases getting a `SIGPIPE` would trigger process termination.
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub struct UnixStream(pub(super) Socket);
 
@@ -633,7 +654,7 @@ impl io::Write for UnixStream {
 #[stable(feature = "unix_socket", since = "1.10.0")]
 impl<'a> io::Write for &'a UnixStream {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
+        self.0.send_with_flags(buf, MSG_NOSIGNAL)
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index c15d8c40085..69f03353153 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -45,10 +45,9 @@ pub use crate::result::Result::{self, Err, Ok};
 
 // Re-exported built-in macros
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated)]
 #[doc(no_inline)]
 pub use core::prelude::v1::{
-    assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
+    assert, cfg, column, compile_error, concat, env, file, format_args,
     format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
     stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
 };
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index b35d5d2aa84..b2a4961c3c5 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -281,6 +281,14 @@ impl Socket {
         self.0.duplicate().map(Socket)
     }
 
+    pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            libc::send(self.as_raw_fd(), buf.as_ptr() as *const c_void, len, flags)
+        })?;
+        Ok(ret as usize)
+    }
+
     fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
         let ret = cvt(unsafe {
             libc::recv(
diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs
index a4d29e66f38..5f001f0f532 100644
--- a/library/std/src/sys/random/uefi.rs
+++ b/library/std/src/sys/random/uefi.rs
@@ -1,27 +1,158 @@
-use r_efi::protocols::rng;
+pub fn fill_bytes(bytes: &mut [u8]) {
+    // Handle zero-byte request
+    if bytes.is_empty() {
+        return;
+    }
+
+    // Try EFI_RNG_PROTOCOL
+    if rng_protocol::fill_bytes(bytes) {
+        return;
+    }
 
-use crate::sys::pal::helpers;
+    // Fallback to rdrand if rng protocol missing.
+    //
+    // For real-world example, see [issue-13825](https://github.com/rust-lang/rust/issues/138252#issuecomment-2891270323)
+    #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
+    if rdrand::fill_bytes(bytes) {
+        return;
+    }
 
-pub fn fill_bytes(bytes: &mut [u8]) {
-    let handles =
-        helpers::locate_handles(rng::PROTOCOL_GUID).expect("failed to generate random data");
-    for handle in handles {
-        if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
-            let r = unsafe {
-                ((*protocol.as_ptr()).get_rng)(
-                    protocol.as_ptr(),
-                    crate::ptr::null_mut(),
-                    bytes.len(),
-                    bytes.as_mut_ptr(),
-                )
+    panic!("failed to generate random data");
+}
+
+mod rng_protocol {
+    use r_efi::protocols::rng;
+
+    use crate::sys::pal::helpers;
+
+    pub(crate) fn fill_bytes(bytes: &mut [u8]) -> bool {
+        if let Ok(handles) = helpers::locate_handles(rng::PROTOCOL_GUID) {
+            for handle in handles {
+                if let Ok(protocol) =
+                    helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID)
+                {
+                    let r = unsafe {
+                        ((*protocol.as_ptr()).get_rng)(
+                            protocol.as_ptr(),
+                            crate::ptr::null_mut(),
+                            bytes.len(),
+                            bytes.as_mut_ptr(),
+                        )
+                    };
+                    if r.is_error() {
+                        continue;
+                    } else {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        false
+    }
+}
+
+/// Port from [getrandom](https://github.com/rust-random/getrandom/blob/master/src/backends/rdrand.rs)
+#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
+mod rdrand {
+    cfg_if::cfg_if! {
+        if #[cfg(target_arch = "x86_64")] {
+            use crate::arch::x86_64 as arch;
+            use arch::_rdrand64_step as rdrand_step;
+            type Word = u64;
+        } else if #[cfg(target_arch = "x86")] {
+            use crate::arch::x86 as arch;
+            use arch::_rdrand32_step as rdrand_step;
+            type Word = u32;
+        }
+    }
+
+    static RDRAND_GOOD: crate::sync::LazyLock<bool> = crate::sync::LazyLock::new(is_rdrand_good);
+
+    // Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
+    // Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
+    // Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
+    const RETRY_LIMIT: usize = 10;
+
+    unsafe fn rdrand() -> Option<Word> {
+        for _ in 0..RETRY_LIMIT {
+            let mut val = 0;
+            if unsafe { rdrand_step(&mut val) } == 1 {
+                return Some(val);
+            }
+        }
+        None
+    }
+
+    // Run a small self-test to make sure we aren't repeating values
+    // Adapted from Linux's test in arch/x86/kernel/cpu/rdrand.c
+    // Fails with probability < 2^(-90) on 32-bit systems
+    unsafe fn self_test() -> bool {
+        // On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision.
+        let mut prev = Word::MAX;
+        let mut fails = 0;
+        for _ in 0..8 {
+            match unsafe { rdrand() } {
+                Some(val) if val == prev => fails += 1,
+                Some(val) => prev = val,
+                None => return false,
             };
-            if r.is_error() {
-                continue;
-            } else {
-                return;
+        }
+        fails <= 2
+    }
+
+    fn is_rdrand_good() -> bool {
+        #[cfg(not(target_feature = "rdrand"))]
+        {
+            // SAFETY: All Rust x86 targets are new enough to have CPUID, and we
+            // check that leaf 1 is supported before using it.
+            let cpuid0 = unsafe { arch::__cpuid(0) };
+            if cpuid0.eax < 1 {
+                return false;
+            }
+            let cpuid1 = unsafe { arch::__cpuid(1) };
+
+            let vendor_id =
+                [cpuid0.ebx.to_le_bytes(), cpuid0.edx.to_le_bytes(), cpuid0.ecx.to_le_bytes()];
+            if vendor_id == [*b"Auth", *b"enti", *b"cAMD"] {
+                let mut family = (cpuid1.eax >> 8) & 0xF;
+                if family == 0xF {
+                    family += (cpuid1.eax >> 20) & 0xFF;
+                }
+                // AMD CPUs families before 17h (Zen) sometimes fail to set CF when
+                // RDRAND fails after suspend. Don't use RDRAND on those families.
+                // See https://bugzilla.redhat.com/show_bug.cgi?id=1150286
+                if family < 0x17 {
+                    return false;
+                }
+            }
+
+            const RDRAND_FLAG: u32 = 1 << 30;
+            if cpuid1.ecx & RDRAND_FLAG == 0 {
+                return false;
             }
         }
+
+        // SAFETY: We have already checked that rdrand is available.
+        unsafe { self_test() }
     }
 
-    panic!("failed to generate random data");
+    unsafe fn rdrand_exact(dest: &mut [u8]) -> Option<()> {
+        let mut chunks = dest.array_chunks_mut();
+        for chunk in &mut chunks {
+            *chunk = unsafe { rdrand() }?.to_ne_bytes();
+        }
+
+        let tail = chunks.into_remainder();
+        let n = tail.len();
+        if n > 0 {
+            let src = unsafe { rdrand() }?.to_ne_bytes();
+            tail.copy_from_slice(&src[..n]);
+        }
+        Some(())
+    }
+
+    pub(crate) fn fill_bytes(bytes: &mut [u8]) -> bool {
+        if *RDRAND_GOOD { unsafe { rdrand_exact(bytes).is_some() } } else { false }
+    }
 }
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 0e3c3aaee0f..99044e2a253 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -683,6 +683,7 @@ impl Builder<'_> {
                         .arg("--print=file-names")
                         .arg("--crate-type=proc-macro")
                         .arg("-")
+                        .stdin(std::process::Stdio::null())
                         .run_capture(self)
                         .stderr();
 
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index eb9802bf2e1..78b28ac1828 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -119,6 +119,11 @@ impl<'a> BootstrapCommand {
         self
     }
 
+    pub fn stdin(&mut self, stdin: std::process::Stdio) -> &mut Self {
+        self.command.stdin(stdin);
+        self
+    }
+
     #[must_use]
     pub fn delay_failure(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self }
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile
index a877de1f7b2..9bdcf00dccc 100644
--- a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile
@@ -39,7 +39,6 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 
 COPY host-x86_64/mingw-check-1/check-default-config-profiles.sh /scripts/
 COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
-COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/
 
 # Check library crates on all tier 1 targets.
 # We disable optimized compiler built-ins because that requires a C toolchain for the target.
@@ -52,7 +51,6 @@ ENV SCRIPT \
            python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
            python3 ../x.py check --stage 1 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
            /scripts/validate-toolstate.sh && \
-           /scripts/validate-error-codes.sh && \
            reuse --include-submodules lint && \
            python3 ../x.py test collect-license-metadata && \
            # Runs checks to ensure that there are no issues in our JS code.
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh b/src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh
deleted file mode 100755
index e9aa948eb87..00000000000
--- a/src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-# Checks that no error code explanation is removed.
-
-set -eo pipefail
-
-if [[ -z "$BASE_COMMIT" ]]; then
-    echo "not checking error code explanations removal"
-    exit 0
-fi
-
-echo "Check if an error code explanation was removed..."
-
-if (git diff "$BASE_COMMIT" --name-status | grep '^D' \
-        | grep --quiet "compiler/rustc_error_codes/src/error_codes/"); then
-    echo "Error code explanations should never be removed!"
-    echo "Take a look at E0001 to see how to handle it."
-    exit 1
-fi
-
-echo "No error code explanation was removed!"
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index 8d2c5e004e4..62cd8a31212 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -39,7 +39,6 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
     && pip3 install virtualenv
 
 COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
-COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/
 
 RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)'
 
diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
index b6dbdb14407..7eb5dca532f 100644
--- a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
+++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
@@ -8,7 +8,8 @@ In stable Rust, there is no way to create new identifiers by joining identifiers
  `#![feature(macro_metavar_expr_concat)]` introduces a way to do this, using the concat metavariable expression.
 
 > This feature uses the syntax from [`macro_metavar_expr`] but is otherwise
-> independent. It replaces the old unstable feature [`concat_idents`].
+> independent. It replaces the since-removed unstable feature
+> [`concat_idents`].
 
 > This is an experimental feature; it and its syntax will require a RFC before stabilization.
 
@@ -126,8 +127,7 @@ test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; fini
 
 [`paste`]: https://crates.io/crates/paste
 [RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html
-[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html
 [`macro_metavar_expr`]: ../language-features/macro-metavar-expr.md
-[`concat_idents`]: ../library-features/concat-idents.md
+[`concat_idents`]: https://github.com/rust-lang/rust/issues/29599
 [#124225]: https://github.com/rust-lang/rust/issues/124225
 [declarative macros]: https://doc.rust-lang.org/stable/reference/macros-by-example.html
diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md
deleted file mode 100644
index 8a38d155e3d..00000000000
--- a/src/doc/unstable-book/src/library-features/concat-idents.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# `concat_idents`
-
-The tracking issue for this feature is: [#29599]
-
-This feature is deprecated, to be replaced by [`macro_metavar_expr_concat`].
-
-[#29599]: https://github.com/rust-lang/rust/issues/29599
-[`macro_metavar_expr_concat`]: https://github.com/rust-lang/rust/issues/124225
-
-------------------------
-
-> This feature is expected to be superseded by [`macro_metavar_expr_concat`](../language-features/macro-metavar-expr-concat.md).
-
-The `concat_idents` feature adds a macro for concatenating multiple identifiers
-into one identifier.
-
-## Examples
-
-```rust
-#![feature(concat_idents)]
-
-fn main() {
-    fn foobar() -> u32 { 23 }
-    let f = concat_idents!(foo, bar);
-    assert_eq!(f(), 23);
-}
-```
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 0aedc7f5219..69899539b45 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -753,7 +753,8 @@ impl Item {
             .other_attrs
             .iter()
             .filter_map(|attr| {
-                // NoMangle is special-cased because cargo-semver-checks uses it
+                // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
+                // It is also used by cargo-semver-checks.
                 if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) {
                     Some("#[no_mangle]".to_string())
                 } else if is_json {
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index f93aa8ffd0d..986390dbaa0 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::DiagCtxtHandle;
 use rustc_session::config::{
     self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns,
-    OptionsTargetModifiers, UnstableOptions, get_cmd_lint_options, nightly_options,
+    OptionsTargetModifiers, Sysroot, UnstableOptions, get_cmd_lint_options, nightly_options,
     parse_crate_types_from_list, parse_externs, parse_target_triple,
 };
 use rustc_session::lint::Level;
@@ -103,9 +103,7 @@ pub(crate) struct Options {
     /// compiling doctests from the crate.
     pub(crate) edition: Edition,
     /// The path to the sysroot. Used during the compilation process.
-    pub(crate) sysroot: PathBuf,
-    /// Has the same value as `sysroot` except is `None` when the user didn't pass `---sysroot`.
-    pub(crate) maybe_sysroot: Option<PathBuf>,
+    pub(crate) sysroot: Sysroot,
     /// Lint information passed over the command-line.
     pub(crate) lint_opts: Vec<(String, Level)>,
     /// Whether to ask rustc to describe the lints it knows.
@@ -201,7 +199,6 @@ impl fmt::Debug for Options {
             .field("target", &self.target)
             .field("edition", &self.edition)
             .field("sysroot", &self.sysroot)
-            .field("maybe_sysroot", &self.maybe_sysroot)
             .field("lint_opts", &self.lint_opts)
             .field("describe_lints", &self.describe_lints)
             .field("lint_cap", &self.lint_cap)
@@ -725,16 +722,14 @@ impl Options {
         }
 
         let target = parse_target_triple(early_dcx, matches);
-        let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
-
-        let sysroot = rustc_session::filesearch::materialize_sysroot(maybe_sysroot.clone());
+        let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
 
         let libs = matches
             .opt_strs("L")
             .iter()
             .map(|s| {
                 SearchPath::from_cli_opt(
-                    &sysroot,
+                    sysroot.path(),
                     &target,
                     early_dcx,
                     s,
@@ -827,7 +822,6 @@ impl Options {
             target,
             edition,
             sysroot,
-            maybe_sysroot,
             lint_opts,
             describe_lints,
             lint_cap,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 130fdff1afe..1b5c9fd4664 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -514,8 +514,9 @@ fn run_test(
 
     compiler_args.push(format!("@{}", doctest.global_opts.args_file.display()));
 
-    if let Some(sysroot) = &rustdoc_options.maybe_sysroot {
-        compiler_args.push(format!("--sysroot={}", sysroot.display()));
+    let sysroot = &rustdoc_options.sysroot;
+    if let Some(explicit_sysroot) = &sysroot.explicit {
+        compiler_args.push(format!("--sysroot={}", explicit_sysroot.display()));
     }
 
     compiler_args.extend_from_slice(&["--edition".to_owned(), doctest.edition.to_string()]);
@@ -574,7 +575,7 @@ fn run_test(
     let rustc_binary = rustdoc_options
         .test_builder
         .as_deref()
-        .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
+        .unwrap_or_else(|| rustc_interface::util::rustc_path(sysroot).expect("found rustc"));
     let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
 
     compiler.args(&compiler_args);
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 7b1a61a3ffa..2de8f836da3 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1,6 +1,6 @@
 // Local js definitions:
 /* global addClass, getSettingValue, hasClass, updateLocalStorage */
-/* global onEachLazy, removeClass, getVar */
+/* global onEachLazy, removeClass, getVar, nonnull */
 
 "use strict";
 
@@ -2138,3 +2138,31 @@ function preLoadCss(cssUrl) {
         elem.addEventListener("click", showHideCodeExampleButtons);
     });
 }());
+
+// This section is a bugfix for firefox: when copying text with `user-select: none`, it adds
+// extra backline characters.
+//
+// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464
+// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
+(function() {
+    document.body.addEventListener("copy", event => {
+        let target = nonnull(event.target);
+        let isInsideCode = false;
+        while (target && target !== document.body) {
+            // @ts-expect-error
+            if (target.tagName === "CODE") {
+                isInsideCode = true;
+                break;
+            }
+            // @ts-expect-error
+            target = target.parentElement;
+        }
+        if (!isInsideCode) {
+            return;
+        }
+        const selection = document.getSelection();
+         // @ts-expect-error
+        nonnull(event.clipboardData).setData("text/plain", selection.toString());
+        event.preventDefault();
+    });
+}());
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 0778b5b56f5..f51b35097f6 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -194,22 +194,25 @@ impl FromClean<attrs::Deprecation> for Deprecation {
 }
 
 impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
-    fn from_clean(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
+    fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
         use clean::GenericArgs::*;
-        if args.is_empty() {
-            return None;
-        }
-        Some(Box::new(match args {
-            AngleBracketed { args, constraints } => GenericArgs::AngleBracketed {
-                args: args.into_json(renderer),
-                constraints: constraints.into_json(renderer),
-            },
-            Parenthesized { inputs, output } => GenericArgs::Parenthesized {
+        match generic_args {
+            AngleBracketed { args, constraints } => {
+                if generic_args.is_empty() {
+                    None
+                } else {
+                    Some(Box::new(GenericArgs::AngleBracketed {
+                        args: args.into_json(renderer),
+                        constraints: constraints.into_json(renderer),
+                    }))
+                }
+            }
+            Parenthesized { inputs, output } => Some(Box::new(GenericArgs::Parenthesized {
                 inputs: inputs.into_json(renderer),
                 output: output.into_json(renderer),
-            },
-            ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
-        }))
+            })),
+            ReturnTypeNotation => Some(Box::new(GenericArgs::ReturnTypeNotation)),
+        }
     }
 }
 
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index b5a2b7feac9..9fa26305f6b 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -16,6 +16,8 @@ pub enum ErrorKind {
     Suggestion,
     Warning,
     Raw,
+    /// Used for better recovery and diagnostics in compiletest.
+    Unknown,
 }
 
 impl ErrorKind {
@@ -31,21 +33,25 @@ impl ErrorKind {
 
     /// Either the canonical uppercase string, or some additional versions for compatibility.
     /// FIXME: consider keeping only the canonical versions here.
-    pub fn from_user_str(s: &str) -> ErrorKind {
-        match s {
+    fn from_user_str(s: &str) -> Option<ErrorKind> {
+        Some(match s {
             "HELP" | "help" => ErrorKind::Help,
             "ERROR" | "error" => ErrorKind::Error,
-            // `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct,
-            // but those tests never use the error kind later on.
-            "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note,
+            "NOTE" | "note" => ErrorKind::Note,
             "SUGGESTION" => ErrorKind::Suggestion,
             "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
             "RAW" => ErrorKind::Raw,
-            _ => panic!(
+            _ => return None,
+        })
+    }
+
+    pub fn expect_from_user_str(s: &str) -> ErrorKind {
+        ErrorKind::from_user_str(s).unwrap_or_else(|| {
+            panic!(
                 "unexpected diagnostic kind `{s}`, expected \
-                 `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
-            ),
-        }
+                 `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` or `RAW`"
+            )
+        })
     }
 }
 
@@ -58,6 +64,7 @@ impl fmt::Display for ErrorKind {
             ErrorKind::Suggestion => write!(f, "SUGGESTION"),
             ErrorKind::Warning => write!(f, "WARN"),
             ErrorKind::Raw => write!(f, "RAW"),
+            ErrorKind::Unknown => write!(f, "UNKNOWN"),
         }
     }
 }
@@ -65,6 +72,7 @@ impl fmt::Display for ErrorKind {
 #[derive(Debug)]
 pub struct Error {
     pub line_num: Option<usize>,
+    pub column_num: Option<usize>,
     /// What kind of message we expect (e.g., warning, error, suggestion).
     pub kind: ErrorKind,
     pub msg: String,
@@ -74,17 +82,6 @@ pub struct Error {
     pub require_annotation: bool,
 }
 
-impl Error {
-    pub fn render_for_expected(&self) -> String {
-        use colored::Colorize;
-        format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan())
-    }
-
-    pub fn line_num_str(&self) -> String {
-        self.line_num.map_or("?".to_string(), |line_num| line_num.to_string())
-    }
-}
-
 /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
 /// The former is a "follow" that inherits its target from the preceding line;
 /// the latter is an "adjusts" that goes that many lines up.
@@ -168,8 +165,10 @@ fn parse_expected(
     let rest = line[tag.end()..].trim_start();
     let (kind_str, _) =
         rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
-    let kind = ErrorKind::from_user_str(kind_str);
-    let untrimmed_msg = &rest[kind_str.len()..];
+    let (kind, untrimmed_msg) = match ErrorKind::from_user_str(kind_str) {
+        Some(kind) => (kind, &rest[kind_str.len()..]),
+        None => (ErrorKind::Unknown, rest),
+    };
     let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
 
     let line_num_adjust = &captures["adjust"];
@@ -182,6 +181,7 @@ fn parse_expected(
     } else {
         (false, Some(line_num - line_num_adjust.len()))
     };
+    let column_num = Some(tag.start() + 1);
 
     debug!(
         "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
@@ -191,7 +191,7 @@ fn parse_expected(
         kind,
         msg
     );
-    Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
+    Some((follow_prev, Error { line_num, column_num, kind, msg, require_annotation: true }))
 }
 
 #[cfg(test)]
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 8bee9caacc9..2b203bb309c 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -593,7 +593,7 @@ impl TestProps {
                         config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
                     {
                         self.dont_require_annotations
-                            .insert(ErrorKind::from_user_str(err_kind.trim()));
+                            .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
                     }
                 },
             );
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 6ed2b52c66d..a8e6416e56c 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -36,9 +36,7 @@ struct UnusedExternNotification {
 struct DiagnosticSpan {
     file_name: String,
     line_start: usize,
-    line_end: usize,
     column_start: usize,
-    column_end: usize,
     is_primary: bool,
     label: Option<String>,
     suggested_replacement: Option<String>,
@@ -148,6 +146,7 @@ pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
             Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
             Err(_) => errors.push(Error {
                 line_num: None,
+                column_num: None,
                 kind: ErrorKind::Raw,
                 msg: line.to_string(),
                 require_annotation: false,
@@ -193,25 +192,9 @@ fn push_actual_errors(
     // also ensure that `//~ ERROR E123` *always* works. The
     // assumption is that these multi-line error messages are on their
     // way out anyhow.
-    let with_code = |span: Option<&DiagnosticSpan>, text: &str| {
-        // FIXME(#33000) -- it'd be better to use a dedicated
-        // UI harness than to include the line/col number like
-        // this, but some current tests rely on it.
-        //
-        // Note: Do NOT include the filename. These can easily
-        // cause false matches where the expected message
-        // appears in the filename, and hence the message
-        // changes but the test still passes.
-        let span_str = match span {
-            Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => {
-                format!("{line_start}:{column_start}: {line_end}:{column_end}")
-            }
-            None => format!("?:?: ?:?"),
-        };
-        match &diagnostic.code {
-            Some(code) => format!("{span_str}: {text} [{}]", code.code),
-            None => format!("{span_str}: {text}"),
-        }
+    let with_code = |text| match &diagnostic.code {
+        Some(code) => format!("{text} [{}]", code.code),
+        None => format!("{text}"),
     };
 
     // Convert multi-line messages into multiple errors.
@@ -225,8 +208,9 @@ fn push_actual_errors(
             || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
         errors.push(Error {
             line_num: None,
+            column_num: None,
             kind,
-            msg: with_code(None, first_line),
+            msg: with_code(first_line),
             require_annotation: diagnostic.level != "failure-note"
                 && !RE.get_or_init(re_init).is_match(first_line),
         });
@@ -234,8 +218,9 @@ fn push_actual_errors(
         for span in primary_spans {
             errors.push(Error {
                 line_num: Some(span.line_start),
+                column_num: Some(span.column_start),
                 kind,
-                msg: with_code(Some(span), first_line),
+                msg: with_code(first_line),
                 require_annotation: true,
             });
         }
@@ -244,16 +229,18 @@ fn push_actual_errors(
         if primary_spans.is_empty() {
             errors.push(Error {
                 line_num: None,
+                column_num: None,
                 kind,
-                msg: with_code(None, next_line),
+                msg: with_code(next_line),
                 require_annotation: false,
             });
         } else {
             for span in primary_spans {
                 errors.push(Error {
                     line_num: Some(span.line_start),
+                    column_num: Some(span.column_start),
                     kind,
-                    msg: with_code(Some(span), next_line),
+                    msg: with_code(next_line),
                     require_annotation: false,
                 });
             }
@@ -266,6 +253,7 @@ fn push_actual_errors(
             for (index, line) in suggested_replacement.lines().enumerate() {
                 errors.push(Error {
                     line_num: Some(span.line_start + index),
+                    column_num: Some(span.column_start),
                     kind: ErrorKind::Suggestion,
                     msg: line.to_string(),
                     // Empty suggestions (suggestions to remove something) are common
@@ -288,6 +276,7 @@ fn push_actual_errors(
         if let Some(label) = &span.label {
             errors.push(Error {
                 line_num: Some(span.line_start),
+                column_num: Some(span.column_start),
                 kind: ErrorKind::Note,
                 msg: label.clone(),
                 // Empty labels (only underlining spans) are common and do not need annotations.
@@ -310,6 +299,7 @@ fn push_backtrace(
     if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
         errors.push(Error {
             line_num: Some(expansion.span.line_start),
+            column_num: Some(expansion.span.column_start),
             kind: ErrorKind::Note,
             msg: format!("in this expansion of {}", expansion.macro_decl_name),
             require_annotation: true,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 42c851ea999..980e89889ab 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -11,7 +11,7 @@ use std::{env, iter, str};
 
 use build_helper::fs::remove_and_create_dir_all;
 use camino::{Utf8Path, Utf8PathBuf};
-use colored::Colorize;
+use colored::{Color, Colorize};
 use regex::{Captures, Regex};
 use tracing::*;
 
@@ -677,9 +677,6 @@ impl<'test> TestCx<'test> {
             return;
         }
 
-        // On Windows, translate all '\' path separators to '/'
-        let file_name = self.testpaths.file.to_string().replace(r"\", "/");
-
         // On Windows, keep all '\' path separators to match the paths reported in the JSON output
         // from the compiler
         let diagnostic_file_name = if self.props.remap_src_base {
@@ -704,6 +701,7 @@ impl<'test> TestCx<'test> {
             .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e });
 
         let mut unexpected = Vec::new();
+        let mut unimportant = Vec::new();
         let mut found = vec![false; expected_errors.len()];
         for actual_error in actual_errors {
             for pattern in &self.props.error_patterns {
@@ -738,14 +736,9 @@ impl<'test> TestCx<'test> {
                         && expected_kinds.contains(&actual_error.kind)
                         && !self.props.dont_require_annotations.contains(&actual_error.kind)
                     {
-                        self.error(&format!(
-                            "{}:{}: unexpected {}: '{}'",
-                            file_name,
-                            actual_error.line_num_str(),
-                            actual_error.kind,
-                            actual_error.msg
-                        ));
                         unexpected.push(actual_error);
+                    } else {
+                        unimportant.push(actual_error);
                     }
                 }
             }
@@ -755,39 +748,140 @@ impl<'test> TestCx<'test> {
         // anything not yet found is a problem
         for (index, expected_error) in expected_errors.iter().enumerate() {
             if !found[index] {
-                self.error(&format!(
-                    "{}:{}: expected {} not found: {}",
-                    file_name,
-                    expected_error.line_num_str(),
-                    expected_error.kind,
-                    expected_error.msg
-                ));
                 not_found.push(expected_error);
             }
         }
 
         if !unexpected.is_empty() || !not_found.is_empty() {
             self.error(&format!(
-                "{} unexpected errors found, {} expected errors not found",
+                "{} unexpected diagnostics reported, {} expected diagnostics not reported",
                 unexpected.len(),
                 not_found.len()
             ));
-            println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline);
+
+            // Emit locations in a format that is short (relative paths) but "clickable" in editors.
+            // Also normalize path separators to `/`.
+            let file_name = self
+                .testpaths
+                .file
+                .strip_prefix(self.config.src_root.as_str())
+                .unwrap_or(&self.testpaths.file)
+                .to_string()
+                .replace(r"\", "/");
+            let line_str = |e: &Error| {
+                let line_num = e.line_num.map_or("?".to_string(), |line_num| line_num.to_string());
+                // `file:?:NUM` may be confusing to editors and unclickable.
+                let opt_col_num = match e.column_num {
+                    Some(col_num) if line_num != "?" => format!(":{col_num}"),
+                    _ => "".to_string(),
+                };
+                format!("{file_name}:{line_num}{opt_col_num}")
+            };
+            let print_error = |e| println!("{}: {}: {}", line_str(e), e.kind, e.msg.cyan());
+            let push_suggestion =
+                |suggestions: &mut Vec<_>, e: &Error, kind, line, msg, color, rank| {
+                    let mut ret = String::new();
+                    if kind {
+                        ret += &format!("{} {}", "with kind".color(color), e.kind);
+                    }
+                    if line {
+                        if !ret.is_empty() {
+                            ret.push(' ');
+                        }
+                        ret += &format!("{} {}", "on line".color(color), line_str(e));
+                    }
+                    if msg {
+                        if !ret.is_empty() {
+                            ret.push(' ');
+                        }
+                        ret += &format!("{} {}", "with message".color(color), e.msg.cyan());
+                    }
+                    suggestions.push((ret, rank));
+                };
+            let show_suggestions = |mut suggestions: Vec<_>, prefix: &str, color| {
+                // Only show suggestions with the highest rank.
+                suggestions.sort_by_key(|(_, rank)| *rank);
+                if let Some(&(_, top_rank)) = suggestions.first() {
+                    for (suggestion, rank) in suggestions {
+                        if rank == top_rank {
+                            println!("  {} {suggestion}", prefix.color(color));
+                        }
+                    }
+                }
+            };
+
+            // Fuzzy matching quality:
+            // - message and line / message and kind - great, suggested
+            // - only message - good, suggested
+            // - known line and kind - ok, suggested
+            // - only known line - meh, but suggested
+            // - others are not worth suggesting
             if !unexpected.is_empty() {
-                println!("{}", "--- unexpected errors (from JSON output) ---".green());
+                let header = "--- reported in JSON output but not expected in test file ---";
+                println!("{}", header.green());
                 for error in &unexpected {
-                    println!("{}", error.render_for_expected());
+                    print_error(error);
+                    let mut suggestions = Vec::new();
+                    for candidate in &not_found {
+                        let mut push_red_suggestion = |line, msg, rank| {
+                            push_suggestion(
+                                &mut suggestions,
+                                candidate,
+                                candidate.kind != error.kind,
+                                line,
+                                msg,
+                                Color::Red,
+                                rank,
+                            )
+                        };
+                        if error.msg.contains(&candidate.msg) {
+                            push_red_suggestion(candidate.line_num != error.line_num, false, 0);
+                        } else if candidate.line_num.is_some()
+                            && candidate.line_num == error.line_num
+                        {
+                            push_red_suggestion(false, true, 1);
+                        }
+                    }
+
+                    show_suggestions(suggestions, "expected", Color::Red);
                 }
                 println!("{}", "---".green());
             }
             if !not_found.is_empty() {
-                println!("{}", "--- not found errors (from test file) ---".red());
+                let header = "--- expected in test file but not reported in JSON output ---";
+                println!("{}", header.red());
                 for error in &not_found {
-                    println!("{}", error.render_for_expected());
+                    print_error(error);
+                    let mut suggestions = Vec::new();
+                    for candidate in unexpected.iter().chain(&unimportant) {
+                        let mut push_green_suggestion = |line, msg, rank| {
+                            push_suggestion(
+                                &mut suggestions,
+                                candidate,
+                                candidate.kind != error.kind,
+                                line,
+                                msg,
+                                Color::Green,
+                                rank,
+                            )
+                        };
+                        if candidate.msg.contains(&error.msg) {
+                            push_green_suggestion(candidate.line_num != error.line_num, false, 0);
+                        } else if candidate.line_num.is_some()
+                            && candidate.line_num == error.line_num
+                        {
+                            push_green_suggestion(false, true, 1);
+                        }
+                    }
+
+                    show_suggestions(suggestions, "reported", Color::Green);
                 }
-                println!("{}", "---\n".red());
+                println!("{}", "---".red());
             }
-            panic!("errors differ from expected");
+            panic!(
+                "errors differ from expected\nstatus: {}\ncommand: {}\n",
+                proc_res.status, proc_res.cmdline
+            );
         }
     }
 
@@ -2073,7 +2167,6 @@ impl<'test> TestCx<'test> {
             println!("{}", String::from_utf8_lossy(&output.stdout));
             eprintln!("{}", String::from_utf8_lossy(&output.stderr));
         } else {
-            use colored::Colorize;
             eprintln!("warning: no pager configured, falling back to unified diff");
             eprintln!(
                 "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`"
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 947f815fd69..67d8c351a59 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -83,7 +83,7 @@ pub use run::{cmd, run, run_fail, run_with_args};
 
 /// Helpers for checking target information.
 pub use targets::{
-    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_win7, llvm_components_contain,
+    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_windows_msvc, is_win7, llvm_components_contain,
     target, uname,
 };
 
diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs
index 86edbdf750b..1ab2e2ab2be 100644
--- a/src/tools/run-make-support/src/targets.rs
+++ b/src/tools/run-make-support/src/targets.rs
@@ -28,6 +28,12 @@ pub fn is_windows_gnu() -> bool {
     target().ends_with("windows-gnu")
 }
 
+/// Check if target is windows-msvc.
+#[must_use]
+pub fn is_windows_msvc() -> bool {
+    target().ends_with("windows-msvc")
+}
+
 /// Check if target is win7.
 #[must_use]
 pub fn is_win7() -> bool {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index c618e4bdce7..00408e95ae6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -11,12 +11,12 @@ use syntax::{AstPtr, ast};
 use triomphe::Arc;
 
 use crate::{
-    AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
-    EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
-    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander,
-    MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
-    StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId,
-    TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
+    AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc,
+    EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc,
+    FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc,
+    MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId,
+    ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId,
+    TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
     attr::{Attrs, AttrsWithOwner},
     expr_store::{
         Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
@@ -90,7 +90,10 @@ pub trait InternDatabase: RootQueryDb {
 
     #[salsa::interned]
     fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId;
-    // // endregion: items
+    // endregion: items
+
+    #[salsa::interned]
+    fn intern_block(&self, loc: BlockLoc) -> BlockId;
 }
 
 #[query_group::query_group]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 03683ec9203..efa1374a446 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -11,7 +11,7 @@ use base_db::FxIndexSet;
 use cfg::CfgOptions;
 use either::Either;
 use hir_expand::{
-    HirFileId, InFile, Intern, MacroDefId,
+    HirFileId, InFile, MacroDefId,
     mod_path::tool_path,
     name::{AsName, Name},
     span_map::SpanMapRef,
@@ -2148,7 +2148,7 @@ impl ExprCollector<'_> {
     ) -> ExprId {
         let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
             let ast_id = self.expander.in_file(file_local_id);
-            BlockLoc { ast_id, module: self.module }.intern(self.db)
+            self.db.intern_block(BlockLoc { ast_id, module: self.module })
         });
 
         let (module, def_map) =
@@ -2815,6 +2815,51 @@ impl ExprCollector<'_> {
                 mutability: Mutability::Shared,
             })
         };
+
+        // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
+        // but `format_unsafe_arg` does not
+        let fmt_args =
+            || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatArguments);
+        let fmt_unsafe_arg =
+            || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatUnsafeArg);
+        let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none();
+
+        let idx = if use_format_args_since_1_89_0 {
+            self.collect_format_args_impl(
+                syntax_ptr,
+                fmt,
+                hygiene,
+                argmap,
+                lit_pieces,
+                format_options,
+            )
+        } else {
+            self.collect_format_args_before_1_89_0_impl(
+                syntax_ptr,
+                fmt,
+                argmap,
+                lit_pieces,
+                format_options,
+            )
+        };
+
+        self.source_map
+            .template_map
+            .get_or_insert_with(Default::default)
+            .format_args_to_captures
+            .insert(idx, (hygiene, mappings));
+        idx
+    }
+
+    /// `format_args!` expansion implementation for rustc versions < `1.89.0`
+    fn collect_format_args_before_1_89_0_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+        argmap: FxIndexSet<(usize, ArgumentType)>,
+        lit_pieces: ExprId,
+        format_options: ExprId,
+    ) -> ExprId {
         let arguments = &*fmt.arguments.arguments;
 
         let args = if arguments.is_empty() {
@@ -2902,19 +2947,181 @@ impl ExprCollector<'_> {
             });
         }
 
-        let idx = self.alloc_expr(
+        self.alloc_expr(
             Expr::Call {
                 callee: new_v1_formatted,
                 args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
             },
             syntax_ptr,
-        );
-        self.source_map
-            .template_map
-            .get_or_insert_with(Default::default)
-            .format_args_to_captures
-            .insert(idx, (hygiene, mappings));
-        idx
+        )
+    }
+
+    /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
+    /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
+    fn collect_format_args_impl(
+        &mut self,
+        syntax_ptr: AstPtr<ast::Expr>,
+        fmt: FormatArgs,
+        hygiene: HygieneId,
+        argmap: FxIndexSet<(usize, ArgumentType)>,
+        lit_pieces: ExprId,
+        format_options: ExprId,
+    ) -> ExprId {
+        let arguments = &*fmt.arguments.arguments;
+
+        let (let_stmts, args) = if arguments.is_empty() {
+            (
+                // Generate:
+                //     []
+                vec![],
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                    elements: Box::default(),
+                })),
+            )
+        } else if argmap.len() == 1 && arguments.len() == 1 {
+            // Only one argument, so we don't need to make the `args` tuple.
+            //
+            // Generate:
+            //     super let args = [<core::fmt::Arguments>::new_display(&arg)];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let ref_arg = self.alloc_expr_desugared(Expr::Ref {
+                        expr: arguments[arg_index].expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    });
+                    self.make_argument(ref_arg, ty)
+                })
+                .collect();
+            let args =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_name = Name::new_symbol_root(sym::args);
+            let args_binding =
+                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            // TODO: We don't have `super let` yet.
+            let let_stmt = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args),
+                else_branch: None,
+            };
+            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name))))
+        } else {
+            // Generate:
+            //     super let args = (&arg0, &arg1, &...);
+            let args_name = Name::new_symbol_root(sym::args);
+            let args_binding =
+                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let elements = arguments
+                .iter()
+                .map(|arg| {
+                    self.alloc_expr_desugared(Expr::Ref {
+                        expr: arg.expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    })
+                })
+                .collect();
+            let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
+            // TODO: We don't have `super let` yet
+            let let_stmt1 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(args_tuple),
+                else_branch: None,
+            };
+
+            // Generate:
+            //     super let args = [
+            //         <core::fmt::Argument>::new_display(args.0),
+            //         <core::fmt::Argument>::new_lower_hex(args.1),
+            //         <core::fmt::Argument>::new_debug(args.0),
+            //         …
+            //     ];
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let args_ident_expr =
+                        self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
+                    let arg = self.alloc_expr_desugared(Expr::Field {
+                        expr: args_ident_expr,
+                        name: Name::new_tuple_field(arg_index),
+                    });
+                    self.make_argument(arg, ty)
+                })
+                .collect();
+            let array =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
+            let args_binding =
+                self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene);
+            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
+            self.add_definition_to_binding(args_binding, args_pat);
+            let let_stmt2 = Statement::Let {
+                pat: args_pat,
+                type_ref: None,
+                initializer: Some(array),
+                else_branch: None,
+            };
+            (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
+        };
+
+        // Generate:
+        //     &args
+        let args = self.alloc_expr_desugared(Expr::Ref {
+            expr: args,
+            rawness: Rawness::Ref,
+            mutability: Mutability::Shared,
+        });
+
+        let call_block = {
+            // Generate:
+            //     unsafe {
+            //         <core::fmt::Arguments>::new_v1_formatted(
+            //             lit_pieces,
+            //             args,
+            //             format_options,
+            //         )
+            //     }
+
+            let new_v1_formatted = LangItem::FormatArguments.ty_rel_path(
+                self.db,
+                self.module.krate(),
+                Name::new_symbol_root(sym::new_v1_formatted),
+            );
+            let new_v1_formatted =
+                self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
+            let args = [lit_pieces, args, format_options];
+            let call = self
+                .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
+
+            Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
+        };
+
+        if !let_stmts.is_empty() {
+            // Generate:
+            //     {
+            //         super let …
+            //         super let …
+            //         <core::fmt::Arguments>::new_…(…)
+            //     }
+            let call = self.alloc_expr_desugared(call_block);
+            self.alloc_expr(
+                Expr::Block {
+                    id: None,
+                    statements: let_stmts.into(),
+                    tail: Some(call),
+                    label: None,
+                },
+                syntax_ptr,
+            )
+        } else {
+            self.alloc_expr(call_block, syntax_ptr)
+        }
     }
 
     /// Generate a hir expression for a format_args placeholder specification.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index 29e249b07a7..927e280d739 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -178,14 +178,14 @@ fn main() {
 }
 
 #[test]
-fn desugar_builtin_format_args() {
+fn desugar_builtin_format_args_before_1_89_0() {
     let (db, body, def) = lower(
         r#"
-//- minicore: fmt
+//- minicore: fmt_before_1_89_0
 fn main() {
     let are = "are";
     let count = 10;
-    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
+    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
 }
 "#,
     );
@@ -249,8 +249,11 @@ fn main() {
                         builtin#lang(Count::Implied),
                     ),
                 ],
-                unsafe {
-                    builtin#lang(UnsafeArg::new)()
+                {
+                    ();
+                    unsafe {
+                        builtin#lang(UnsafeArg::new)()
+                    }
                 },
             );
         }"#]]
@@ -258,6 +261,89 @@ fn main() {
 }
 
 #[test]
+fn desugar_builtin_format_args() {
+    let (db, body, def) = lower(
+        r#"
+//- minicore: fmt
+fn main() {
+    let are = "are";
+    let count = 10;
+    builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!");
+}
+"#,
+    );
+
+    expect![[r#"
+        fn main() {
+            let are = "are";
+            let count = 10;
+            {
+                let args = (&"fancy", &(), &"!", &count, &are, );
+                let args = [
+                    builtin#lang(Argument::new_display)(
+                        args.3,
+                    ), builtin#lang(Argument::new_display)(
+                        args.0,
+                    ), builtin#lang(Argument::new_debug)(
+                        args.4,
+                    ), builtin#lang(Argument::new_display)(
+                        args.2,
+                    ),
+                ];
+                unsafe {
+                    builtin#lang(Arguments::new_v1_formatted)(
+                        &[
+                            "\u{1b}hello ", " ", " friends, we ", " ", "",
+                        ],
+                        &args,
+                        &[
+                            builtin#lang(Placeholder::new)(
+                                0usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                8u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Is)(
+                                    2,
+                                ),
+                            ), builtin#lang(Placeholder::new)(
+                                1usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ), builtin#lang(Placeholder::new)(
+                                2usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ), builtin#lang(Placeholder::new)(
+                                1usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ), builtin#lang(Placeholder::new)(
+                                3usize,
+                                ' ',
+                                builtin#lang(Alignment::Unknown),
+                                0u32,
+                                builtin#lang(Count::Implied),
+                                builtin#lang(Count::Implied),
+                            ),
+                        ],
+                    )
+                }
+            };
+        }"#]]
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
+}
+
+#[test]
 fn test_macro_hygiene() {
     let (db, body, def) = lower(
         r##"
@@ -295,29 +381,31 @@ impl SsrError {
     expect![[r#"
         fn main() {
             _ = ra_test_fixture::error::SsrError::new(
-                builtin#lang(Arguments::new_v1_formatted)(
-                    &[
-                        "Failed to resolve path `", "`",
-                    ],
-                    &[
+                {
+                    let args = [
                         builtin#lang(Argument::new_display)(
                             &node.text(),
                         ),
-                    ],
-                    &[
-                        builtin#lang(Placeholder::new)(
-                            0usize,
-                            ' ',
-                            builtin#lang(Alignment::Unknown),
-                            0u32,
-                            builtin#lang(Count::Implied),
-                            builtin#lang(Count::Implied),
-                        ),
-                    ],
+                    ];
                     unsafe {
-                        builtin#lang(UnsafeArg::new)()
-                    },
-                ),
+                        builtin#lang(Arguments::new_v1_formatted)(
+                            &[
+                                "Failed to resolve path `", "`",
+                            ],
+                            &args,
+                            &[
+                                builtin#lang(Placeholder::new)(
+                                    0usize,
+                                    ' ',
+                                    builtin#lang(Alignment::Unknown),
+                                    0u32,
+                                    builtin#lang(Count::Implied),
+                                    builtin#lang(Count::Implied),
+                                ),
+                            ],
+                        )
+                    }
+                },
             );
         }"#]]
     .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
@@ -327,7 +415,7 @@ impl SsrError {
 fn regression_10300() {
     let (db, body, def) = lower(
         r#"
-//- minicore: concat, panic
+//- minicore: concat, panic, fmt_before_1_89_0
 mod private {
     pub use core::concat;
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index bb0b70bc5bf..c7707378a5b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -189,8 +189,8 @@ fn f() {
 }
     "#,
         expect![[r#"
-            BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::<ModuleData>(1) }
-            BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
+            BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
+            BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
             crate scope
         "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index a542214d303..a562f2d0af2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -384,26 +384,7 @@ pub struct BlockLoc {
     /// The containing module.
     pub module: ModuleId,
 }
-#[salsa_macros::tracked(debug)]
-#[derive(PartialOrd, Ord)]
-pub struct BlockIdLt<'db> {
-    pub loc: BlockLoc,
-}
-pub type BlockId = BlockIdLt<'static>;
-impl hir_expand::Intern for BlockLoc {
-    type Database = dyn DefDatabase;
-    type ID = BlockId;
-    fn intern(self, db: &Self::Database) -> Self::ID {
-        unsafe { std::mem::transmute::<BlockIdLt<'_>, BlockId>(BlockIdLt::new(db, self)) }
-    }
-}
-impl hir_expand::Lookup for BlockId {
-    type Database = dyn DefDatabase;
-    type Data = BlockLoc;
-    fn lookup(&self, db: &Self::Database) -> Self::Data {
-        self.loc(db)
-    }
-}
+impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 
 /// A `ModuleId` that is always a crate's root module.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index d1432cacf8d..b756bb859d3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -1230,11 +1230,15 @@ impl InferenceContext<'_> {
                     self.select_from_expr(*expr);
                 }
             }
+            Expr::Let { pat: _, expr } => {
+                self.walk_expr(*expr);
+                let place = self.place_of_expr(*expr);
+                self.ref_expr(*expr, place);
+            }
             Expr::UnaryOp { expr, op: _ }
             | Expr::Array(Array::Repeat { initializer: expr, repeat: _ })
             | Expr::Await { expr }
             | Expr::Loop { body: expr, label: _ }
-            | Expr::Let { pat: _, expr }
             | Expr::Box { expr }
             | Expr::Cast { expr, type_ref: _ } => {
                 self.consume_expr(*expr);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
index 88d21be81ea..7fb981752de 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
@@ -444,3 +444,22 @@ fn main() {
         expect!["99..165;49..54;120..121,133..134 ByRef(Mut { kind: Default }) a &'? mut A"],
     );
 }
+
+#[test]
+fn let_binding_is_a_ref_capture() {
+    check_closure_captures(
+        r#"
+//- minicore:copy
+struct S;
+fn main() {
+    let mut s = S;
+    let s_ref = &mut s;
+    let closure = || {
+        if let ref cb = s_ref {
+        }
+    };
+}
+"#,
+        expect!["83..135;49..54;112..117 ByRef(Shared) s_ref &'? &'? mut S"],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index b1cf30b98f5..0bce69a179b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -242,9 +242,9 @@ fn resolve_assoc_or_field(
     resolve_field(db, variant_def, name, ns)
 }
 
-fn resolve_assoc_item(
-    db: &dyn HirDatabase,
-    ty: &Type,
+fn resolve_assoc_item<'db>(
+    db: &'db dyn HirDatabase,
+    ty: &Type<'db>,
     name: &Name,
     ns: Option<Namespace>,
 ) -> Option<DocLinkDef> {
@@ -256,10 +256,10 @@ fn resolve_assoc_item(
     })
 }
 
-fn resolve_impl_trait_item(
-    db: &dyn HirDatabase,
+fn resolve_impl_trait_item<'db>(
+    db: &'db dyn HirDatabase,
     resolver: Resolver<'_>,
-    ty: &Type,
+    ty: &Type<'db>,
     name: &Name,
     ns: Option<Namespace>,
 ) -> Option<DocLinkDef> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index f7b140e03d4..074bde91fb6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -36,15 +36,15 @@ pub use hir_ty::{
 };
 
 macro_rules! diagnostics {
-    ($($diag:ident,)*) => {
+    ($($diag:ident $(<$lt:lifetime>)?,)*) => {
         #[derive(Debug)]
-        pub enum AnyDiagnostic {$(
-            $diag(Box<$diag>),
+        pub enum AnyDiagnostic<'db> {$(
+            $diag(Box<$diag $(<$lt>)?>),
         )*}
 
         $(
-            impl From<$diag> for AnyDiagnostic {
-                fn from(d: $diag) -> AnyDiagnostic {
+            impl<'db> From<$diag $(<$lt>)?> for AnyDiagnostic<'db> {
+                fn from(d: $diag $(<$lt>)?) -> AnyDiagnostic<'db> {
                     AnyDiagnostic::$diag(Box::new(d))
                 }
             }
@@ -69,12 +69,12 @@ macro_rules! diagnostics {
 diagnostics![
     AwaitOutsideOfAsync,
     BreakOutsideOfLoop,
-    CastToUnsized,
-    ExpectedFunction,
+    CastToUnsized<'db>,
+    ExpectedFunction<'db>,
     InactiveCode,
     IncoherentImpl,
     IncorrectCase,
-    InvalidCast,
+    InvalidCast<'db>,
     InvalidDeriveTarget,
     MacroDefError,
     MacroError,
@@ -85,7 +85,7 @@ diagnostics![
     MissingFields,
     MissingMatchArms,
     MissingUnsafe,
-    MovedOutOfRef,
+    MovedOutOfRef<'db>,
     NeedMut,
     NonExhaustiveLet,
     NoSuchField,
@@ -98,17 +98,17 @@ diagnostics![
     TraitImplMissingAssocItems,
     TraitImplOrphan,
     TraitImplRedundantAssocItems,
-    TypedHole,
-    TypeMismatch,
+    TypedHole<'db>,
+    TypeMismatch<'db>,
     UndeclaredLabel,
     UnimplementedBuiltinMacro,
     UnreachableLabel,
     UnresolvedAssocItem,
     UnresolvedExternCrate,
-    UnresolvedField,
+    UnresolvedField<'db>,
     UnresolvedImport,
     UnresolvedMacroCall,
-    UnresolvedMethodCall,
+    UnresolvedMethodCall<'db>,
     UnresolvedModule,
     UnresolvedIdent,
     UnusedMut,
@@ -130,9 +130,9 @@ pub struct BreakOutsideOfLoop {
 }
 
 #[derive(Debug)]
-pub struct TypedHole {
+pub struct TypedHole<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub expected: Type,
+    pub expected: Type<'db>,
 }
 
 #[derive(Debug)]
@@ -242,25 +242,25 @@ pub struct MismatchedTupleStructPatArgCount {
 }
 
 #[derive(Debug)]
-pub struct ExpectedFunction {
+pub struct ExpectedFunction<'db> {
     pub call: InFile<ExprOrPatPtr>,
-    pub found: Type,
+    pub found: Type<'db>,
 }
 
 #[derive(Debug)]
-pub struct UnresolvedField {
+pub struct UnresolvedField<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub receiver: Type,
+    pub receiver: Type<'db>,
     pub name: Name,
     pub method_with_same_name_exists: bool,
 }
 
 #[derive(Debug)]
-pub struct UnresolvedMethodCall {
+pub struct UnresolvedMethodCall<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub receiver: Type,
+    pub receiver: Type<'db>,
     pub name: Name,
-    pub field_with_same_name: Option<Type>,
+    pub field_with_same_name: Option<Type<'db>>,
     pub assoc_func_with_same_name: Option<Function>,
 }
 
@@ -329,10 +329,10 @@ pub struct NonExhaustiveLet {
 }
 
 #[derive(Debug)]
-pub struct TypeMismatch {
+pub struct TypeMismatch<'db> {
     pub expr_or_pat: InFile<ExprOrPatPtr>,
-    pub expected: Type,
-    pub actual: Type,
+    pub expected: Type<'db>,
+    pub actual: Type<'db>,
 }
 
 #[derive(Debug)]
@@ -352,8 +352,8 @@ pub struct UnusedVariable {
 }
 
 #[derive(Debug)]
-pub struct MovedOutOfRef {
-    pub ty: Type,
+pub struct MovedOutOfRef<'db> {
+    pub ty: Type<'db>,
     pub span: InFile<SyntaxNodePtr>,
 }
 
@@ -403,17 +403,17 @@ pub struct RemoveUnnecessaryElse {
 }
 
 #[derive(Debug)]
-pub struct CastToUnsized {
+pub struct CastToUnsized<'db> {
     pub expr: InFile<ExprOrPatPtr>,
-    pub cast_ty: Type,
+    pub cast_ty: Type<'db>,
 }
 
 #[derive(Debug)]
-pub struct InvalidCast {
+pub struct InvalidCast<'db> {
     pub expr: InFile<ExprOrPatPtr>,
     pub error: CastError,
-    pub expr_ty: Type,
-    pub cast_ty: Type,
+    pub expr_ty: Type<'db>,
+    pub cast_ty: Type<'db>,
 }
 
 #[derive(Debug)]
@@ -482,12 +482,12 @@ pub struct IncorrectGenericsOrder {
     pub expected_kind: GenericArgKind,
 }
 
-impl AnyDiagnostic {
+impl<'db> AnyDiagnostic<'db> {
     pub(crate) fn body_validation_diagnostic(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         diagnostic: BodyValidationDiagnostic,
         source_map: &hir_def::expr_store::BodySourceMap,
-    ) -> Option<AnyDiagnostic> {
+    ) -> Option<AnyDiagnostic<'db>> {
         match diagnostic {
             BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
                 let variant_data = variant.variant_data(db);
@@ -618,12 +618,12 @@ impl AnyDiagnostic {
     }
 
     pub(crate) fn inference_diagnostic(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: DefWithBodyId,
         d: &InferenceDiagnostic,
         source_map: &hir_def::expr_store::BodySourceMap,
         sig_map: &hir_def::expr_store::ExpressionStoreSourceMap,
-    ) -> Option<AnyDiagnostic> {
+    ) -> Option<AnyDiagnostic<'db>> {
         let expr_syntax = |expr| {
             source_map
                 .expr_syntax(expr)
@@ -819,7 +819,7 @@ impl AnyDiagnostic {
     fn path_diagnostic(
         diag: &PathLoweringDiagnostic,
         path: InFile<ast::Path>,
-    ) -> Option<AnyDiagnostic> {
+    ) -> Option<AnyDiagnostic<'db>> {
         Some(match *diag {
             PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
                 let segment = hir_segment_to_ast_segment(&path.value, segment)?;
@@ -912,8 +912,8 @@ impl AnyDiagnostic {
     pub(crate) fn ty_diagnostic(
         diag: &TyLoweringDiagnostic,
         source_map: &ExpressionStoreSourceMap,
-        db: &dyn HirDatabase,
-    ) -> Option<AnyDiagnostic> {
+        db: &'db dyn HirDatabase,
+    ) -> Option<AnyDiagnostic<'db>> {
         let Ok(source) = source_map.type_syntax(diag.source) else {
             stdx::never!("error on synthetic type syntax");
             return None;
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 124ab8e274a..112558bdd04 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -431,7 +431,7 @@ impl HirDisplay for Variant {
     }
 }
 
-impl HirDisplay for Type {
+impl HirDisplay for Type<'_> {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         self.ty.hir_fmt(f)
     }
@@ -743,7 +743,7 @@ impl HirDisplay for Static {
     }
 }
 
-impl HirDisplay for TraitRef {
+impl HirDisplay for TraitRef<'_> {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         self.trait_ref.hir_fmt(f)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
index fe7429c8672..4767d4792e7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
@@ -225,7 +225,7 @@ impl HasSource for LocalSource {
     }
 }
 
-impl HasSource for Param {
+impl HasSource for Param<'_> {
     type Ast = Either<ast::SelfParam, ast::Param>;
 
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index adae335627b..3b39707cf60 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -84,7 +84,7 @@ use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::{AstIdNode, Edition, FileId};
-use stdx::{format_to, impl_from, never};
+use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime};
 use syntax::{
     AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr,
     ast::{self, HasAttrs as _, HasName, HasVisibility as _},
@@ -400,7 +400,11 @@ impl ModuleDef {
         Some(name)
     }
 
-    pub fn diagnostics(self, db: &dyn HirDatabase, style_lints: bool) -> Vec<AnyDiagnostic> {
+    pub fn diagnostics<'db>(
+        self,
+        db: &'db dyn HirDatabase,
+        style_lints: bool,
+    ) -> Vec<AnyDiagnostic<'db>> {
         let id = match self {
             ModuleDef::Adt(it) => match it {
                 Adt::Struct(it) => it.id.into(),
@@ -612,10 +616,10 @@ impl Module {
     }
 
     /// Fills `acc` with the module's diagnostics.
-    pub fn diagnostics(
+    pub fn diagnostics<'db>(
         self,
-        db: &dyn HirDatabase,
-        acc: &mut Vec<AnyDiagnostic>,
+        db: &'db dyn HirDatabase,
+        acc: &mut Vec<AnyDiagnostic<'db>>,
         style_lints: bool,
     ) {
         let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered();
@@ -970,10 +974,10 @@ impl Module {
     }
 }
 
-fn macro_call_diagnostics(
-    db: &dyn HirDatabase,
+fn macro_call_diagnostics<'db>(
+    db: &'db dyn HirDatabase,
     macro_call_id: MacroCallId,
-    acc: &mut Vec<AnyDiagnostic>,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
 ) {
     let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
         return;
@@ -1010,7 +1014,11 @@ fn macro_call_diagnostics(
     }
 }
 
-fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
+fn emit_macro_def_diagnostics<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
+    m: Macro,
+) {
     let id = db.macro_def(m.id);
     if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) {
         if let Some(e) = expander.mac.err() {
@@ -1030,18 +1038,18 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>
     }
 }
 
-fn emit_def_diagnostic(
-    db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+fn emit_def_diagnostic<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
     diag: &DefDiagnostic,
     edition: Edition,
 ) {
     emit_def_diagnostic_(db, acc, &diag.kind, edition)
 }
 
-fn emit_def_diagnostic_(
-    db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+fn emit_def_diagnostic_<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
     diag: &DefDiagnosticKind,
     edition: Edition,
 ) {
@@ -1251,14 +1259,18 @@ impl TupleField {
         Name::new_tuple_field(self.index as usize)
     }
 
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let ty = db.infer(self.owner).tuple_field_access_types[&self.tuple]
             .as_slice(Interner)
             .get(self.index as usize)
             .and_then(|arg| arg.ty(Interner))
             .cloned()
             .unwrap_or_else(|| TyKind::Error.intern(Interner));
-        Type { env: db.trait_environment_for_body(self.owner), ty }
+        Type {
+            env: db.trait_environment_for_body(self.owner),
+            ty,
+            _pd: PhantomCovariantLifetime::new(),
+        }
     }
 }
 
@@ -1309,7 +1321,7 @@ impl Field {
     /// Returns the type as in the signature of the struct (i.e., with
     /// placeholder types for type parameters). Only use this in the context of
     /// the field definition.
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let var_id = self.parent.into();
         let generic_def_id: GenericDefId = match self.parent {
             VariantDef::Struct(it) => it.id.into(),
@@ -1322,7 +1334,11 @@ impl Field {
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
+    pub fn ty_with_args<'db>(
+        &self,
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let var_id = self.parent.into();
         let def_id: AdtId = match self.parent {
             VariantDef::Struct(it) => it.id.into(),
@@ -1394,15 +1410,15 @@ impl Struct {
             .collect()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def_placeholders(db, self.id)
     }
 
-    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -1449,15 +1465,15 @@ impl Union {
         Module { id: self.id.lookup(db).container }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def_placeholders(db, self.id)
     }
 
-    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -1515,16 +1531,16 @@ impl Enum {
         db.enum_signature(self.id).repr
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         Type::from_def_placeholders(db, self.id)
     }
 
     /// The type of the enum variant bodies.
-    pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         Type::new_for_crate(
             self.id.lookup(db).container.krate(),
             TyBuilder::builtin(match db.enum_signature(self.id).variant_body_type() {
@@ -1599,7 +1615,7 @@ impl Variant {
         self.id.lookup(db).parent.into()
     }
 
-    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -1701,14 +1717,18 @@ impl Adt {
     /// Turns this ADT into a type. Any type parameters of the ADT will be
     /// turned into unknown types, which is good for e.g. finding the most
     /// general set of completions, but will not look very nice when printed.
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let id = AdtId::from(self);
         Type::from_def(db, id)
     }
 
     /// Turns this ADT into a type with the given type parameters. This isn't
     /// the greatest API, FIXME find a better one.
-    pub fn ty_with_args(self, db: &dyn HirDatabase, args: impl Iterator<Item = Type>) -> Type {
+    pub fn ty_with_args<'db>(
+        self,
+        db: &'db dyn HirDatabase,
+        args: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let id = AdtId::from(self);
         let mut it = args.map(|t| t.ty);
         let ty = TyBuilder::def_ty(db, id.into(), None)
@@ -1841,7 +1861,7 @@ impl DefWithBody {
     }
 
     /// Returns the type this def's body has to evaluate to.
-    pub fn body_type(self, db: &dyn HirDatabase) -> Type {
+    pub fn body_type(self, db: &dyn HirDatabase) -> Type<'_> {
         match self {
             DefWithBody::Function(it) => it.ret_type(db),
             DefWithBody::Static(it) => it.ty(db),
@@ -1874,10 +1894,10 @@ impl DefWithBody {
         }
     }
 
-    pub fn diagnostics(
+    pub fn diagnostics<'db>(
         self,
-        db: &dyn HirDatabase,
-        acc: &mut Vec<AnyDiagnostic>,
+        db: &'db dyn HirDatabase,
+        acc: &mut Vec<AnyDiagnostic<'db>>,
         style_lints: bool,
     ) {
         let krate = self.module(db).id.krate();
@@ -2107,7 +2127,7 @@ impl DefWithBody {
 
 fn expr_store_diagnostics(
     db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+    acc: &mut Vec<AnyDiagnostic<'_>>,
     source_map: &ExpressionStoreSourceMap,
 ) {
     for diag in source_map.diagnostics() {
@@ -2172,11 +2192,11 @@ impl Function {
         db.function_signature(self.id).name.clone()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
-    pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type {
+    pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2185,7 +2205,7 @@ impl Function {
     }
 
     /// Get this function's return type
-    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
+    pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2194,11 +2214,11 @@ impl Function {
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn ret_type_with_args(
+    pub fn ret_type_with_args<'db>(
         self,
-        db: &dyn HirDatabase,
-        generics: impl Iterator<Item = Type>,
-    ) -> Type {
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let resolver = self.id.resolver(db);
         let parent_id: Option<GenericDefId> = match self.id.lookup(db).container {
             ItemContainerId::ImplId(it) => Some(it.into()),
@@ -2223,7 +2243,7 @@ impl Function {
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
-    pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         if !self.is_async(db) {
             return None;
         }
@@ -2247,7 +2267,7 @@ impl Function {
         self.has_self_param(db).then_some(SelfParam { func: self.id })
     }
 
-    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
+    pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2256,7 +2276,11 @@ impl Function {
             .iter()
             .enumerate()
             .map(|(idx, ty)| {
-                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                let ty = Type {
+                    env: environment.clone(),
+                    ty: ty.clone(),
+                    _pd: PhantomCovariantLifetime::new(),
+                };
                 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
             })
             .collect()
@@ -2266,12 +2290,12 @@ impl Function {
         db.function_signature(self.id).params.len()
     }
 
-    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
+    pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param<'_>>> {
         self.self_param(db)?;
         Some(self.params_without_self(db))
     }
 
-    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param> {
+    pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
@@ -2282,18 +2306,22 @@ impl Function {
             .enumerate()
             .skip(skip)
             .map(|(idx, ty)| {
-                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                let ty = Type {
+                    env: environment.clone(),
+                    ty: ty.clone(),
+                    _pd: PhantomCovariantLifetime::new(),
+                };
                 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
             })
             .collect()
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn params_without_self_with_args(
+    pub fn params_without_self_with_args<'db>(
         self,
-        db: &dyn HirDatabase,
-        generics: impl Iterator<Item = Type>,
-    ) -> Vec<Param> {
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Vec<Param<'db>> {
         let environment = db.trait_environment(self.id.into());
         let parent_id: Option<GenericDefId> = match self.id.lookup(db).container {
             ItemContainerId::ImplId(it) => Some(it.into()),
@@ -2328,7 +2356,11 @@ impl Function {
             .enumerate()
             .skip(skip)
             .map(|(idx, ty)| {
-                let ty = Type { env: environment.clone(), ty: ty.clone() };
+                let ty = Type {
+                    env: environment.clone(),
+                    ty: ty.clone(),
+                    _pd: PhantomCovariantLifetime::new(),
+                };
                 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
             })
             .collect()
@@ -2358,7 +2390,8 @@ impl Function {
             return true;
         }
 
-        let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false };
+        let ret_type = self.ret_type(db);
+        let Some(impl_traits) = ret_type.as_impl_traits(db) else { return false };
         let Some(future_trait_id) = LangItem::Future.resolve_trait(db, self.ty(db).env.krate)
         else {
             return false;
@@ -2501,14 +2534,14 @@ impl From<hir_ty::Mutability> for Access {
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Param {
+pub struct Param<'db> {
     func: Callee,
     /// The index in parameter list, including self parameter.
     idx: usize,
-    ty: Type,
+    ty: Type<'db>,
 }
 
-impl Param {
+impl<'db> Param<'db> {
     pub fn parent_fn(&self) -> Option<Function> {
         match self.func {
             Callee::Def(CallableDefId::FunctionId(f)) => Some(f.into()),
@@ -2524,7 +2557,7 @@ impl Param {
         self.idx
     }
 
-    pub fn ty(&self) -> &Type {
+    pub fn ty(&self) -> &Type<'db> {
         &self.ty
     }
 
@@ -2591,17 +2624,21 @@ impl SelfParam {
         Function::from(self.func)
     }
 
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let substs = TyBuilder::placeholder_subst(db, self.func);
         let callable_sig =
             db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
     // FIXME: Find better API to also handle const generics
-    pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator<Item = Type>) -> Type {
+    pub fn ty_with_args<'db>(
+        &self,
+        db: &'db dyn HirDatabase,
+        generics: impl Iterator<Item = Type<'db>>,
+    ) -> Type<'db> {
         let parent_id: GenericDefId = match self.func.lookup(db).container {
             ItemContainerId::ImplId(it) => it.into(),
             ItemContainerId::TraitId(it) => it.into(),
@@ -2626,7 +2663,7 @@ impl SelfParam {
             db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 }
 
@@ -2714,7 +2751,7 @@ impl Const {
         self.source(db)?.value.body()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -2791,7 +2828,7 @@ impl Static {
         self.source(db)?.value.body()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_value_def(db, self.id)
     }
 
@@ -2961,11 +2998,11 @@ impl TypeAlias {
         Module { id: self.id.module(db) }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def(db, self.id)
     }
 
-    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::from_def_placeholders(db, self.id)
     }
 
@@ -3010,7 +3047,7 @@ impl BuiltinType {
         BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> {
         let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]);
         Type::new_for_crate(core, TyBuilder::builtin(self.inner))
     }
@@ -3472,7 +3509,7 @@ impl AssocItem {
         }
     }
 
-    pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option<Type<'_>> {
         match self.container(db) {
             AssocItemContainer::Impl(i) => Some(i.self_ty(db)),
             _ => None,
@@ -3500,10 +3537,10 @@ impl AssocItem {
         }
     }
 
-    pub fn diagnostics(
+    pub fn diagnostics<'db>(
         self,
-        db: &dyn HirDatabase,
-        acc: &mut Vec<AnyDiagnostic>,
+        db: &'db dyn HirDatabase,
+        acc: &mut Vec<AnyDiagnostic<'db>>,
         style_lints: bool,
     ) {
         match self {
@@ -3625,7 +3662,7 @@ impl GenericDef {
         }
     }
 
-    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
+    pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec<AnyDiagnostic<'db>>) {
         let def = self.id();
 
         let generics = db.generic_params(def);
@@ -3690,18 +3727,19 @@ impl GenericDef {
 
 // We cannot call this `Substitution` unfortunately...
 #[derive(Debug)]
-pub struct GenericSubstitution {
+pub struct GenericSubstitution<'db> {
     def: GenericDefId,
     subst: Substitution,
     env: Arc<TraitEnvironment>,
+    _pd: PhantomCovariantLifetime<'db>,
 }
 
-impl GenericSubstitution {
+impl<'db> GenericSubstitution<'db> {
     fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
-        Self { def, subst, env }
+        Self { def, subst, env, _pd: PhantomCovariantLifetime::new() }
     }
 
-    pub fn types(&self, db: &dyn HirDatabase) -> Vec<(Symbol, Type)> {
+    pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> {
         let container = match self.def {
             GenericDefId::ConstId(id) => Some(id.lookup(db).container),
             GenericDefId::FunctionId(id) => Some(id.lookup(db).container),
@@ -3744,7 +3782,10 @@ impl GenericSubstitution {
         container_params
             .chain(self_params)
             .filter_map(|(ty, name)| {
-                Some((name?.symbol().clone(), Type { ty, env: self.env.clone() }))
+                Some((
+                    name?.symbol().clone(),
+                    Type { ty, env: self.env.clone(), _pd: PhantomCovariantLifetime::new() },
+                ))
             })
             .collect()
     }
@@ -3847,7 +3888,7 @@ impl Local {
         self.parent(db).module(db)
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let def = self.parent;
         let infer = db.infer(def);
         let ty = infer[self.binding_id].clone();
@@ -4109,6 +4150,10 @@ impl TypeParam {
         self.merge().name(db)
     }
 
+    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
+        self.id.parent().into()
+    }
+
     pub fn module(self, db: &dyn HirDatabase) -> Module {
         self.id.parent().module(db).into()
     }
@@ -4124,7 +4169,7 @@ impl TypeParam {
         }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.parent().resolver(db);
         let ty =
             TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
@@ -4146,7 +4191,7 @@ impl TypeParam {
             .collect()
     }
 
-    pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn default(self, db: &dyn HirDatabase) -> Option<Type<'_>> {
         let ty = generic_arg_from_param(db, self.id.into())?;
         let resolver = self.id.parent().resolver(db);
         match ty.data(Interner) {
@@ -4211,7 +4256,7 @@ impl ConstParam {
         self.id.parent().into()
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         Type::new(db, self.id.parent(), db.const_param_ty(self.id))
     }
 
@@ -4268,7 +4313,7 @@ impl TypeOrConstParam {
         }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
         match self.split(db) {
             Either::Left(it) => it.ty(db),
             Either::Right(it) => it.ty(db),
@@ -4313,7 +4358,10 @@ impl Impl {
         module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect()
     }
 
-    pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec<Impl> {
+    pub fn all_for_type<'db>(
+        db: &'db dyn HirDatabase,
+        Type { ty, env, _pd: _ }: Type<'db>,
+    ) -> Vec<Impl> {
         let def_crates = match method_resolution::def_crates(db, &ty, env.krate) {
             Some(def_crates) => def_crates,
             None => return Vec::new(),
@@ -4398,14 +4446,14 @@ impl Impl {
         Some(Trait { id })
     }
 
-    pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef> {
+    pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> {
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let trait_ref = db.impl_trait(self.id)?.substitute(Interner, &substs);
         let resolver = self.id.resolver(db);
         Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
     }
 
-    pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
+    pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
         let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
@@ -4467,21 +4515,22 @@ impl Impl {
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct TraitRef {
+pub struct TraitRef<'db> {
     env: Arc<TraitEnvironment>,
     trait_ref: hir_ty::TraitRef,
+    _pd: PhantomCovariantLifetime<'db>,
 }
 
-impl TraitRef {
+impl<'db> TraitRef<'db> {
     pub(crate) fn new_with_resolver(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         resolver: &Resolver<'_>,
         trait_ref: hir_ty::TraitRef,
-    ) -> TraitRef {
+    ) -> Self {
         let env = resolver
             .generic_def()
             .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
-        TraitRef { env, trait_ref }
+        TraitRef { env, trait_ref, _pd: PhantomCovariantLifetime::new() }
     }
 
     pub fn trait_(&self) -> Trait {
@@ -4489,21 +4538,21 @@ impl TraitRef {
         Trait { id }
     }
 
-    pub fn self_ty(&self) -> Type {
+    pub fn self_ty(&self) -> Type<'_> {
         let ty = self.trait_ref.self_type_parameter(Interner);
-        Type { env: self.env.clone(), ty }
+        Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() }
     }
 
     /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the
     /// first argument is the `Self` type.
-    pub fn get_type_argument(&self, idx: usize) -> Option<Type> {
+    pub fn get_type_argument(&self, idx: usize) -> Option<Type<'db>> {
         self.trait_ref
             .substitution
             .as_slice(Interner)
             .get(idx)
             .and_then(|arg| arg.ty(Interner))
             .cloned()
-            .map(|ty| Type { env: self.env.clone(), ty })
+            .map(|ty| Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() })
     }
 }
 
@@ -4551,7 +4600,7 @@ impl Closure {
             .collect()
     }
 
-    pub fn capture_types(&self, db: &dyn HirDatabase) -> Vec<Type> {
+    pub fn capture_types<'db>(&self, db: &'db dyn HirDatabase) -> Vec<Type<'db>> {
         let owner = db.lookup_intern_closure((self.id).into()).0;
         let infer = &db.infer(owner);
         let (captures, _) = infer.closure_info(&self.id);
@@ -4560,6 +4609,7 @@ impl Closure {
             .map(|capture| Type {
                 env: db.trait_environment_for_body(owner),
                 ty: capture.ty(&self.subst),
+                _pd: PhantomCovariantLifetime::new(),
             })
             .collect()
     }
@@ -4691,40 +4741,45 @@ impl CaptureUsageSource {
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Type {
+pub struct Type<'db> {
     env: Arc<TraitEnvironment>,
     ty: Ty,
+    _pd: PhantomCovariantLifetime<'db>,
 }
 
-impl Type {
-    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty) -> Type {
+impl<'db> Type<'db> {
+    pub(crate) fn new_with_resolver(
+        db: &'db dyn HirDatabase,
+        resolver: &Resolver<'_>,
+        ty: Ty,
+    ) -> Self {
         Type::new_with_resolver_inner(db, resolver, ty)
     }
 
     pub(crate) fn new_with_resolver_inner(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         resolver: &Resolver<'_>,
         ty: Ty,
-    ) -> Type {
+    ) -> Self {
         let environment = resolver
             .generic_def()
             .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
-    pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Type {
-        Type { env: TraitEnvironment::empty(krate), ty }
+    pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Self {
+        Type { env: TraitEnvironment::empty(krate), ty, _pd: PhantomCovariantLifetime::new() }
     }
 
-    fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
+    fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Self {
         let resolver = lexical_env.resolver(db);
         let environment = resolver
             .generic_def()
             .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d));
-        Type { env: environment, ty }
+        Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
-    fn from_def(db: &dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Type {
+    fn from_def(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self {
         let ty = db.ty(def.into());
         let substs = TyBuilder::unknown_subst(
             db,
@@ -4737,7 +4792,10 @@ impl Type {
         Type::new(db, def, ty.substitute(Interner, &substs))
     }
 
-    fn from_def_placeholders(db: &dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Type {
+    fn from_def_placeholders(
+        db: &'db dyn HirDatabase,
+        def: impl Into<TyDefId> + HasResolver,
+    ) -> Self {
         let ty = db.ty(def.into());
         let substs = TyBuilder::placeholder_subst(
             db,
@@ -4750,7 +4808,10 @@ impl Type {
         Type::new(db, def, ty.substitute(Interner, &substs))
     }
 
-    fn from_value_def(db: &dyn HirDatabase, def: impl Into<ValueTyDefId> + HasResolver) -> Type {
+    fn from_value_def(
+        db: &'db dyn HirDatabase,
+        def: impl Into<ValueTyDefId> + HasResolver,
+    ) -> Self {
         let Some(ty) = db.value_ty(def.into()) else {
             return Type::new(db, def, TyKind::Error.intern(Interner));
         };
@@ -4770,13 +4831,17 @@ impl Type {
         Type::new(db, def, ty.substitute(Interner, &substs))
     }
 
-    pub fn new_slice(ty: Type) -> Type {
-        Type { env: ty.env, ty: TyBuilder::slice(ty.ty) }
+    pub fn new_slice(ty: Self) -> Self {
+        Type { env: ty.env, ty: TyBuilder::slice(ty.ty), _pd: PhantomCovariantLifetime::new() }
     }
 
-    pub fn new_tuple(krate: base_db::Crate, tys: &[Type]) -> Type {
+    pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self {
         let tys = tys.iter().map(|it| it.ty.clone());
-        Type { env: TraitEnvironment::empty(krate), ty: TyBuilder::tuple_with(tys) }
+        Type {
+            env: TraitEnvironment::empty(krate),
+            ty: TyBuilder::tuple_with(tys),
+            _pd: PhantomCovariantLifetime::new(),
+        }
     }
 
     pub fn is_unit(&self) -> bool {
@@ -4803,7 +4868,7 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
-    pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool {
+    pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool {
         return go(db, self.env.krate, &self.ty);
 
         fn go(db: &dyn HirDatabase, krate: base_db::Crate, ty: &Ty) -> bool {
@@ -4847,13 +4912,13 @@ impl Type {
         }
     }
 
-    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
+    pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> {
         let (ty, _lt, m) = self.ty.as_reference()?;
         let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
         Some((self.derived(ty.clone()), m))
     }
 
-    pub fn add_reference(&self, mutability: Mutability) -> Type {
+    pub fn add_reference(&self, mutability: Mutability) -> Self {
         let ty_mutability = match mutability {
             Mutability::Shared => hir_ty::Mutability::Not,
             Mutability::Mut => hir_ty::Mutability::Mut,
@@ -4889,25 +4954,25 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Tuple(..))
     }
 
-    pub fn remove_ref(&self) -> Option<Type> {
+    pub fn remove_ref(&self) -> Option<Type<'db>> {
         match &self.ty.kind(Interner) {
             TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
             _ => None,
         }
     }
 
-    pub fn as_slice(&self) -> Option<Type> {
+    pub fn as_slice(&self) -> Option<Type<'db>> {
         match &self.ty.kind(Interner) {
             TyKind::Slice(ty) => Some(self.derived(ty.clone())),
             _ => None,
         }
     }
 
-    pub fn strip_references(&self) -> Type {
+    pub fn strip_references(&self) -> Self {
         self.derived(self.ty.strip_references().clone())
     }
 
-    pub fn strip_reference(&self) -> Type {
+    pub fn strip_reference(&self) -> Self {
         self.derived(self.ty.strip_reference().clone())
     }
 
@@ -4918,7 +4983,7 @@ impl Type {
     /// Checks that particular type `ty` implements `std::future::IntoFuture` or
     /// `std::future::Future` and returns the `Output` associated type.
     /// This function is used in `.await` syntax completion.
-    pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn into_future_output(&self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let trait_ = LangItem::IntoFutureIntoFuture
             .resolve_function(db, self.env.krate)
             .and_then(|into_future_fn| {
@@ -4940,13 +5005,13 @@ impl Type {
     }
 
     /// This does **not** resolve `IntoFuture`, only `Future`.
-    pub fn future_output(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn future_output(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let future_output = LangItem::FutureOutput.resolve_type_alias(db, self.env.krate)?;
         self.normalize_trait_assoc_type(db, &[], future_output.into())
     }
 
     /// This does **not** resolve `IntoIterator`, only `Iterator`.
-    pub fn iterator_item(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?;
         let iterator_item = db
             .trait_items(iterator_trait)
@@ -4954,7 +5019,7 @@ impl Type {
         self.normalize_trait_assoc_type(db, &[], iterator_item.into())
     }
 
-    pub fn impls_iterator(self, db: &dyn HirDatabase) -> bool {
+    pub fn impls_iterator(self, db: &'db dyn HirDatabase) -> bool {
         let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else {
             return false;
         };
@@ -4964,7 +5029,7 @@ impl Type {
     }
 
     /// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type
-    pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option<Type> {
+    pub fn into_iterator_iter(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
         let trait_ = LangItem::IntoIterIntoIter.resolve_function(db, self.env.krate).and_then(
             |into_iter_fn| {
                 let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?;
@@ -4989,7 +5054,7 @@ impl Type {
     ///
     /// This function can be used to check if a particular type is callable, since FnOnce is a
     /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
-    pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
+    pub fn impls_fnonce(&self, db: &'db dyn HirDatabase) -> bool {
         let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) {
             Some(it) => it,
             None => return false,
@@ -5001,7 +5066,7 @@ impl Type {
     }
 
     // FIXME: Find better API that also handles const generics
-    pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
+    pub fn impls_trait(&self, db: &'db dyn HirDatabase, trait_: Trait, args: &[Type<'db>]) -> bool {
         let mut it = args.iter().map(|t| t.ty.clone());
         let trait_ref = TyBuilder::trait_ref(db, trait_.id)
             .push(self.ty.clone())
@@ -5029,10 +5094,10 @@ impl Type {
 
     pub fn normalize_trait_assoc_type(
         &self,
-        db: &dyn HirDatabase,
-        args: &[Type],
+        db: &'db dyn HirDatabase,
+        args: &[Type<'db>],
         alias: TypeAlias,
-    ) -> Option<Type> {
+    ) -> Option<Type<'db>> {
         let mut args = args.iter();
         let trait_id = match alias.id.lookup(db).container {
             ItemContainerId::TraitId(id) => id,
@@ -5056,14 +5121,14 @@ impl Type {
         if ty.is_unknown() { None } else { Some(self.derived(ty)) }
     }
 
-    pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
+    pub fn is_copy(&self, db: &'db dyn HirDatabase) -> bool {
         let Some(copy_trait) = LangItem::Copy.resolve_trait(db, self.env.krate) else {
             return false;
         };
         self.impls_trait(db, copy_trait.into(), &[])
     }
 
-    pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
+    pub fn as_callable(&self, db: &'db dyn HirDatabase) -> Option<Callable<'db>> {
         let callee = match self.ty.kind(Interner) {
             TyKind::Closure(id, subst) => Callee::Closure(*id, subst.clone()),
             TyKind::Function(_) => Callee::FnPtr,
@@ -5117,7 +5182,7 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Array(..))
     }
 
-    pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
+    pub fn is_packed(&self, db: &'db dyn HirDatabase) -> bool {
         let adt_id = match *self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
             _ => return false,
@@ -5134,7 +5199,7 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Raw(..))
     }
 
-    pub fn remove_raw_ptr(&self) -> Option<Type> {
+    pub fn remove_raw_ptr(&self) -> Option<Type<'db>> {
         if let TyKind::Raw(_, ty) = self.ty.kind(Interner) {
             Some(self.derived(ty.clone()))
         } else {
@@ -5182,7 +5247,7 @@ impl Type {
         }
     }
 
-    pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
+    pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> {
         let (variant_id, substs) = match self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
             TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
@@ -5199,7 +5264,7 @@ impl Type {
             .collect()
     }
 
-    pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
+    pub fn tuple_fields(&self, _db: &'db dyn HirDatabase) -> Vec<Self> {
         if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
             substs
                 .iter(Interner)
@@ -5210,7 +5275,7 @@ impl Type {
         }
     }
 
-    pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> {
+    pub fn as_array(&self, db: &'db dyn HirDatabase) -> Option<(Self, usize)> {
         if let TyKind::Array(ty, len) = &self.ty.kind(Interner) {
             try_const_usize(db, len).map(|it| (self.derived(ty.clone()), it as usize))
         } else {
@@ -5228,14 +5293,14 @@ impl Type {
 
     /// Returns types that this type dereferences to (including this type itself). The returned
     /// iterator won't yield the same type more than once even if the deref chain contains a cycle.
-    pub fn autoderef<'db>(
+    pub fn autoderef(
         &self,
         db: &'db dyn HirDatabase,
-    ) -> impl Iterator<Item = Type> + use<'_, 'db> {
+    ) -> impl Iterator<Item = Type<'db>> + use<'_, 'db> {
         self.autoderef_(db).map(move |ty| self.derived(ty))
     }
 
-    fn autoderef_(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Ty> {
+    fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Ty> {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
         autoderef(db, self.env.clone(), canonical)
@@ -5245,7 +5310,7 @@ impl Type {
     // lifetime problems, because we need to borrow temp `CrateImplDefs`.
     pub fn iterate_assoc_items<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         krate: Crate,
         mut callback: impl FnMut(AssocItem) -> Option<T>,
     ) -> Option<T> {
@@ -5259,7 +5324,7 @@ impl Type {
 
     fn iterate_assoc_items_dyn(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         krate: Crate,
         callback: &mut dyn FnMut(AssocItemId) -> bool,
     ) {
@@ -5298,7 +5363,7 @@ impl Type {
     /// - "String"
     /// - "U"
     /// ```
-    pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
+    pub fn type_arguments(&self) -> impl Iterator<Item = Type<'db>> + '_ {
         self.ty
             .strip_references()
             .as_adt()
@@ -5368,7 +5433,7 @@ impl Type {
 
     pub fn iterate_method_candidates_with_traits<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5396,7 +5461,7 @@ impl Type {
 
     pub fn iterate_method_candidates<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         with_local_impls: Option<Module>,
         name: Option<&Name>,
@@ -5418,7 +5483,7 @@ impl Type {
     /// are considered inherent methods.
     pub fn iterate_method_candidates_split_inherent(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5486,7 +5551,7 @@ impl Type {
     #[tracing::instrument(skip_all, fields(name = ?name))]
     pub fn iterate_path_candidates<T>(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5521,7 +5586,7 @@ impl Type {
     #[tracing::instrument(skip_all, fields(name = ?name))]
     pub fn iterate_path_candidates_split_inherent(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         scope: &SemanticsScope<'_>,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
@@ -5584,10 +5649,10 @@ impl Type {
 
     /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
     /// or an empty iterator otherwise.
-    pub fn applicable_inherent_traits<'a>(
-        &'a self,
-        db: &'a dyn HirDatabase,
-    ) -> impl Iterator<Item = Trait> + 'a {
+    pub fn applicable_inherent_traits(
+        &self,
+        db: &'db dyn HirDatabase,
+    ) -> impl Iterator<Item = Trait> {
         let _p = tracing::info_span!("applicable_inherent_traits").entered();
         self.autoderef_(db)
             .filter_map(|ty| ty.dyn_trait())
@@ -5595,7 +5660,7 @@ impl Type {
             .map(Trait::from)
     }
 
-    pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
+    pub fn env_traits(&self, db: &'db dyn HirDatabase) -> impl Iterator<Item = Trait> {
         let _p = tracing::info_span!("env_traits").entered();
         self.autoderef_(db)
             .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
@@ -5607,10 +5672,7 @@ impl Type {
             .map(Trait::from)
     }
 
-    pub fn as_impl_traits(
-        &self,
-        db: &dyn HirDatabase,
-    ) -> Option<impl Iterator<Item = Trait> + use<>> {
+    pub fn as_impl_traits(&self, db: &'db dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
         self.ty.impl_trait_bounds(db).map(|it| {
             it.into_iter().filter_map(|pred| match pred.skip_binders() {
                 hir_ty::WhereClause::Implemented(trait_ref) => {
@@ -5621,33 +5683,33 @@ impl Type {
         })
     }
 
-    pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
+    pub fn as_associated_type_parent_trait(&self, db: &'db dyn HirDatabase) -> Option<Trait> {
         self.ty.associated_type_parent_trait(db).map(Into::into)
     }
 
-    fn derived(&self, ty: Ty) -> Type {
-        Type { env: self.env.clone(), ty }
+    fn derived(&self, ty: Ty) -> Self {
+        Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() }
     }
 
     /// Visits every type, including generic arguments, in this type. `cb` is called with type
     /// itself first, and then with its generic arguments.
-    pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
-        fn walk_substs(
-            db: &dyn HirDatabase,
-            type_: &Type,
+    pub fn walk(&self, db: &'db dyn HirDatabase, mut cb: impl FnMut(Type<'db>)) {
+        fn walk_substs<'db>(
+            db: &'db dyn HirDatabase,
+            type_: &Type<'db>,
             substs: &Substitution,
-            cb: &mut impl FnMut(Type),
+            cb: &mut impl FnMut(Type<'db>),
         ) {
             for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
                 walk_type(db, &type_.derived(ty.clone()), cb);
             }
         }
 
-        fn walk_bounds(
-            db: &dyn HirDatabase,
-            type_: &Type,
+        fn walk_bounds<'db>(
+            db: &'db dyn HirDatabase,
+            type_: &Type<'db>,
             bounds: &[QuantifiedWhereClause],
-            cb: &mut impl FnMut(Type),
+            cb: &mut impl FnMut(Type<'db>),
         ) {
             for pred in bounds {
                 if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
@@ -5664,7 +5726,11 @@ impl Type {
             }
         }
 
-        fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
+        fn walk_type<'db>(
+            db: &'db dyn HirDatabase,
+            type_: &Type<'db>,
+            cb: &mut impl FnMut(Type<'db>),
+        ) {
             let ty = type_.ty.strip_references();
             match ty.kind(Interner) {
                 TyKind::Adt(_, substs) => {
@@ -5732,7 +5798,7 @@ impl Type {
     ///
     /// Note that we consider placeholder types to unify with everything.
     /// For example `Option<T>` and `Option<U>` unify although there is unresolved goal `T = U`.
-    pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
+    pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
         hir_ty::could_unify(db, self.env.clone(), &tys)
     }
@@ -5741,17 +5807,17 @@ impl Type {
     ///
     /// This means that placeholder types are not considered to unify if there are any bounds set on
     /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
-    pub fn could_unify_with_deeply(&self, db: &dyn HirDatabase, other: &Type) -> bool {
+    pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
         hir_ty::could_unify_deeply(db, self.env.clone(), &tys)
     }
 
-    pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
+    pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
         hir_ty::could_coerce(db, self.env.clone(), &tys)
     }
 
-    pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option<TypeParam> {
+    pub fn as_type_param(&self, db: &'db dyn HirDatabase) -> Option<TypeParam> {
         match self.ty.kind(Interner) {
             TyKind::Placeholder(p) => Some(TypeParam {
                 id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)),
@@ -5761,19 +5827,19 @@ impl Type {
     }
 
     /// Returns unique `GenericParam`s contained in this type.
-    pub fn generic_params(&self, db: &dyn HirDatabase) -> FxHashSet<GenericParam> {
+    pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet<GenericParam> {
         hir_ty::collect_placeholders(&self.ty, db)
             .into_iter()
             .map(|id| TypeOrConstParam { id }.split(db).either_into())
             .collect()
     }
 
-    pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> {
         db.layout_of_ty(self.ty.clone(), self.env.clone())
             .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
     }
 
-    pub fn drop_glue(&self, db: &dyn HirDatabase) -> DropGlue {
+    pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue {
         db.has_drop_glue(self.ty.clone(), self.env.clone())
     }
 }
@@ -5800,8 +5866,8 @@ impl InlineAsmOperand {
 
 // FIXME: Document this
 #[derive(Debug)]
-pub struct Callable {
-    ty: Type,
+pub struct Callable<'db> {
+    ty: Type<'db>,
     sig: CallableSig,
     callee: Callee,
     /// Whether this is a method that was called with method call syntax.
@@ -5825,7 +5891,7 @@ pub enum CallableKind {
     FnImpl(FnTrait),
 }
 
-impl Callable {
+impl<'db> Callable<'db> {
     pub fn kind(&self) -> CallableKind {
         match self.callee {
             Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
@@ -5840,7 +5906,7 @@ impl Callable {
             Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_),
         }
     }
-    pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> {
+    pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> {
         let func = match self.callee {
             Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
             _ => return None,
@@ -5851,7 +5917,7 @@ impl Callable {
     pub fn n_params(&self) -> usize {
         self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
     }
-    pub fn params(&self) -> Vec<Param> {
+    pub fn params(&self) -> Vec<Param<'db>> {
         self.sig
             .params()
             .iter()
@@ -5861,14 +5927,14 @@ impl Callable {
             .map(|(idx, ty)| Param { func: self.callee.clone(), idx, ty })
             .collect()
     }
-    pub fn return_type(&self) -> Type {
+    pub fn return_type(&self) -> Type<'db> {
         self.ty.derived(self.sig.ret().clone())
     }
     pub fn sig(&self) -> &CallableSig {
         &self.sig
     }
 
-    pub fn ty(&self) -> &Type {
+    pub fn ty(&self) -> &Type<'db> {
         &self.ty
     }
 }
@@ -6070,9 +6136,9 @@ impl From<ItemInNs> for ScopeDef {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Adjustment {
-    pub source: Type,
-    pub target: Type,
+pub struct Adjustment<'db> {
+    pub source: Type<'db>,
+    pub target: Type<'db>,
     pub kind: Adjust,
 }
 
@@ -6171,7 +6237,7 @@ impl HasCrate for TypeAlias {
     }
 }
 
-impl HasCrate for Type {
+impl HasCrate for Type<'_> {
     fn krate(&self, _db: &dyn HirDatabase) -> Crate {
         self.env.krate.into()
     }
@@ -6325,9 +6391,9 @@ pub enum DocLinkDef {
     SelfType(Trait),
 }
 
-fn push_ty_diagnostics(
-    db: &dyn HirDatabase,
-    acc: &mut Vec<AnyDiagnostic>,
+fn push_ty_diagnostics<'db>(
+    db: &'db dyn HirDatabase,
+    acc: &mut Vec<AnyDiagnostic<'db>>,
     diagnostics: Option<ThinArc<(), TyLoweringDiagnostic>>,
     source_map: &ExpressionStoreSourceMap,
 ) {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 10498958242..d96975831e0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -123,15 +123,15 @@ impl PathResolutionPerNs {
 }
 
 #[derive(Debug)]
-pub struct TypeInfo {
+pub struct TypeInfo<'db> {
     /// The original type of the expression or pattern.
-    pub original: Type,
+    pub original: Type<'db>,
     /// The adjusted type, if an adjustment happened.
-    pub adjusted: Option<Type>,
+    pub adjusted: Option<Type<'db>>,
 }
 
-impl TypeInfo {
-    pub fn original(self) -> Type {
+impl<'db> TypeInfo<'db> {
+    pub fn original(self) -> Type<'db> {
         self.original
     }
 
@@ -140,7 +140,7 @@ impl TypeInfo {
     }
 
     /// The adjusted type, or the original in case no adjustments occurred.
-    pub fn adjusted(self) -> Type {
+    pub fn adjusted(self) -> Type<'db> {
         self.adjusted.unwrap_or(self.original)
     }
 }
@@ -1534,7 +1534,7 @@ impl<'db> SemanticsImpl<'db> {
         Some(Label { parent, label_id })
     }
 
-    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
+    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type<'db>> {
         let analyze = self.analyze(ty.syntax())?;
         analyze.type_of_type(self.db, ty)
     }
@@ -1553,7 +1553,7 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
-    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
+    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment<'db>>> {
         let mutability = |m| match m {
             hir_ty::Mutability::Not => Mutability::Shared,
             hir_ty::Mutability::Mut => Mutability::Mut,
@@ -1596,13 +1596,13 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
-    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
+    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo<'db>> {
         self.analyze(expr.syntax())?
             .type_of_expr(self.db, expr)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
     }
 
-    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
+    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo<'db>> {
         self.analyze(pat.syntax())?
             .type_of_pat(self.db, pat)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
@@ -1611,15 +1611,15 @@ impl<'db> SemanticsImpl<'db> {
     /// It also includes the changes that binding mode makes in the type. For example in
     /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
     /// of this function is `&mut Option<T>`
-    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
+    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type<'db>> {
         self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
     }
 
-    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
+    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type<'db>> {
         self.analyze(param.syntax())?.type_of_self(self.db, param)
     }
 
-    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type<'db>; 1]> {
         self.analyze(pat.syntax())
             .and_then(|it| it.pattern_adjustments(self.db, pat))
             .unwrap_or_default()
@@ -1629,7 +1629,7 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
     }
 
-    pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable> {
+    pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable<'db>> {
         self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call)
     }
 
@@ -1641,7 +1641,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_method_call_fallback(
         &self,
         call: &ast::MethodCallExpr,
-    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
     }
 
@@ -1649,10 +1649,10 @@ impl<'db> SemanticsImpl<'db> {
     // FIXME: better api for the trait environment
     pub fn resolve_trait_impl_method(
         &self,
-        env: Type,
+        env: Type<'db>,
         trait_: Trait,
         func: Function,
-        subst: impl IntoIterator<Item = Type>,
+        subst: impl IntoIterator<Item = Type<'db>>,
     ) -> Option<Function> {
         let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
         for s in subst {
@@ -1691,7 +1691,10 @@ impl<'db> SemanticsImpl<'db> {
 
     // This does not resolve the method call to the correct trait impl!
     // We should probably fix that.
-    pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
+    pub fn resolve_method_call_as_callable(
+        &self,
+        call: &ast::MethodCallExpr,
+    ) -> Option<Callable<'db>> {
         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
     }
 
@@ -1702,14 +1705,15 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_field_fallback(
         &self,
         field: &ast::FieldExpr,
-    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
+    {
         self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
     }
 
     pub fn resolve_record_field(
         &self,
         field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type)> {
+    ) -> Option<(Field, Option<Local>, Type<'db>)> {
         self.resolve_record_field_with_substitution(field)
             .map(|(field, local, ty, _)| (field, local, ty))
     }
@@ -1717,18 +1721,21 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_record_field_with_substitution(
         &self,
         field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {
         self.analyze(field.syntax())?.resolve_record_field(self.db, field)
     }
 
-    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
+    pub fn resolve_record_pat_field(
+        &self,
+        field: &ast::RecordPatField,
+    ) -> Option<(Field, Type<'db>)> {
         self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
     }
 
     pub fn resolve_record_pat_field_with_subst(
         &self,
         field: &ast::RecordPatField,
-    ) -> Option<(Field, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
         self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
     }
 
@@ -1801,7 +1808,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_path_with_subst(
         &self,
         path: &ast::Path,
-    ) -> Option<(PathResolution, Option<GenericSubstitution>)> {
+    ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
         self.analyze(path.syntax())?.resolve_path(self.db, path)
     }
 
@@ -1812,7 +1819,7 @@ impl<'db> SemanticsImpl<'db> {
     pub fn resolve_offset_of_field(
         &self,
         name_ref: &ast::NameRef,
-    ) -> Option<(Either<Variant, Field>, GenericSubstitution)> {
+    ) -> Option<(Either<Variant, Field>, GenericSubstitution<'db>)> {
         self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref)
     }
 
@@ -1834,13 +1841,19 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
     }
 
-    pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
+    pub fn record_literal_missing_fields(
+        &self,
+        literal: &ast::RecordExpr,
+    ) -> Vec<(Field, Type<'db>)> {
         self.analyze(literal.syntax())
             .and_then(|it| it.record_literal_missing_fields(self.db, literal))
             .unwrap_or_default()
     }
 
-    pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
+    pub fn record_pattern_missing_fields(
+        &self,
+        pattern: &ast::RecordPat,
+    ) -> Vec<(Field, Type<'db>)> {
         self.analyze(pattern.syntax())
             .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
             .unwrap_or_default()
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 3273358b78e..48543ca581f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -257,7 +257,11 @@ impl<'db> SourceAnalyzer<'db> {
         infer.expr_adjustments.get(&expr_id).map(|v| &**v)
     }
 
-    pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
+    pub(crate) fn type_of_type(
+        &self,
+        db: &'db dyn HirDatabase,
+        ty: &ast::Type,
+    ) -> Option<Type<'db>> {
         let type_ref = self.type_id(ty)?;
         let ty = TyLoweringContext::new(
             db,
@@ -277,7 +281,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         expr: &ast::Expr,
-    ) -> Option<(Type, Option<Type>)> {
+    ) -> Option<(Type<'db>, Option<Type<'db>>)> {
         let expr_id = self.expr_id(expr.clone())?;
         let infer = self.infer()?;
         let coerced = expr_id
@@ -293,7 +297,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pat: &ast::Pat,
-    ) -> Option<(Type, Option<Type>)> {
+    ) -> Option<(Type<'db>, Option<Type<'db>>)> {
         let expr_or_pat_id = self.pat_id(pat)?;
         let infer = self.infer()?;
         let coerced = match expr_or_pat_id {
@@ -316,7 +320,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pat: &ast::IdentPat,
-    ) -> Option<Type> {
+    ) -> Option<Type<'db>> {
         let binding_id = self.binding_id_of_pat(pat)?;
         let infer = self.infer()?;
         let ty = infer[binding_id].clone();
@@ -328,7 +332,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         _param: &ast::SelfParam,
-    ) -> Option<Type> {
+    ) -> Option<Type<'db>> {
         let binding = self.body()?.self_param?;
         let ty = self.infer()?[binding].clone();
         Some(Type::new_with_resolver(db, &self.resolver, ty))
@@ -353,7 +357,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pat: &ast::Pat,
-    ) -> Option<SmallVec<[Type; 1]>> {
+    ) -> Option<SmallVec<[Type<'db>; 1]>> {
         let pat_id = self.pat_id(pat)?;
         let infer = self.infer()?;
         Some(
@@ -370,7 +374,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
-    ) -> Option<Callable> {
+    ) -> Option<Callable<'db>> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
         let (func, substs) = self.infer()?.method_resolution(expr_id)?;
         let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
@@ -395,7 +399,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
-    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
         let inference_result = self.infer()?;
         match inference_result.method_resolution(expr_id) {
@@ -419,7 +423,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         call: &ast::Expr,
-    ) -> Option<Callable> {
+    ) -> Option<Callable<'db>> {
         let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
         adjusted.unwrap_or(orig).as_callable(db)
     }
@@ -440,7 +444,7 @@ impl<'db> SourceAnalyzer<'db> {
         field_expr: ExprId,
         infer: &InferenceResult,
         db: &'db dyn HirDatabase,
-    ) -> Option<GenericSubstitution> {
+    ) -> Option<GenericSubstitution<'db>> {
         let body = self.store()?;
         if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
             let (adt, subst) = type_of_expr_including_adjust(infer, object_expr)?.as_adt()?;
@@ -457,7 +461,8 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         field: &ast::FieldExpr,
-    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
+    ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)>
+    {
         let (def, ..) = self.body_()?;
         let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
         let inference_result = self.infer()?;
@@ -680,7 +685,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Option<Local>, Type<'db>, GenericSubstitution<'db>)> {
         let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let expr = ast::Expr::from(record_expr);
         let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?;
@@ -724,7 +729,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         field: &ast::RecordPatField,
-    ) -> Option<(Field, Type, GenericSubstitution)> {
+    ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
         let field_name = field.field_name()?.as_name();
         let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let pat_id = self.pat_id(&record_pat.into())?;
@@ -779,7 +784,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         name_ref: &ast::NameRef,
-    ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> {
+    ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution<'db>)> {
         let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;
         let container = offset_of_expr.ty()?;
         let container = self.type_of_type(db, &container)?;
@@ -851,7 +856,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         path: &ast::Path,
-    ) -> Option<(PathResolution, Option<GenericSubstitution>)> {
+    ) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
         let parent = path.syntax().parent();
         let parent = || parent.clone();
 
@@ -1216,7 +1221,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         literal: &ast::RecordExpr,
-    ) -> Option<Vec<(Field, Type)>> {
+    ) -> Option<Vec<(Field, Type<'db>)>> {
         let body = self.store()?;
         let infer = self.infer()?;
 
@@ -1239,7 +1244,7 @@ impl<'db> SourceAnalyzer<'db> {
         &self,
         db: &'db dyn HirDatabase,
         pattern: &ast::RecordPat,
-    ) -> Option<Vec<(Field, Type)>> {
+    ) -> Option<Vec<(Field, Type<'db>)>> {
         let body = self.store()?;
         let infer = self.infer()?;
 
@@ -1258,7 +1263,7 @@ impl<'db> SourceAnalyzer<'db> {
         substs: &Substitution,
         variant: VariantId,
         missing_fields: Vec<LocalFieldId>,
-    ) -> Vec<(Field, Type)> {
+    ) -> Vec<(Field, Type<'db>)> {
         let field_types = db.field_types(variant);
 
         missing_fields
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
index af72179305c..4b354e64062 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -22,20 +22,20 @@ enum NewTypesKey {
 /// Helper enum to squash big number of alternative trees into `Many` variant as there is too many
 /// to take into account.
 #[derive(Debug)]
-enum AlternativeExprs {
+enum AlternativeExprs<'db> {
     /// There are few trees, so we keep track of them all
-    Few(FxHashSet<Expr>),
+    Few(FxHashSet<Expr<'db>>),
     /// There are too many trees to keep track of
     Many,
 }
 
-impl AlternativeExprs {
+impl<'db> AlternativeExprs<'db> {
     /// Construct alternative trees
     ///
     /// # Arguments
     /// `threshold` - threshold value for many trees (more than that is many)
     /// `exprs` - expressions iterator
-    fn new(threshold: usize, exprs: impl Iterator<Item = Expr>) -> AlternativeExprs {
+    fn new(threshold: usize, exprs: impl Iterator<Item = Expr<'db>>) -> AlternativeExprs<'db> {
         let mut it = AlternativeExprs::Few(Default::default());
         it.extend_with_threshold(threshold, exprs);
         it
@@ -45,7 +45,7 @@ impl AlternativeExprs {
     ///
     /// # Arguments
     /// `ty` - Type of expressions queried (this is used to give type to `Expr::Many`)
-    fn exprs(&self, ty: &Type) -> Vec<Expr> {
+    fn exprs(&self, ty: &Type<'db>) -> Vec<Expr<'db>> {
         match self {
             AlternativeExprs::Few(exprs) => exprs.iter().cloned().collect(),
             AlternativeExprs::Many => vec![Expr::Many(ty.clone())],
@@ -57,7 +57,7 @@ impl AlternativeExprs {
     /// # Arguments
     /// `threshold` - threshold value for many trees (more than that is many)
     /// `exprs` - expressions iterator
-    fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator<Item = Expr>) {
+    fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator<Item = Expr<'db>>) {
         match self {
             AlternativeExprs::Few(tts) => {
                 for it in exprs {
@@ -88,20 +88,20 @@ impl AlternativeExprs {
 /// Both of them are to speed up the term search by leaving out types / ScopeDefs that likely do
 /// not produce any new results.
 #[derive(Default, Debug)]
-struct LookupTable {
+struct LookupTable<'db> {
     /// All the `Expr`s in "value" produce the type of "key"
-    data: FxHashMap<Type, AlternativeExprs>,
+    data: FxHashMap<Type<'db>, AlternativeExprs<'db>>,
     /// New types reached since last query by the `NewTypesKey`
-    new_types: FxHashMap<NewTypesKey, Vec<Type>>,
+    new_types: FxHashMap<NewTypesKey, Vec<Type<'db>>>,
     /// Types queried but not present
-    types_wishlist: FxHashSet<Type>,
+    types_wishlist: FxHashSet<Type<'db>>,
     /// Threshold to squash trees to `Many`
     many_threshold: usize,
 }
 
-impl LookupTable {
+impl<'db> LookupTable<'db> {
     /// Initialize lookup table
-    fn new(many_threshold: usize, goal: Type) -> Self {
+    fn new(many_threshold: usize, goal: Type<'db>) -> Self {
         let mut res = Self { many_threshold, ..Default::default() };
         res.new_types.insert(NewTypesKey::ImplMethod, Vec::new());
         res.new_types.insert(NewTypesKey::StructProjection, Vec::new());
@@ -110,7 +110,7 @@ impl LookupTable {
     }
 
     /// Find all `Expr`s that unify with the `ty`
-    fn find(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
+    fn find(&mut self, db: &'db dyn HirDatabase, ty: &Type<'db>) -> Option<Vec<Expr<'db>>> {
         let res = self
             .data
             .iter()
@@ -135,7 +135,7 @@ impl LookupTable {
     ///
     /// For example if we have type `i32` in data and we query for `&i32` it map all the type
     /// trees we have for `i32` with `Expr::Reference` and returns them.
-    fn find_autoref(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option<Vec<Expr>> {
+    fn find_autoref(&mut self, db: &'db dyn HirDatabase, ty: &Type<'db>) -> Option<Vec<Expr<'db>>> {
         let res = self
             .data
             .iter()
@@ -174,7 +174,7 @@ impl LookupTable {
     /// Note that the types have to be the same, unification is not enough as unification is not
     /// transitive. For example Vec<i32> and FxHashSet<i32> both unify with Iterator<Item = i32>,
     /// but they clearly do not unify themselves.
-    fn insert(&mut self, ty: Type, exprs: impl Iterator<Item = Expr>) {
+    fn insert(&mut self, ty: Type<'db>, exprs: impl Iterator<Item = Expr<'db>>) {
         match self.data.get_mut(&ty) {
             Some(it) => {
                 it.extend_with_threshold(self.many_threshold, exprs);
@@ -192,14 +192,14 @@ impl LookupTable {
     }
 
     /// Iterate all the reachable types
-    fn iter_types(&self) -> impl Iterator<Item = Type> + '_ {
+    fn iter_types(&self) -> impl Iterator<Item = Type<'db>> + '_ {
         self.data.keys().cloned()
     }
 
     /// Query new types reached since last query by key
     ///
     /// Create new key if you wish to query it to avoid conflicting with existing queries.
-    fn new_types(&mut self, key: NewTypesKey) -> Vec<Type> {
+    fn new_types(&mut self, key: NewTypesKey) -> Vec<Type<'db>> {
         match self.new_types.get_mut(&key) {
             Some(it) => std::mem::take(it),
             None => Vec::new(),
@@ -207,20 +207,20 @@ impl LookupTable {
     }
 
     /// Types queried but not found
-    fn types_wishlist(&mut self) -> &FxHashSet<Type> {
+    fn types_wishlist(&mut self) -> &FxHashSet<Type<'db>> {
         &self.types_wishlist
     }
 }
 
 /// Context for the `term_search` function
 #[derive(Debug)]
-pub struct TermSearchCtx<'a, DB: HirDatabase> {
+pub struct TermSearchCtx<'db, DB: HirDatabase> {
     /// Semantics for the program
-    pub sema: &'a Semantics<'a, DB>,
+    pub sema: &'db Semantics<'db, DB>,
     /// Semantic scope, captures context for the term search
-    pub scope: &'a SemanticsScope<'a>,
+    pub scope: &'db SemanticsScope<'db>,
     /// Target / expected output type
-    pub goal: Type,
+    pub goal: Type<'db>,
     /// Configuration for term search
     pub config: TermSearchConfig,
 }
@@ -263,7 +263,7 @@ impl Default for TermSearchConfig {
 /// Note that there are usually more ways we can get to the `goal` type but some are discarded to
 /// reduce the memory consumption. It is also unlikely anyone is willing ti browse through
 /// thousands of possible responses so we currently take first 10 from every tactic.
-pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
+pub fn term_search<'db, DB: HirDatabase>(ctx: &'db TermSearchCtx<'db, DB>) -> Vec<Expr<'db>> {
     let module = ctx.scope.module();
     let mut defs = FxHashSet::default();
     defs.insert(ScopeDef::ModuleDef(ModuleDef::Module(module)));
@@ -285,7 +285,7 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
     };
 
     // Try trivial tactic first, also populates lookup table
-    let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
+    let mut solutions: Vec<Expr<'db>> = tactics::trivial(ctx, &defs, &mut lookup).collect();
     // Use well known types tactic before iterations as it does not depend on other tactics
     solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
     solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup));
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
index 78ee3b5aa68..843831948ad 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -59,7 +59,7 @@ fn mod_item_path_str(
 /// So in short it pretty much gives us a way to get type `Option<i32>` using the items we have in
 /// scope.
 #[derive(Debug, Clone, Eq, Hash, PartialEq)]
-pub enum Expr {
+pub enum Expr<'db> {
     /// Constant
     Const(Const),
     /// Static variable
@@ -69,26 +69,31 @@ pub enum Expr {
     /// Constant generic parameter
     ConstParam(ConstParam),
     /// Well known type (such as `true` for bool)
-    FamousType { ty: Type, value: &'static str },
+    FamousType { ty: Type<'db>, value: &'static str },
     /// Function call (does not take self param)
-    Function { func: Function, generics: Vec<Type>, params: Vec<Expr> },
+    Function { func: Function, generics: Vec<Type<'db>>, params: Vec<Expr<'db>> },
     /// Method call (has self param)
-    Method { func: Function, generics: Vec<Type>, target: Box<Expr>, params: Vec<Expr> },
+    Method {
+        func: Function,
+        generics: Vec<Type<'db>>,
+        target: Box<Expr<'db>>,
+        params: Vec<Expr<'db>>,
+    },
     /// Enum variant construction
-    Variant { variant: Variant, generics: Vec<Type>, params: Vec<Expr> },
+    Variant { variant: Variant, generics: Vec<Type<'db>>, params: Vec<Expr<'db>> },
     /// Struct construction
-    Struct { strukt: Struct, generics: Vec<Type>, params: Vec<Expr> },
+    Struct { strukt: Struct, generics: Vec<Type<'db>>, params: Vec<Expr<'db>> },
     /// Tuple construction
-    Tuple { ty: Type, params: Vec<Expr> },
+    Tuple { ty: Type<'db>, params: Vec<Expr<'db>> },
     /// Struct field access
-    Field { expr: Box<Expr>, field: Field },
+    Field { expr: Box<Expr<'db>>, field: Field },
     /// Passing type as reference (with `&`)
-    Reference(Box<Expr>),
+    Reference(Box<Expr<'db>>),
     /// Indicates possibility of many different options that all evaluate to `ty`
-    Many(Type),
+    Many(Type<'db>),
 }
 
-impl Expr {
+impl<'db> Expr<'db> {
     /// Generate source code for type tree.
     ///
     /// Note that trait imports are not added to generated code.
@@ -96,8 +101,8 @@ impl Expr {
     /// by `traits_used` method are also imported.
     pub fn gen_source_code(
         &self,
-        sema_scope: &SemanticsScope<'_>,
-        many_formatter: &mut dyn FnMut(&Type) -> String,
+        sema_scope: &SemanticsScope<'db>,
+        many_formatter: &mut dyn FnMut(&Type<'db>) -> String,
         cfg: ImportPathConfig,
         display_target: DisplayTarget,
     ) -> Result<String, DisplaySourceCodeError> {
@@ -298,7 +303,7 @@ impl Expr {
     /// Get type of the type tree.
     ///
     /// Same as getting the type of root node
-    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+    pub fn ty(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         match self {
             Expr::Const(it) => it.ty(db),
             Expr::Static(it) => it.ty(db),
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
index bcff44fcd01..9df131f90e4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -40,11 +40,11 @@ use super::{LookupTable, NewTypesKey, TermSearchCtx};
 ///
 /// _Note that there is no use of calling this tactic in every iteration as the output does not
 /// depend on the current state of `lookup`_
-pub(super) fn trivial<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
+    lookup: &'lt mut LookupTable<'db>,
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     defs.iter().filter_map(|def| {
         let expr = match def {
@@ -104,11 +104,11 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
 ///
 /// _Note that there is no use of calling this tactic in every iteration as the output does not
 /// depend on the current state of `lookup`_
-pub(super) fn assoc_const<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
+    lookup: &'lt mut LookupTable<'db>,
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
 
@@ -152,12 +152,12 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn data_constructor<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -199,14 +199,14 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
                 let generics: Vec<_> = ty.type_arguments().collect();
 
                 // Early exit if some param cannot be filled from lookup
-                let param_exprs: Vec<Vec<Expr>> = fields
+                let param_exprs: Vec<Vec<Expr<'_>>> = fields
                     .into_iter()
                     .map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())))
                     .collect::<Option<_>>()?;
 
                 // Note that we need special case for 0 param constructors because of multi cartesian
                 // product
-                let exprs: Vec<Expr> = if param_exprs.is_empty() {
+                let exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                     vec![Expr::Struct { strukt, generics, params: Vec::new() }]
                 } else {
                     param_exprs
@@ -247,7 +247,7 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
                     .into_iter()
                     .filter_map(|variant| {
                         // Early exit if some param cannot be filled from lookup
-                        let param_exprs: Vec<Vec<Expr>> = variant
+                        let param_exprs: Vec<Vec<Expr<'_>>> = variant
                             .fields(db)
                             .into_iter()
                             .map(|field| {
@@ -257,7 +257,7 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
 
                         // Note that we need special case for 0 param constructors because of multi cartesian
                         // product
-                        let variant_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                        let variant_exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                             vec![Expr::Variant {
                                 variant,
                                 generics: generics.clone(),
@@ -301,12 +301,12 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn free_function<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     defs.iter()
@@ -375,7 +375,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
                         }
 
                         // Early exit if some param cannot be filled from lookup
-                        let param_exprs: Vec<Vec<Expr>> = it
+                        let param_exprs: Vec<Vec<Expr<'_>>> = it
                             .params_without_self_with_args(db, generics.iter().cloned())
                             .into_iter()
                             .map(|field| {
@@ -389,7 +389,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
 
                         // Note that we need special case for 0 param constructors because of multi cartesian
                         // product
-                        let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
+                        let fn_exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                             vec![Expr::Function { func: *it, generics, params: Vec::new() }]
                         } else {
                             param_exprs
@@ -432,12 +432,12 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn impl_method<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -507,14 +507,14 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
             let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup");
 
             // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> = it
+            let param_exprs: Vec<Vec<Expr<'_>>> = it
                 .params_without_self_with_args(db, ty.type_arguments())
                 .into_iter()
                 .map(|field| lookup.find_autoref(db, field.ty()))
                 .collect::<Option<_>>()?;
 
             let generics: Vec<_> = ty.type_arguments().collect();
-            let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs)
+            let fn_exprs: Vec<Expr<'_>> = std::iter::once(target_type_exprs)
                 .chain(param_exprs)
                 .multi_cartesian_product()
                 .map(|params| {
@@ -547,12 +547,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn struct_projection<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -589,11 +589,11 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
-pub(super) fn famous_types<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
+    lookup: &'lt mut LookupTable<'db>,
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     [
@@ -620,12 +620,12 @@ pub(super) fn famous_types<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn impl_static_method<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     lookup
@@ -683,7 +683,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
             }
 
             // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> = it
+            let param_exprs: Vec<Vec<Expr<'_>>> = it
                 .params_without_self_with_args(db, ty.type_arguments())
                 .into_iter()
                 .map(|field| lookup.find_autoref(db, field.ty()))
@@ -692,7 +692,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
             // Note that we need special case for 0 param constructors because of multi cartesian
             // product
             let generics = ty.type_arguments().collect();
-            let fn_exprs: Vec<Expr> = if param_exprs.is_empty() {
+            let fn_exprs: Vec<Expr<'_>> = if param_exprs.is_empty() {
                 vec![Expr::Function { func: it, generics, params: Vec::new() }]
             } else {
                 param_exprs
@@ -722,12 +722,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
 /// * `should_continue` - Function that indicates when to stop iterating
-pub(super) fn make_tuple<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
+pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>(
+    ctx: &'a TermSearchCtx<'db, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
+    lookup: &'lt mut LookupTable<'db>,
     should_continue: &'a dyn std::ops::Fn() -> bool,
-) -> impl Iterator<Item = Expr> + 'a {
+) -> impl Iterator<Item = Expr<'db>> + use<'a, 'db, 'lt, DB> {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
 
@@ -749,15 +749,15 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
             }
 
             // Early exit if some param cannot be filled from lookup
-            let param_exprs: Vec<Vec<Expr>> =
+            let param_exprs: Vec<Vec<Expr<'db>>> =
                 ty.type_arguments().map(|field| lookup.find(db, &field)).collect::<Option<_>>()?;
 
-            let exprs: Vec<Expr> = param_exprs
+            let exprs: Vec<Expr<'db>> = param_exprs
                 .into_iter()
                 .multi_cartesian_product()
                 .filter(|_| should_continue())
                 .map(|params| {
-                    let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
+                    let tys: Vec<Type<'_>> = params.iter().map(|it| it.ty(db)).collect();
                     let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
 
                     let expr = Expr::Tuple { ty: tuple_ty.clone(), params };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index fb569f8cdae..57ced8d8534 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -22,6 +22,7 @@ pub struct AssistConfig {
     pub term_search_borrowck: bool,
     pub code_action_grouping: bool,
     pub expr_fill_default: ExprFillDefaultMode,
+    pub prefer_self_ty: bool,
 }
 
 impl AssistConfig {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
index 9eb9452a2b8..207a7548f49 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs
@@ -95,7 +95,7 @@ impl<'a> AssistContext<'a> {
         }
     }
 
-    pub(crate) fn db(&self) -> &RootDatabase {
+    pub(crate) fn db(&self) -> &'a RootDatabase {
         self.sema.db
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 6a55f39e693..9f9d21923ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -192,7 +192,7 @@ fn add_missing_impl_members_inner(
 fn try_gen_trait_body(
     ctx: &AssistContext<'_>,
     func: &ast::Fn,
-    trait_ref: hir::TraitRef,
+    trait_ref: hir::TraitRef<'_>,
     impl_def: &ast::Impl,
     edition: Edition,
 ) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 858d4369914..1ece7ddab10 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -1,12 +1,13 @@
 use std::iter::{self, Peekable};
 
 use either::Either;
-use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym};
+use hir::{Adt, AsAssocItem, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym};
 use ide_db::RootDatabase;
 use ide_db::assists::ExprFillDefaultMode;
 use ide_db::syntax_helpers::suggest_name;
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 use itertools::Itertools;
+use syntax::ToSmolStr;
 use syntax::ast::edit::IndentLevel;
 use syntax::ast::edit_in_place::Indent;
 use syntax::ast::syntax_factory::SyntaxFactory;
@@ -79,12 +80,20 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 
     let make = SyntaxFactory::with_mappings();
 
-    let module = ctx.sema.scope(expr.syntax())?.module();
+    let scope = ctx.sema.scope(expr.syntax())?;
+    let module = scope.module();
+    let self_ty = if ctx.config.prefer_self_ty {
+        scope
+            .containing_function()
+            .and_then(|function| function.as_assoc_item(ctx.db())?.implementing_ty(ctx.db()))
+    } else {
+        None
+    };
     let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
         Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
         bool,
         bool,
-    ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
+    ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
         let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
 
         let variants = enum_def.variants(ctx.db());
@@ -102,8 +111,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             })
             .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 
-        let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option().map(lift_enum);
-        let missing_pats: Box<dyn Iterator<Item = _>> = if Some(enum_def) == option_enum {
+        let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option();
+        let missing_pats: Box<dyn Iterator<Item = _>> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum)
+        {
             // Match `Some` variant first.
             cov_mark::hit!(option_order);
             Box::new(missing_pats.rev())
@@ -111,7 +121,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             Box::new(missing_pats)
         };
         (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants)
-    } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
+    } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) {
         let is_non_exhaustive =
             enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate()));
 
@@ -159,7 +169,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             is_non_exhaustive,
             has_hidden_variants,
         )
-    } else if let Some((enum_def, len)) = resolve_array_of_enum_def(&ctx.sema, &expr) {
+    } else if let Some((enum_def, len)) =
+        resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref())
+    {
         let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
         let variants = enum_def.variants(ctx.db());
 
@@ -373,23 +385,23 @@ fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
     }
 }
 
-#[derive(Eq, PartialEq, Clone, Copy)]
+#[derive(Eq, PartialEq, Clone)]
 enum ExtendedEnum {
     Bool,
-    Enum(hir::Enum),
+    Enum { enum_: hir::Enum, use_self: bool },
 }
 
 #[derive(Eq, PartialEq, Clone, Copy, Debug)]
 enum ExtendedVariant {
     True,
     False,
-    Variant(hir::Variant),
+    Variant { variant: hir::Variant, use_self: bool },
 }
 
 impl ExtendedVariant {
     fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool {
         match self {
-            ExtendedVariant::Variant(var) => {
+            ExtendedVariant::Variant { variant: var, .. } => {
                 var.attrs(db).has_doc_hidden() && var.module(db).krate() != krate
             }
             _ => false,
@@ -397,25 +409,35 @@ impl ExtendedVariant {
     }
 }
 
-fn lift_enum(e: hir::Enum) -> ExtendedEnum {
-    ExtendedEnum::Enum(e)
-}
-
 impl ExtendedEnum {
-    fn is_non_exhaustive(self, db: &RootDatabase, krate: Crate) -> bool {
+    fn enum_(
+        db: &RootDatabase,
+        enum_: hir::Enum,
+        enum_ty: &hir::Type<'_>,
+        self_ty: Option<&hir::Type<'_>>,
+    ) -> Self {
+        ExtendedEnum::Enum {
+            enum_,
+            use_self: self_ty.is_some_and(|self_ty| self_ty.could_unify_with_deeply(db, enum_ty)),
+        }
+    }
+
+    fn is_non_exhaustive(&self, db: &RootDatabase, krate: Crate) -> bool {
         match self {
-            ExtendedEnum::Enum(e) => {
+            ExtendedEnum::Enum { enum_: e, .. } => {
                 e.attrs(db).by_key(sym::non_exhaustive).exists() && e.module(db).krate() != krate
             }
             _ => false,
         }
     }
 
-    fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> {
-        match self {
-            ExtendedEnum::Enum(e) => {
-                e.variants(db).into_iter().map(ExtendedVariant::Variant).collect::<Vec<_>>()
-            }
+    fn variants(&self, db: &RootDatabase) -> Vec<ExtendedVariant> {
+        match *self {
+            ExtendedEnum::Enum { enum_: e, use_self } => e
+                .variants(db)
+                .into_iter()
+                .map(|variant| ExtendedVariant::Variant { variant, use_self })
+                .collect::<Vec<_>>(),
             ExtendedEnum::Bool => {
                 Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False])
             }
@@ -423,9 +445,13 @@ impl ExtendedEnum {
     }
 }
 
-fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> {
+fn resolve_enum_def(
+    sema: &Semantics<'_, RootDatabase>,
+    expr: &ast::Expr,
+    self_ty: Option<&hir::Type<'_>>,
+) -> Option<ExtendedEnum> {
     sema.type_of_expr(expr)?.adjusted().autoderef(sema.db).find_map(|ty| match ty.as_adt() {
-        Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)),
+        Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)),
         _ => ty.is_bool().then_some(ExtendedEnum::Bool),
     })
 }
@@ -433,6 +459,7 @@ fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Opt
 fn resolve_tuple_of_enum_def(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
+    self_ty: Option<&hir::Type<'_>>,
 ) -> Option<Vec<ExtendedEnum>> {
     sema.type_of_expr(expr)?
         .adjusted()
@@ -441,7 +468,7 @@ fn resolve_tuple_of_enum_def(
         .map(|ty| {
             ty.autoderef(sema.db).find_map(|ty| {
                 match ty.as_adt() {
-                    Some(Adt::Enum(e)) => Some(lift_enum(e)),
+                    Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)),
                     // For now we only handle expansion for a tuple of enums. Here
                     // we map non-enum items to None and rely on `collect` to
                     // convert Vec<Option<hir::Enum>> into Option<Vec<hir::Enum>>.
@@ -456,10 +483,11 @@ fn resolve_tuple_of_enum_def(
 fn resolve_array_of_enum_def(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
+    self_ty: Option<&hir::Type<'_>>,
 ) -> Option<(ExtendedEnum, usize)> {
     sema.type_of_expr(expr)?.adjusted().as_array(sema.db).and_then(|(ty, len)| {
         ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
-            Some(Adt::Enum(e)) => Some((lift_enum(e), len)),
+            Some(Adt::Enum(e)) => Some((ExtendedEnum::enum_(sema.db, e, &ty, self_ty), len)),
             _ => ty.is_bool().then_some((ExtendedEnum::Bool, len)),
         })
     })
@@ -474,9 +502,21 @@ fn build_pat(
 ) -> Option<ast::Pat> {
     let db = ctx.db();
     match var {
-        ExtendedVariant::Variant(var) => {
+        ExtendedVariant::Variant { variant: var, use_self } => {
             let edition = module.krate().edition(db);
-            let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
+            let path = if use_self {
+                make::path_from_segments(
+                    [
+                        make::path_segment(make::name_ref_self_ty()),
+                        make::path_segment(make::name_ref(
+                            &var.name(db).display(db, edition).to_smolstr(),
+                        )),
+                    ],
+                    false,
+                )
+            } else {
+                mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition)
+            };
             let fields = var.fields(db);
             let pat: ast::Pat = match var.kind(db) {
                 hir::StructKind::Tuple => {
@@ -509,8 +549,10 @@ fn build_pat(
 
 #[cfg(test)]
 mod tests {
+    use crate::AssistConfig;
     use crate::tests::{
-        check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved,
+        TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_target,
+        check_assist_unresolved, check_assist_with_config,
     };
 
     use super::add_missing_match_arms;
@@ -2095,4 +2137,111 @@ fn f() {
 "#,
         );
     }
+
+    #[test]
+    fn prefer_self() {
+        check_assist_with_config(
+            add_missing_match_arms,
+            AssistConfig { prefer_self_ty: true, ..TEST_CONFIG },
+            r#"
+enum Foo {
+    Bar,
+    Baz,
+}
+
+impl Foo {
+    fn qux(&self) {
+        match self {
+            $0_ => {}
+        }
+    }
+}
+            "#,
+            r#"
+enum Foo {
+    Bar,
+    Baz,
+}
+
+impl Foo {
+    fn qux(&self) {
+        match self {
+            Self::Bar => ${1:todo!()},
+            Self::Baz => ${2:todo!()},$0
+        }
+    }
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn prefer_self_with_generics() {
+        check_assist_with_config(
+            add_missing_match_arms,
+            AssistConfig { prefer_self_ty: true, ..TEST_CONFIG },
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(&self) {
+        match self {
+            $0_ => {}
+        }
+    }
+}
+            "#,
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(&self) {
+        match self {
+            Self::Bar(${1:_}) => ${2:todo!()},
+            Self::Baz => ${3:todo!()},$0
+        }
+    }
+}
+            "#,
+        );
+        check_assist_with_config(
+            add_missing_match_arms,
+            AssistConfig { prefer_self_ty: true, ..TEST_CONFIG },
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(v: Foo<i32>) {
+        match v {
+            $0_ => {}
+        }
+    }
+}
+            "#,
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+impl<T> Foo<T> {
+    fn qux(v: Foo<i32>) {
+        match v {
+            Foo::Bar(${1:_}) => ${2:todo!()},
+            Foo::Baz => ${3:todo!()},$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 f3243d369a0..bb6a10d40b7 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
@@ -164,9 +164,9 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     Some(())
 }
 
-pub(super) fn find_importable_node(
-    ctx: &AssistContext<'_>,
-) -> Option<(ImportAssets, SyntaxNode, Option<Type>)> {
+pub(super) fn find_importable_node<'a: 'db, 'db>(
+    ctx: &'a AssistContext<'db>,
+) -> Option<(ImportAssets<'db>, SyntaxNode, Option<Type<'db>>)> {
     // Deduplicate this with the `expected_type_and_name` logic for completions
     let expected = |expr_or_pat: Either<ast::Expr, ast::Pat>| match expr_or_pat {
         Either::Left(expr) => {
@@ -226,7 +226,7 @@ pub(super) fn find_importable_node(
     }
 }
 
-fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
+fn group_label(import_candidate: &ImportCandidate<'_>) -> GroupLabel {
     let name = match import_candidate {
         ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
         ImportCandidate::TraitAssocItem(candidate) => {
@@ -244,7 +244,7 @@ fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
 pub(crate) fn relevance_score(
     ctx: &AssistContext<'_>,
     import: &LocatedImport,
-    expected: Option<&Type>,
+    expected: Option<&Type<'_>>,
     current_module: Option<&Module>,
 ) -> i32 {
     let mut score = 0;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index cf45ea0a30d..00cbef1c01c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -309,23 +309,23 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
 }
 
 #[derive(Debug)]
-struct Function {
+struct Function<'db> {
     name: ast::NameRef,
     self_param: Option<ast::SelfParam>,
-    params: Vec<Param>,
-    control_flow: ControlFlow,
-    ret_ty: RetType,
+    params: Vec<Param<'db>>,
+    control_flow: ControlFlow<'db>,
+    ret_ty: RetType<'db>,
     body: FunctionBody,
     outliving_locals: Vec<OutlivedLocal>,
     /// Whether at least one of the container's tail expr is contained in the range we're extracting.
     contains_tail_expr: bool,
-    mods: ContainerInfo,
+    mods: ContainerInfo<'db>,
 }
 
 #[derive(Debug)]
-struct Param {
+struct Param<'db> {
     var: Local,
-    ty: hir::Type,
+    ty: hir::Type<'db>,
     move_local: bool,
     requires_mut: bool,
     is_copy: bool,
@@ -340,10 +340,10 @@ enum ParamKind {
 }
 
 #[derive(Debug)]
-enum FunType {
+enum FunType<'db> {
     Unit,
-    Single(hir::Type),
-    Tuple(Vec<hir::Type>),
+    Single(hir::Type<'db>),
+    Tuple(Vec<hir::Type<'db>>),
 }
 
 /// Where to put extracted function definition
@@ -358,19 +358,19 @@ enum Anchor {
 // FIXME: ControlFlow and ContainerInfo both track some function modifiers, feels like these two should
 // probably be merged somehow.
 #[derive(Debug)]
-struct ControlFlow {
-    kind: Option<FlowKind>,
+struct ControlFlow<'db> {
+    kind: Option<FlowKind<'db>>,
     is_async: bool,
     is_unsafe: bool,
 }
 
 /// The thing whose expression we are extracting from. Can be a function, const, static, const arg, ...
 #[derive(Clone, Debug)]
-struct ContainerInfo {
+struct ContainerInfo<'db> {
     is_const: bool,
     parent_loop: Option<SyntaxNode>,
     /// The function's return type, const's type etc.
-    ret_type: Option<hir::Type>,
+    ret_type: Option<hir::Type<'db>>,
     generic_param_lists: Vec<ast::GenericParamList>,
     where_clauses: Vec<ast::WhereClause>,
     edition: Edition,
@@ -389,11 +389,11 @@ struct ContainerInfo {
 /// }
 /// ```
 #[derive(Debug, Clone)]
-enum FlowKind {
+enum FlowKind<'db> {
     /// Return with value (`return $expr;`)
     Return(Option<ast::Expr>),
     Try {
-        kind: TryKind,
+        kind: TryKind<'db>,
     },
     /// Break with label and value (`break 'label $expr;`)
     Break(Option<ast::Lifetime>, Option<ast::Expr>),
@@ -402,18 +402,18 @@ enum FlowKind {
 }
 
 #[derive(Debug, Clone)]
-enum TryKind {
+enum TryKind<'db> {
     Option,
-    Result { ty: hir::Type },
+    Result { ty: hir::Type<'db> },
 }
 
 #[derive(Debug)]
-enum RetType {
-    Expr(hir::Type),
+enum RetType<'db> {
+    Expr(hir::Type<'db>),
     Stmt,
 }
 
-impl RetType {
+impl RetType<'_> {
     fn is_unit(&self) -> bool {
         match self {
             RetType::Expr(ty) => ty.is_unit(),
@@ -456,8 +456,8 @@ impl LocalUsages {
     }
 }
 
-impl Function {
-    fn return_type(&self, ctx: &AssistContext<'_>) -> FunType {
+impl<'db> Function<'db> {
+    fn return_type(&self, ctx: &AssistContext<'db>) -> FunType<'db> {
         match &self.ret_ty {
             RetType::Expr(ty) if ty.is_unit() => FunType::Unit,
             RetType::Expr(ty) => FunType::Single(ty.clone()),
@@ -487,7 +487,7 @@ impl ParamKind {
     }
 }
 
-impl Param {
+impl<'db> Param<'db> {
     fn kind(&self) -> ParamKind {
         match (self.move_local, self.requires_mut, self.is_copy) {
             (false, true, _) => ParamKind::MutRef,
@@ -497,7 +497,7 @@ impl Param {
         }
     }
 
-    fn to_arg(&self, ctx: &AssistContext<'_>, edition: Edition) -> ast::Expr {
+    fn to_arg(&self, ctx: &AssistContext<'db>, edition: Edition) -> ast::Expr {
         let var = path_expr_from_local(ctx, self.var, edition);
         match self.kind() {
             ParamKind::Value | ParamKind::MutValue => var,
@@ -532,8 +532,12 @@ impl Param {
     }
 }
 
-impl TryKind {
-    fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>, edition: Edition) -> Option<TryKind> {
+impl<'db> TryKind<'db> {
+    fn of_ty(
+        ty: hir::Type<'db>,
+        ctx: &AssistContext<'db>,
+        edition: Edition,
+    ) -> Option<TryKind<'db>> {
         if ty.is_unknown() {
             // We favour Result for `expr?`
             return Some(TryKind::Result { ty });
@@ -551,7 +555,7 @@ impl TryKind {
     }
 }
 
-impl FlowKind {
+impl<'db> FlowKind<'db> {
     fn make_result_handler(&self, expr: Option<ast::Expr>) -> ast::Expr {
         match self {
             FlowKind::Return(_) => make::expr_return(expr),
@@ -567,7 +571,7 @@ impl FlowKind {
         }
     }
 
-    fn expr_ty(&self, ctx: &AssistContext<'_>) -> Option<hir::Type> {
+    fn expr_ty(&self, ctx: &AssistContext<'db>) -> Option<hir::Type<'db>> {
         match self {
             FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => {
                 ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted)
@@ -876,11 +880,11 @@ impl FunctionBody {
         (res, self_param)
     }
 
-    fn analyze_container(
+    fn analyze_container<'db>(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         edition: Edition,
-    ) -> Option<(ContainerInfo, bool)> {
+    ) -> Option<(ContainerInfo<'db>, bool)> {
         let mut ancestors = self.parent()?.ancestors();
         let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted);
         let mut parent_loop = None;
@@ -985,7 +989,7 @@ impl FunctionBody {
         ))
     }
 
-    fn return_ty(&self, ctx: &AssistContext<'_>) -> Option<RetType> {
+    fn return_ty<'db>(&self, ctx: &AssistContext<'db>) -> Option<RetType<'db>> {
         match self.tail_expr() {
             Some(expr) => ctx.sema.type_of_expr(&expr).map(TypeInfo::original).map(RetType::Expr),
             None => Some(RetType::Stmt),
@@ -1006,11 +1010,11 @@ impl FunctionBody {
     }
 
     /// Analyses the function body for external control flow.
-    fn external_control_flow(
+    fn external_control_flow<'db>(
         &self,
-        ctx: &AssistContext<'_>,
-        container_info: &ContainerInfo,
-    ) -> Option<ControlFlow> {
+        ctx: &AssistContext<'db>,
+        container_info: &ContainerInfo<'db>,
+    ) -> Option<ControlFlow<'db>> {
         let mut ret_expr = None;
         let mut try_expr = None;
         let mut break_expr = None;
@@ -1096,12 +1100,12 @@ impl FunctionBody {
     /// find variables that should be extracted as params
     ///
     /// Computes additional info that affects param type and mutability
-    fn extracted_function_params(
+    fn extracted_function_params<'db>(
         &self,
-        ctx: &AssistContext<'_>,
-        container_info: &ContainerInfo,
+        ctx: &AssistContext<'db>,
+        container_info: &ContainerInfo<'db>,
         locals: FxIndexSet<Local>,
-    ) -> Vec<Param> {
+    ) -> Vec<Param<'db>> {
         locals
             .into_iter()
             .sorted()
@@ -1449,7 +1453,7 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
     }
 }
 
-fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode {
+fn make_call(ctx: &AssistContext<'_>, fun: &Function<'_>, indent: IndentLevel) -> SyntaxNode {
     let ret_ty = fun.return_type(ctx);
 
     let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition)));
@@ -1508,17 +1512,17 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> Sy
     }
 }
 
-enum FlowHandler {
+enum FlowHandler<'db> {
     None,
-    Try { kind: TryKind },
-    If { action: FlowKind },
-    IfOption { action: FlowKind },
-    MatchOption { none: FlowKind },
-    MatchResult { err: FlowKind },
+    Try { kind: TryKind<'db> },
+    If { action: FlowKind<'db> },
+    IfOption { action: FlowKind<'db> },
+    MatchOption { none: FlowKind<'db> },
+    MatchResult { err: FlowKind<'db> },
 }
 
-impl FlowHandler {
-    fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler {
+impl<'db> FlowHandler<'db> {
+    fn from_ret_ty(fun: &Function<'db>, ret_ty: &FunType<'db>) -> FlowHandler<'db> {
         if fun.contains_tail_expr {
             return FlowHandler::None;
         }
@@ -1628,7 +1632,7 @@ fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local, edition: Edition) -
 fn format_function(
     ctx: &AssistContext<'_>,
     module: hir::Module,
-    fun: &Function,
+    fun: &Function<'_>,
     old_indent: IndentLevel,
 ) -> ast::Fn {
     let fun_name = make::name(&fun.name.text());
@@ -1654,7 +1658,7 @@ fn format_function(
 
 fn make_generic_params_and_where_clause(
     ctx: &AssistContext<'_>,
-    fun: &Function,
+    fun: &Function<'_>,
 ) -> (Option<ast::GenericParamList>, Option<ast::WhereClause>) {
     let used_type_params = fun.type_params(ctx);
 
@@ -1666,7 +1670,7 @@ fn make_generic_params_and_where_clause(
 
 fn make_generic_param_list(
     ctx: &AssistContext<'_>,
-    fun: &Function,
+    fun: &Function<'_>,
     used_type_params: &[TypeParam],
 ) -> Option<ast::GenericParamList> {
     let mut generic_params = fun
@@ -1703,7 +1707,7 @@ fn param_is_required(
 
 fn make_where_clause(
     ctx: &AssistContext<'_>,
-    fun: &Function,
+    fun: &Function<'_>,
     used_type_params: &[TypeParam],
 ) -> Option<ast::WhereClause> {
     let mut predicates = fun
@@ -1743,9 +1747,9 @@ fn resolved_type_param(ctx: &AssistContext<'_>, pred: &ast::WherePred) -> Option
     }
 }
 
-impl Function {
+impl<'db> Function<'db> {
     /// Collect all the `TypeParam`s used in the `body` and `params`.
-    fn type_params(&self, ctx: &AssistContext<'_>) -> Vec<TypeParam> {
+    fn type_params(&self, ctx: &AssistContext<'db>) -> Vec<TypeParam> {
         let type_params_in_descendant_paths =
             self.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) {
                 Some(PathResolution::TypeParam(type_param)) => Some(type_param),
@@ -1808,8 +1812,8 @@ impl Function {
     }
 }
 
-impl FunType {
-    fn make_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
+impl<'db> FunType<'db> {
+    fn make_ty(&self, ctx: &AssistContext<'db>, module: hir::Module) -> ast::Type {
         match self {
             FunType::Unit => make::ty_unit(),
             FunType::Single(ty) => make_ty(ty, ctx, module),
@@ -1831,7 +1835,11 @@ impl FunType {
     }
 }
 
-fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -> ast::BlockExpr {
+fn make_body(
+    ctx: &AssistContext<'_>,
+    old_indent: IndentLevel,
+    fun: &Function<'_>,
+) -> ast::BlockExpr {
     let ret_ty = fun.return_type(ctx);
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
 
@@ -2009,19 +2017,19 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr
     make::hacky_block_expr(elements, Some(tail_expr))
 }
 
-fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String {
+fn format_type(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) -> String {
     ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_owned())
 }
 
-fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
+fn make_ty(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
     let ty_str = format_type(ty, ctx, module);
     make::ty(&ty_str)
 }
 
 fn rewrite_body_segment(
     ctx: &AssistContext<'_>,
-    params: &[Param],
-    handler: &FlowHandler,
+    params: &[Param<'_>],
+    handler: &FlowHandler<'_>,
     syntax: &SyntaxNode,
 ) -> SyntaxNode {
     let syntax = fix_param_usages(ctx, params, syntax);
@@ -2030,8 +2038,12 @@ fn rewrite_body_segment(
 }
 
 /// change all usages to account for added `&`/`&mut` for some params
-fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode {
-    let mut usages_for_param: Vec<(&Param, Vec<ast::Expr>)> = Vec::new();
+fn fix_param_usages(
+    ctx: &AssistContext<'_>,
+    params: &[Param<'_>],
+    syntax: &SyntaxNode,
+) -> SyntaxNode {
+    let mut usages_for_param: Vec<(&Param<'_>, Vec<ast::Expr>)> = Vec::new();
 
     let tm = TreeMutator::new(syntax);
 
@@ -2085,7 +2097,7 @@ fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNo
     res
 }
 
-fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) {
+fn update_external_control_flow(handler: &FlowHandler<'_>, syntax: &SyntaxNode) {
     let mut nested_loop = None;
     let mut nested_scope = None;
     for event in syntax.preorder() {
@@ -2146,7 +2158,10 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) {
     }
 }
 
-fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> {
+fn make_rewritten_flow(
+    handler: &FlowHandler<'_>,
+    arg_expr: Option<ast::Expr>,
+) -> Option<ast::Expr> {
     let value = match handler {
         FlowHandler::None | FlowHandler::Try { .. } => return None,
         FlowHandler::If { .. } => make::expr_call(
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 30084d23d1f..78ae815dc87 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
@@ -307,7 +307,7 @@ impl FunctionBuilder {
         ctx: &AssistContext<'_>,
         call: &ast::MethodCallExpr,
         name: &ast::NameRef,
-        receiver_ty: Type,
+        receiver_ty: Type<'_>,
         target_module: Module,
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index 6f028e58d0c..b7b8bc604a5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -283,11 +283,11 @@ impl CallInfo {
     }
 }
 
-fn get_fn_params(
-    db: &dyn HirDatabase,
+fn get_fn_params<'db>(
+    db: &'db dyn HirDatabase,
     function: hir::Function,
     param_list: &ast::ParamList,
-) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param)>> {
+) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param<'db>)>> {
     let mut assoc_fn_params = function.assoc_fn_params(db).into_iter();
 
     let mut params = Vec::new();
@@ -316,7 +316,7 @@ fn inline(
     function_def_file_id: EditionedFileId,
     function: hir::Function,
     fn_body: &ast::BlockExpr,
-    params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
+    params: &[(ast::Pat, Option<ast::Type>, hir::Param<'_>)],
     CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo,
 ) -> ast::Expr {
     let file_id = sema.hir_file_for(fn_body.syntax());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index e5ed04fdc7c..b11d3792bc4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -58,7 +58,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
 
 fn validate_type_recursively(
     ctx: &AssistContext<'_>,
-    ty_hir: Option<&hir::Type>,
+    ty_hir: Option<&hir::Type<'_>>,
     refed: bool,
     fuel: i32,
 ) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
index 42f35210b49..08170f81b28 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
@@ -105,7 +105,7 @@ fn contains_placeholder(a: &ast::MatchArm) -> bool {
 }
 
 fn are_same_types(
-    current_arm_types: &FxHashMap<String, Option<Type>>,
+    current_arm_types: &FxHashMap<String, Option<Type<'_>>>,
     arm: &ast::MatchArm,
     ctx: &AssistContext<'_>,
 ) -> bool {
@@ -121,15 +121,15 @@ fn are_same_types(
     true
 }
 
-fn get_arm_types(
-    context: &AssistContext<'_>,
+fn get_arm_types<'db>(
+    context: &AssistContext<'db>,
     arm: &ast::MatchArm,
-) -> FxHashMap<String, Option<Type>> {
-    let mut mapping: FxHashMap<String, Option<Type>> = FxHashMap::default();
+) -> FxHashMap<String, Option<Type<'db>>> {
+    let mut mapping: FxHashMap<String, Option<Type<'db>>> = FxHashMap::default();
 
-    fn recurse(
-        map: &mut FxHashMap<String, Option<Type>>,
-        ctx: &AssistContext<'_>,
+    fn recurse<'db>(
+        map: &mut FxHashMap<String, Option<Type<'db>>>,
+        ctx: &AssistContext<'db>,
         pat: &Option<ast::Pat>,
     ) {
         if let Some(local_pat) = pat {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index 07d2f52a34e..8834ad97652 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -217,7 +217,7 @@ fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
     }
 }
 
-fn group_label(candidate: &ImportCandidate) -> GroupLabel {
+fn group_label(candidate: &ImportCandidate<'_>) -> GroupLabel {
     let name = match candidate {
         ImportCandidate::Path(it) => &it.name,
         ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
@@ -230,7 +230,7 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
 
 fn label(
     db: &RootDatabase,
-    candidate: &ImportCandidate,
+    candidate: &ImportCandidate<'_>,
     import: &LocatedImport,
     edition: Edition,
 ) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index 16debc4d728..c38bdfdccf5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -117,7 +117,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     if unused.peek().is_some() {
         acc.add(
             AssistId::quick_fix("remove_unused_imports"),
-            "Remove all the unused imports",
+            "Remove all unused imports",
             selected_el.text_range(),
             |builder| {
                 let unused: Vec<ast::UseTree> = unused.map(|x| builder.make_mut(x)).collect();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 6af8e1482c2..019ddaf1441 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -46,7 +46,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         return None;
     }
 
-    let mut formatter = |_: &hir::Type| String::from("todo!()");
+    let mut formatter = |_: &hir::Type<'_>| String::from("todo!()");
 
     let edition = scope.krate().edition(ctx.db());
     let paths = paths
@@ -100,7 +100,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#,
     fn test_complete_todo_with_msg() {
         check_assist(
             term_search,
-            r#"//- minicore: todo, unimplemented
+            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
+            // Should implement super let and remove `fmt_before_1_89_0`
+            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
@@ -110,7 +112,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
     fn test_complete_unimplemented_with_msg() {
         check_assist(
             term_search,
-            r#"//- minicore: todo, unimplemented
+            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
+            // Should implement super let and remove `fmt_before_1_89_0`
+            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
@@ -120,7 +124,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
     fn test_complete_unimplemented() {
         check_assist(
             term_search,
-            r#"//- minicore: todo, unimplemented
+            // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure.
+            // Should implement super let and remove `fmt_before_1_89_0`
+            r#"//- minicore: todo, unimplemented, fmt_before_1_89_0
 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#,
             r#"fn f() { let a: u128 = 1; let b: u128 = a }"#,
         )
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 5e6889792db..cda2ad43278 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -37,6 +37,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: true,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
@@ -57,6 +58,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: false,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@@ -77,6 +79,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: true,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@@ -97,6 +100,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
     term_search_borrowck: true,
     code_action_grouping: true,
     expr_fill_default: ExprFillDefaultMode::Todo,
+    prefer_self_ty: false,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
@@ -114,6 +118,23 @@ pub(crate) fn check_assist(
 }
 
 #[track_caller]
+pub(crate) fn check_assist_with_config(
+    assist: Handler,
+    config: AssistConfig,
+    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
+) {
+    let ra_fixture_after = trim_indent(ra_fixture_after);
+    check_with_config(
+        config,
+        assist,
+        ra_fixture_before,
+        ExpectedResult::After(&ra_fixture_after),
+        None,
+    );
+}
+
+#[track_caller]
 pub(crate) fn check_assist_no_snippet_cap(
     assist: Handler,
     #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
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 ef6914fda1d..1a91053f93c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -405,7 +405,7 @@ pub(crate) fn does_pat_variant_nested_or_literal(ctx: &AssistContext<'_>, pat: &
 }
 
 fn check_pat_variant_from_enum(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool {
-    ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo| {
+    ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo<'_>| {
         ty.adjusted().as_adt().is_some_and(|adt| matches!(adt, hir::Adt::Enum(_)))
     })
 }
@@ -780,9 +780,9 @@ pub(crate) fn add_method_to_adt(
 }
 
 #[derive(Debug)]
-pub(crate) struct ReferenceConversion {
+pub(crate) struct ReferenceConversion<'db> {
     conversion: ReferenceConversionType,
-    ty: hir::Type,
+    ty: hir::Type<'db>,
     impls_deref: bool,
 }
 
@@ -802,10 +802,10 @@ enum ReferenceConversionType {
     Result,
 }
 
-impl ReferenceConversion {
+impl<'db> ReferenceConversion<'db> {
     pub(crate) fn convert_type(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         display_target: DisplayTarget,
     ) -> ast::Type {
         let ty = match self.conversion {
@@ -878,11 +878,11 @@ impl ReferenceConversion {
 // FIXME: It should return a new hir::Type, but currently constructing new types is too cumbersome
 //        and all users of this function operate on string type names, so they can do the conversion
 //        itself themselves.
-pub(crate) fn convert_reference_type(
-    ty: hir::Type,
-    db: &RootDatabase,
-    famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversion> {
+pub(crate) fn convert_reference_type<'db>(
+    ty: hir::Type<'db>,
+    db: &'db RootDatabase,
+    famous_defs: &FamousDefs<'_, 'db>,
+) -> Option<ReferenceConversion<'db>> {
     handle_copy(&ty, db)
         .or_else(|| handle_as_ref_str(&ty, db, famous_defs))
         .or_else(|| handle_as_ref_slice(&ty, db, famous_defs))
@@ -892,18 +892,21 @@ pub(crate) fn convert_reference_type(
         .map(|(conversion, impls_deref)| ReferenceConversion { ty, conversion, impls_deref })
 }
 
-fn could_deref_to_target(ty: &hir::Type, target: &hir::Type, db: &dyn HirDatabase) -> bool {
+fn could_deref_to_target(ty: &hir::Type<'_>, target: &hir::Type<'_>, db: &dyn HirDatabase) -> bool {
     let ty_ref = ty.add_reference(hir::Mutability::Shared);
     let target_ref = target.add_reference(hir::Mutability::Shared);
     ty_ref.could_coerce_to(db, &target_ref)
 }
 
-fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<(ReferenceConversionType, bool)> {
+fn handle_copy(
+    ty: &hir::Type<'_>,
+    db: &dyn HirDatabase,
+) -> Option<(ReferenceConversionType, bool)> {
     ty.is_copy(db).then_some((ReferenceConversionType::Copy, true))
 }
 
 fn handle_as_ref_str(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -914,7 +917,7 @@ fn handle_as_ref_str(
 }
 
 fn handle_as_ref_slice(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -928,7 +931,7 @@ fn handle_as_ref_slice(
 }
 
 fn handle_dereferenced(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -941,7 +944,7 @@ fn handle_dereferenced(
 }
 
 fn handle_option_as_ref(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
@@ -953,7 +956,7 @@ fn handle_option_as_ref(
 }
 
 fn handle_result_as_ref(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
 ) -> Option<(ReferenceConversionType, bool)> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
index 4ea56dc46aa..c58bdd9e8ed 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs
@@ -17,7 +17,7 @@ pub(crate) fn gen_trait_fn_body(
     func: &ast::Fn,
     trait_path: &ast::Path,
     adt: &ast::Adt,
-    trait_ref: Option<TraitRef>,
+    trait_ref: Option<TraitRef<'_>>,
 ) -> Option<()> {
     match trait_path.segment()?.name_ref()?.text().as_str() {
         "Clone" => gen_clone_impl(adt, func),
@@ -405,7 +405,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 }
 
 /// Generate a `PartialEq` impl based on the fields and members of the target type.
-fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -> Option<()> {
+fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
     stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
     fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
         match expr {
@@ -599,7 +599,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
     Some(())
 }
 
-fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -> Option<()> {
+fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
     stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
     fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
         let mut arms = vec![];
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 5d68aca9e61..65072d936f6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -161,7 +161,11 @@ impl Completions {
         item.add_to(self, ctx.db);
     }
 
-    pub(crate) fn add_expr(&mut self, ctx: &CompletionContext<'_>, expr: &hir::term_search::Expr) {
+    pub(crate) fn add_expr(
+        &mut self,
+        ctx: &CompletionContext<'_>,
+        expr: &hir::term_search::Expr<'_>,
+    ) {
         if let Some(item) = render_expr(ctx, expr) {
             item.add_to(self, ctx.db)
         }
@@ -170,7 +174,7 @@ impl Completions {
     pub(crate) fn add_crate_roots(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
     ) {
         ctx.process_all_names(&mut |name, res, doc_aliases| match res {
             ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => {
@@ -183,7 +187,7 @@ impl Completions {
     pub(crate) fn add_path_resolution(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         local_name: hir::Name,
         resolution: hir::ScopeDef,
         doc_aliases: Vec<syntax::SmolStr>,
@@ -232,7 +236,7 @@ impl Completions {
     pub(crate) fn add_enum_variants(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         e: hir::Enum,
     ) {
         if !ctx.check_stability_and_hidden(e) {
@@ -246,7 +250,7 @@ impl Completions {
     pub(crate) fn add_module(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         module: hir::Module,
         local_name: hir::Name,
         doc_aliases: Vec<syntax::SmolStr>,
@@ -263,7 +267,7 @@ impl Completions {
     pub(crate) fn add_macro(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         mac: hir::Macro,
         local_name: hir::Name,
     ) {
@@ -286,7 +290,7 @@ impl Completions {
     pub(crate) fn add_function(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         func: hir::Function,
         local_name: Option<hir::Name>,
     ) {
@@ -312,7 +316,7 @@ impl Completions {
     pub(crate) fn add_method(
         &mut self,
         ctx: &CompletionContext<'_>,
-        dot_access: &DotAccess,
+        dot_access: &DotAccess<'_>,
         func: hir::Function,
         receiver: Option<SmolStr>,
         local_name: Option<hir::Name>,
@@ -340,7 +344,7 @@ impl Completions {
     pub(crate) fn add_method_with_import(
         &mut self,
         ctx: &CompletionContext<'_>,
-        dot_access: &DotAccess,
+        dot_access: &DotAccess<'_>,
         func: hir::Function,
         import: LocatedImport,
     ) {
@@ -407,7 +411,7 @@ impl Completions {
     pub(crate) fn add_qualified_enum_variant(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         variant: hir::Variant,
         path: hir::ModPath,
     ) {
@@ -424,7 +428,7 @@ impl Completions {
     pub(crate) fn add_enum_variant(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
@@ -447,10 +451,10 @@ impl Completions {
     pub(crate) fn add_field(
         &mut self,
         ctx: &CompletionContext<'_>,
-        dot_access: &DotAccess,
+        dot_access: &DotAccess<'_>,
         receiver: Option<SmolStr>,
         field: hir::Field,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
     ) {
         let is_private_editable = match ctx.is_visible(&field) {
             Visible::Yes => false,
@@ -471,7 +475,7 @@ impl Completions {
     pub(crate) fn add_struct_literal(
         &mut self,
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         strukt: hir::Struct,
         path: Option<hir::ModPath>,
         local_name: Option<hir::Name>,
@@ -518,7 +522,7 @@ impl Completions {
         ctx: &CompletionContext<'_>,
         receiver: Option<SmolStr>,
         field: usize,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
     ) {
         // Only used for (unnamed) tuples, whose all fields *are* stable. No need to check
         // stability here.
@@ -550,7 +554,7 @@ impl Completions {
         &mut self,
         ctx: &CompletionContext<'_>,
         pattern_ctx: &PatternContext,
-        path_ctx: Option<&PathCompletionCtx>,
+        path_ctx: Option<&PathCompletionCtx<'_>>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
@@ -704,7 +708,7 @@ pub(super) fn complete_name(
 pub(super) fn complete_name_ref(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    NameRefContext { nameref, kind }: &NameRefContext,
+    NameRefContext { nameref, kind }: &NameRefContext<'_>,
 ) {
     match kind {
         NameRefKind::Path(path_ctx) => {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index 705402c785a..c542e140df5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -86,7 +86,7 @@ pub(crate) fn complete_known_attribute_input(
 pub(crate) fn complete_attribute_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     &AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx,
 ) {
     let is_inner = kind == AttrKind::Inner;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
index 2fc07e01382..267d92b6c09 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
@@ -13,7 +13,7 @@ use crate::{
 pub(crate) fn complete_derive_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     existing_derives: &ExistingDerives,
 ) {
     let core = ctx.famous_defs().core();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 4f21136d214..5340d65a142 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -18,7 +18,7 @@ use crate::{
 pub(crate) fn complete_dot(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
 ) {
     let receiver_ty = match dot_access {
         DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original,
@@ -130,8 +130,8 @@ pub(crate) fn complete_dot(
 pub(crate) fn complete_undotted_self(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    expr_ctx: &PathExprCtx,
+    path_ctx: &PathCompletionCtx<'_>,
+    expr_ctx: &PathExprCtx<'_>,
 ) {
     if !ctx.config.enable_self_on_the_fly {
         return;
@@ -198,9 +198,9 @@ pub(crate) fn complete_undotted_self(
 fn complete_fields(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    receiver: &hir::Type,
-    mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type),
-    mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type),
+    receiver: &hir::Type<'_>,
+    mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>),
+    mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>),
     is_field_access: bool,
     is_method_access_with_parens: bool,
 ) {
@@ -230,7 +230,7 @@ fn complete_fields(
 
 fn complete_methods(
     ctx: &CompletionContext<'_>,
-    receiver: &hir::Type,
+    receiver: &hir::Type<'_>,
     traits_in_scope: &FxHashSet<hir::TraitId>,
     f: impl FnMut(hir::Function),
 ) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index 7fbd1fbc1af..2133291b1de 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -47,8 +47,8 @@ where
 pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
-    expr_ctx: &PathExprCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
+    expr_ctx: &PathExprCtx<'_>,
 ) {
     let _p = tracing::info_span!("complete_expr_path").entered();
     if !ctx.qualifier_ctx.none() {
@@ -145,10 +145,16 @@ pub(crate) fn complete_expr_path(
             });
             match resolution {
                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
-                    // Set visible_from to None so private items are returned.
-                    // They will be possibly filtered out in add_path_resolution()
-                    // via def_is_visible().
-                    let module_scope = module.scope(ctx.db, None);
+                    let visible_from = if ctx.config.enable_private_editable {
+                        // Set visible_from to None so private items are returned.
+                        // They will be possibly filtered out in add_path_resolution()
+                        // via def_is_visible().
+                        None
+                    } else {
+                        Some(ctx.module)
+                    };
+
+                    let module_scope = module.scope(ctx.db, visible_from);
                     for (name, def) in module_scope {
                         if scope_def_applicable(def) {
                             acc.add_path_resolution(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
index 1441b0e3a01..26afa9c8ad9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs
@@ -8,7 +8,7 @@ use crate::{
 pub(crate) fn complete_field_list_tuple_variant(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
 ) {
     if ctx.qualifier_ctx.vis_node.is_some() {
     } else if let PathCompletionCtx {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index a7475613809..dad8a76de87 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -111,7 +111,7 @@ use crate::{
 pub(crate) fn import_on_the_fly_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
 ) -> Option<()> {
     if !ctx.config.enable_imports_on_the_fly {
         return None;
@@ -175,7 +175,7 @@ pub(crate) fn import_on_the_fly_pat(
 pub(crate) fn import_on_the_fly_dot(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
 ) -> Option<()> {
     if !ctx.config.enable_imports_on_the_fly {
         return None;
@@ -203,8 +203,8 @@ pub(crate) fn import_on_the_fly_dot(
 fn import_on_the_fly(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx,
-    import_assets: ImportAssets,
+    path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx<'_>,
+    import_assets: ImportAssets<'_>,
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
@@ -290,7 +290,7 @@ fn import_on_the_fly_pat_(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     pattern_ctx: &PatternContext,
-    import_assets: ImportAssets,
+    import_assets: ImportAssets<'_>,
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
@@ -335,8 +335,8 @@ fn import_on_the_fly_pat_(
 fn import_on_the_fly_method(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
-    import_assets: ImportAssets,
+    dot_access: &DotAccess<'_>,
+    import_assets: ImportAssets<'_>,
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
@@ -400,11 +400,11 @@ fn import_name(ctx: &CompletionContext<'_>) -> String {
     if token_kind.is_any_identifier() { ctx.token.to_string() } else { String::new() }
 }
 
-fn import_assets_for_path(
-    ctx: &CompletionContext<'_>,
+fn import_assets_for_path<'db>(
+    ctx: &CompletionContext<'db>,
     potential_import_name: &str,
     qualifier: Option<ast::Path>,
-) -> Option<ImportAssets> {
+) -> Option<ImportAssets<'db>> {
     let _p =
         tracing::info_span!("import_assets_for_path", ?potential_import_name, ?qualifier).entered();
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
index 893997cee47..6c001bd16bf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
@@ -10,8 +10,8 @@ pub(crate) mod trait_impl;
 pub(crate) fn complete_item_list_in_expr(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    expr_ctx: &PathExprCtx,
+    path_ctx: &PathCompletionCtx<'_>,
+    expr_ctx: &PathExprCtx<'_>,
 ) {
     if !expr_ctx.in_block_expr {
         return;
@@ -25,7 +25,7 @@ pub(crate) fn complete_item_list_in_expr(
 pub(crate) fn complete_item_list(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     kind: &ItemListKind,
 ) {
     let _p = tracing::info_span!("complete_item_list").entered();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 58aead73fd6..092219a058a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -122,7 +122,7 @@ fn complete_trait_impl_name(
 pub(crate) fn complete_trait_impl_item_by_name(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     name_ref: &Option<ast::NameRef>,
     impl_: &Option<ast::Impl>,
 ) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
index ea3511d31ca..62fae1cb237 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
@@ -124,7 +124,7 @@ pub(crate) fn complete_pattern(
 pub(crate) fn complete_pattern_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
 ) {
     match qualified {
         Qualified::With { resolution: Some(resolution), super_chain_len, .. } => {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 3cdf2112835..d0023852acf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -11,6 +11,7 @@ use ide_db::{
     text_edit::TextEdit,
     ty_filter::TryEnum,
 };
+use itertools::Either;
 use stdx::never;
 use syntax::{
     SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
@@ -28,7 +29,7 @@ use crate::{
 pub(crate) fn complete_postfix(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
 ) {
     if !ctx.config.enable_postfix_completions {
         return;
@@ -86,98 +87,10 @@ pub(crate) fn complete_postfix(
         }
     }
 
-    let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references());
-    if let Some(try_enum) = &try_enum {
-        match try_enum {
-            TryEnum::Result => {
-                postfix_snippet(
-                    "ifl",
-                    "if let Ok {}",
-                    &format!("if let Ok($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "lete",
-                    "let Ok else {}",
-                    &format!("let Ok($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "while",
-                    "while let Ok {}",
-                    &format!("while let Ok($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-            }
-            TryEnum::Option => {
-                postfix_snippet(
-                    "ifl",
-                    "if let Some {}",
-                    &format!("if let Some($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "lete",
-                    "let Some else {}",
-                    &format!("let Some($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
-                )
-                .add_to(acc, ctx.db);
-
-                postfix_snippet(
-                    "while",
-                    "while let Some {}",
-                    &format!("while let Some($1) = {receiver_text} {{\n    $0\n}}"),
-                )
-                .add_to(acc, ctx.db);
-            }
-        }
-    } else if receiver_ty.is_bool() || receiver_ty.is_unknown() {
-        postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n    $0\n}}"))
-            .add_to(acc, ctx.db);
-        postfix_snippet("while", "while expr {}", &format!("while {receiver_text} {{\n    $0\n}}"))
-            .add_to(acc, ctx.db);
-        postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db);
-    } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() {
-        if receiver_ty.impls_trait(ctx.db, trait_, &[]) {
-            postfix_snippet(
-                "for",
-                "for ele in expr {}",
-                &format!("for ele in {receiver_text} {{\n    $0\n}}"),
-            )
-            .add_to(acc, ctx.db);
-        }
-    }
-
     postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc, ctx.db);
     postfix_snippet("refm", "&mut expr", &format!("&mut {receiver_text}")).add_to(acc, ctx.db);
     postfix_snippet("deref", "*expr", &format!("*{receiver_text}")).add_to(acc, ctx.db);
 
-    let mut block_should_be_wrapped = true;
-    if dot_receiver.syntax().kind() == BLOCK_EXPR {
-        block_should_be_wrapped = false;
-        if let Some(parent) = dot_receiver.syntax().parent() {
-            if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) {
-                block_should_be_wrapped = true;
-            }
-        }
-    };
-    let unsafe_completion_string = if block_should_be_wrapped {
-        format!("unsafe {{ {receiver_text} }}")
-    } else {
-        format!("unsafe {receiver_text}")
-    };
-    postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db);
-
-    let const_completion_string = if block_should_be_wrapped {
-        format!("const {{ {receiver_text} }}")
-    } else {
-        format!("const {receiver_text}")
-    };
-    postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db);
-
     // The rest of the postfix completions create an expression that moves an argument,
     // so it's better to consider references now to avoid breaking the compilation
 
@@ -195,18 +108,81 @@ pub(crate) fn complete_postfix(
         add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
     }
 
-    match try_enum {
-        Some(try_enum) => match try_enum {
-            TryEnum::Result => {
-                postfix_snippet(
+    postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})"))
+        .add_to(acc, ctx.db);
+    postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc, ctx.db); // fixme
+    postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{receiver_text})")).add_to(acc, ctx.db);
+    postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})"))
+        .add_to(acc, ctx.db);
+
+    let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references());
+    let mut is_in_cond = false;
+    if let Some(parent) = dot_receiver_including_refs.syntax().parent() {
+        if let Some(second_ancestor) = parent.parent() {
+            let sec_ancestor_kind = second_ancestor.kind();
+            if let Some(expr) = <Either<ast::IfExpr, ast::WhileExpr>>::cast(second_ancestor) {
+                is_in_cond = match expr {
+                    Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent),
+                    Either::Right(it) => {
+                        it.condition().is_some_and(|cond| *cond.syntax() == parent)
+                    }
+                }
+            }
+            match &try_enum {
+                Some(try_enum) if is_in_cond => match try_enum {
+                    TryEnum::Result => {
+                        postfix_snippet(
+                            "let",
+                            "let Ok(_)",
+                            &format!("let Ok($0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                        postfix_snippet(
+                            "letm",
+                            "let Ok(mut _)",
+                            &format!("let Ok(mut $0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                    }
+                    TryEnum::Option => {
+                        postfix_snippet(
+                            "let",
+                            "let Some(_)",
+                            &format!("let Some($0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                        postfix_snippet(
+                            "letm",
+                            "let Some(mut _)",
+                            &format!("let Some(mut $0) = {receiver_text}"),
+                        )
+                        .add_to(acc, ctx.db);
+                    }
+                },
+                _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => {
+                    postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
+                        .add_to(acc, ctx.db);
+                    postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};"))
+                        .add_to(acc, ctx.db);
+                }
+                _ => (),
+            }
+        }
+    }
+
+    if !is_in_cond {
+        match try_enum {
+            Some(try_enum) => match try_enum {
+                TryEnum::Result => {
+                    postfix_snippet(
                     "match",
                     "match expr {}",
                     &format!("match {receiver_text} {{\n    Ok(${{1:_}}) => {{$2}},\n    Err(${{3:_}}) => {{$0}},\n}}"),
                 )
                 .add_to(acc, ctx.db);
-            }
-            TryEnum::Option => {
-                postfix_snippet(
+                }
+                TryEnum::Option => {
+                    postfix_snippet(
                     "match",
                     "match expr {}",
                     &format!(
@@ -214,32 +190,106 @@ pub(crate) fn complete_postfix(
                     ),
                 )
                 .add_to(acc, ctx.db);
+                }
+            },
+            None => {
+                postfix_snippet(
+                    "match",
+                    "match expr {}",
+                    &format!("match {receiver_text} {{\n    ${{1:_}} => {{$0}},\n}}"),
+                )
+                .add_to(acc, ctx.db);
             }
-        },
-        None => {
+        }
+        if let Some(try_enum) = &try_enum {
+            match try_enum {
+                TryEnum::Result => {
+                    postfix_snippet(
+                        "ifl",
+                        "if let Ok {}",
+                        &format!("if let Ok($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "lete",
+                        "let Ok else {}",
+                        &format!("let Ok($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "while",
+                        "while let Ok {}",
+                        &format!("while let Ok($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+                }
+                TryEnum::Option => {
+                    postfix_snippet(
+                        "ifl",
+                        "if let Some {}",
+                        &format!("if let Some($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "lete",
+                        "let Some else {}",
+                        &format!("let Some($1) = {receiver_text} else {{\n    $2\n}};\n$0"),
+                    )
+                    .add_to(acc, ctx.db);
+
+                    postfix_snippet(
+                        "while",
+                        "while let Some {}",
+                        &format!("while let Some($1) = {receiver_text} {{\n    $0\n}}"),
+                    )
+                    .add_to(acc, ctx.db);
+                }
+            }
+        } else if receiver_ty.is_bool() || receiver_ty.is_unknown() {
+            postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n    $0\n}}"))
+                .add_to(acc, ctx.db);
             postfix_snippet(
-                "match",
-                "match expr {}",
-                &format!("match {receiver_text} {{\n    ${{1:_}} => {{$0}},\n}}"),
+                "while",
+                "while expr {}",
+                &format!("while {receiver_text} {{\n    $0\n}}"),
             )
             .add_to(acc, ctx.db);
+            postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db);
+        } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() {
+            if receiver_ty.impls_trait(ctx.db, trait_, &[]) {
+                postfix_snippet(
+                    "for",
+                    "for ele in expr {}",
+                    &format!("for ele in {receiver_text} {{\n    $0\n}}"),
+                )
+                .add_to(acc, ctx.db);
+            }
         }
     }
 
-    postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})"))
-        .add_to(acc, ctx.db);
-    postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc, ctx.db); // fixme
-    postfix_snippet("dbgr", "dbg!(&expr)", &format!("dbg!(&{receiver_text})")).add_to(acc, ctx.db);
-    postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})"))
-        .add_to(acc, ctx.db);
-
-    if let Some(parent) = dot_receiver_including_refs.syntax().parent().and_then(|p| p.parent()) {
-        if matches!(parent.kind(), STMT_LIST | EXPR_STMT) {
-            postfix_snippet("let", "let", &format!("let $0 = {receiver_text};"))
-                .add_to(acc, ctx.db);
-            postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};"))
-                .add_to(acc, ctx.db);
+    let mut block_should_be_wrapped = true;
+    if dot_receiver.syntax().kind() == BLOCK_EXPR {
+        block_should_be_wrapped = false;
+        if let Some(parent) = dot_receiver.syntax().parent() {
+            if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) {
+                block_should_be_wrapped = true;
+            }
         }
+    };
+    {
+        let (open_brace, close_brace) =
+            if block_should_be_wrapped { ("{ ", " }") } else { ("", "") };
+        let (open_paren, close_paren) = if is_in_cond { ("(", ")") } else { ("", "") };
+        let unsafe_completion_string =
+            format!("{open_paren}unsafe {open_brace}{receiver_text}{close_brace}{close_paren}");
+        postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db);
+
+        let const_completion_string =
+            format!("{open_paren}const {open_brace}{receiver_text}{close_brace}{close_paren}");
+        postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db);
     }
 
     if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() {
@@ -568,6 +618,54 @@ fn main() {
     }
 
     #[test]
+    fn option_iflet_cond() {
+        check(
+            r#"
+//- minicore: option
+fn main() {
+    let bar = Some(true);
+    if bar.$0
+}
+"#,
+            expect![[r#"
+                me and(…)    fn(self, Option<U>) -> Option<U>
+                me as_ref()     const fn(&self) -> Option<&T>
+                me ok_or(…) const fn(self, E) -> Result<T, E>
+                me unwrap()               const fn(self) -> T
+                me unwrap_or(…)              fn(self, T) -> T
+                sn box                         Box::new(expr)
+                sn call                        function(expr)
+                sn const                             const {}
+                sn dbg                             dbg!(expr)
+                sn dbgr                           dbg!(&expr)
+                sn deref                                *expr
+                sn let                            let Some(_)
+                sn letm                       let Some(mut _)
+                sn ref                                  &expr
+                sn refm                             &mut expr
+                sn return                         return expr
+                sn unsafe                           unsafe {}
+            "#]],
+        );
+        check_edit(
+            "let",
+            r#"
+//- minicore: option
+fn main() {
+    let bar = Some(true);
+    if bar.$0
+}
+"#,
+            r#"
+fn main() {
+    let bar = Some(true);
+    if let Some($0) = bar
+}
+"#,
+        );
+    }
+
+    #[test]
     fn option_letelse() {
         check_edit(
             "lete",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
index c18aab007b2..36f38a70db6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
@@ -88,7 +88,7 @@ pub(crate) fn complete_record_expr_fields(
 pub(crate) fn add_default_update(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    ty: Option<hir::TypeInfo>,
+    ty: Option<hir::TypeInfo<'_>>,
 ) {
     let default_trait = ctx.famous_defs().core_default_Default();
     let impls_default_trait = default_trait
@@ -117,7 +117,7 @@ pub(crate) fn add_default_update(
 fn complete_fields(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    missing_fields: Vec<(hir::Field, hir::Type)>,
+    missing_fields: Vec<(hir::Field, hir::Type<'_>)>,
 ) {
     for (field, ty) in missing_fields {
         // This should call something else, we shouldn't be synthesizing a DotAccess here
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
index 31aae116762..ead9852eff5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
@@ -11,8 +11,8 @@ use crate::{
 pub(crate) fn complete_expr_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    &PathExprCtx { in_block_expr, .. }: &PathExprCtx,
+    path_ctx: &PathCompletionCtx<'_>,
+    &PathExprCtx { in_block_expr, .. }: &PathExprCtx<'_>,
 ) {
     if !matches!(path_ctx.qualified, Qualified::No) {
         return;
@@ -51,7 +51,7 @@ macro_rules! $1 {
 pub(crate) fn complete_item_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     kind: &ItemListKind,
 ) {
     if !matches!(path_ctx.qualified, Qualified::No) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
index 79db705af49..7c38c7d8ce4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
@@ -12,7 +12,7 @@ use crate::{
 pub(crate) fn complete_type_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     location: &TypeLocation,
 ) {
     let _p = tracing::info_span!("complete_type_path").entered();
@@ -220,7 +220,7 @@ pub(crate) fn complete_type_path(
 pub(crate) fn complete_ascribed_type(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     ascription: &TypeAscriptionTarget,
 ) -> Option<()> {
     if !path_ctx.is_trivial_path() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index 4d6d0b758a3..d2ab193ec3d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -13,7 +13,7 @@ use crate::{
 pub(crate) fn complete_use_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx<'_>,
     name_ref: &Option<ast::NameRef>,
 ) {
     match qualified {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
index d15c35ac849..38761f77a2c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
@@ -8,7 +8,7 @@ use crate::{
 pub(crate) fn complete_vis_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+    path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>,
     &has_in_token: &bool,
 ) {
     match qualified {
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 5287627790a..cfd7f80d40b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -65,13 +65,13 @@ impl QualifierCtx {
 
 /// The state of the path we are currently completing.
 #[derive(Debug)]
-pub(crate) struct PathCompletionCtx {
+pub(crate) struct PathCompletionCtx<'db> {
     /// If this is a call with () already there (or {} in case of record patterns)
     pub(crate) has_call_parens: bool,
     /// If this has a macro call bang !
     pub(crate) has_macro_bang: bool,
     /// The qualifier of the current path.
-    pub(crate) qualified: Qualified,
+    pub(crate) qualified: Qualified<'db>,
     /// The parent of the path we are completing.
     pub(crate) parent: Option<ast::Path>,
     #[allow(dead_code)]
@@ -79,14 +79,14 @@ pub(crate) struct PathCompletionCtx {
     pub(crate) path: ast::Path,
     /// The path of which we are completing the segment in the original file
     pub(crate) original_path: Option<ast::Path>,
-    pub(crate) kind: PathKind,
+    pub(crate) kind: PathKind<'db>,
     /// Whether the path segment has type args or not.
     pub(crate) has_type_args: bool,
     /// Whether the qualifier comes from a use tree parent or not
     pub(crate) use_tree_parent: bool,
 }
 
-impl PathCompletionCtx {
+impl PathCompletionCtx<'_> {
     pub(crate) fn is_trivial_path(&self) -> bool {
         matches!(
             self,
@@ -104,9 +104,9 @@ impl PathCompletionCtx {
 
 /// The kind of path we are completing right now.
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) enum PathKind {
+pub(crate) enum PathKind<'db> {
     Expr {
-        expr_ctx: PathExprCtx,
+        expr_ctx: PathExprCtx<'db>,
     },
     Type {
         location: TypeLocation,
@@ -140,7 +140,7 @@ pub(crate) struct AttrCtx {
 }
 
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) struct PathExprCtx {
+pub(crate) struct PathExprCtx<'db> {
     pub(crate) in_block_expr: bool,
     pub(crate) in_breakable: BreakableKind,
     pub(crate) after_if_expr: bool,
@@ -152,7 +152,7 @@ pub(crate) struct PathExprCtx {
     /// The surrounding RecordExpression we are completing a functional update
     pub(crate) is_func_update: Option<ast::RecordExpr>,
     pub(crate) self_param: Option<hir::SelfParam>,
-    pub(crate) innermost_ret_ty: Option<hir::Type>,
+    pub(crate) innermost_ret_ty: Option<hir::Type<'db>>,
     pub(crate) impl_: Option<ast::Impl>,
     /// Whether this expression occurs in match arm guard position: before the
     /// fat arrow token
@@ -241,7 +241,7 @@ pub(crate) enum ItemListKind {
 }
 
 #[derive(Debug)]
-pub(crate) enum Qualified {
+pub(crate) enum Qualified<'db> {
     No,
     With {
         path: ast::Path,
@@ -260,7 +260,7 @@ pub(crate) enum Qualified {
     },
     /// <_>::
     TypeAnchor {
-        ty: Option<hir::Type>,
+        ty: Option<hir::Type<'db>>,
         trait_: Option<hir::Trait>,
     },
     /// Whether the path is an absolute path
@@ -341,17 +341,17 @@ pub(crate) enum NameKind {
 
 /// The state of the NameRef we are completing.
 #[derive(Debug)]
-pub(crate) struct NameRefContext {
+pub(crate) struct NameRefContext<'db> {
     /// NameRef syntax in the original file
     pub(crate) nameref: Option<ast::NameRef>,
-    pub(crate) kind: NameRefKind,
+    pub(crate) kind: NameRefKind<'db>,
 }
 
 /// The kind of the NameRef we are completing.
 #[derive(Debug)]
-pub(crate) enum NameRefKind {
-    Path(PathCompletionCtx),
-    DotAccess(DotAccess),
+pub(crate) enum NameRefKind<'db> {
+    Path(PathCompletionCtx<'db>),
+    DotAccess(DotAccess<'db>),
     /// Position where we are only interested in keyword completions
     Keyword(ast::Item),
     /// The record expression this nameref is a field of and whether a dot precedes the completion identifier.
@@ -365,9 +365,9 @@ pub(crate) enum NameRefKind {
 
 /// The identifier we are currently completing.
 #[derive(Debug)]
-pub(crate) enum CompletionAnalysis {
+pub(crate) enum CompletionAnalysis<'db> {
     Name(NameContext),
-    NameRef(NameRefContext),
+    NameRef(NameRefContext<'db>),
     Lifetime(LifetimeContext),
     /// The string the cursor is currently inside
     String {
@@ -386,9 +386,9 @@ pub(crate) enum CompletionAnalysis {
 
 /// Information about the field or method access we are completing.
 #[derive(Debug)]
-pub(crate) struct DotAccess {
+pub(crate) struct DotAccess<'db> {
     pub(crate) receiver: Option<ast::Expr>,
-    pub(crate) receiver_ty: Option<TypeInfo>,
+    pub(crate) receiver_ty: Option<TypeInfo<'db>>,
     pub(crate) kind: DotAccessKind,
     pub(crate) ctx: DotAccessExprCtx,
 }
@@ -457,7 +457,7 @@ pub(crate) struct CompletionContext<'a> {
     /// This is usually the parameter name of the function argument we are completing.
     pub(crate) expected_name: Option<NameOrNameRef>,
     /// The expected type of what we are completing.
-    pub(crate) expected_type: Option<Type>,
+    pub(crate) expected_type: Option<Type<'a>>,
 
     pub(crate) qualifier_ctx: QualifierCtx,
 
@@ -608,7 +608,7 @@ impl CompletionContext<'_> {
 
     pub(crate) fn iterate_path_candidates(
         &self,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
         mut cb: impl FnMut(hir::AssocItem),
     ) {
         let mut seen = FxHashSet::default();
@@ -695,12 +695,12 @@ impl CompletionContext<'_> {
 }
 
 // CompletionContext construction
-impl<'a> CompletionContext<'a> {
+impl<'db> CompletionContext<'db> {
     pub(crate) fn new(
-        db: &'a RootDatabase,
+        db: &'db RootDatabase,
         position @ FilePosition { file_id, offset }: FilePosition,
-        config: &'a CompletionConfig<'a>,
-    ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> {
+        config: &'db CompletionConfig<'db>,
+    ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
         let _p = tracing::info_span!("CompletionContext::new").entered();
         let sema = Semantics::new(db);
 
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 7a2230b3e36..6e3a76f346a 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
@@ -38,9 +38,9 @@ struct ExpansionResult {
     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) struct AnalysisResult<'db> {
+    pub(super) analysis: CompletionAnalysis<'db>,
+    pub(super) expected: (Option<Type<'db>>, Option<ast::NameOrNameRef>),
     pub(super) qualifier_ctx: QualifierCtx,
     /// the original token of the expanded file
     pub(super) token: SyntaxToken,
@@ -48,13 +48,13 @@ pub(super) struct AnalysisResult {
     pub(super) original_offset: TextSize,
 }
 
-pub(super) fn expand_and_analyze(
-    sema: &Semantics<'_, RootDatabase>,
+pub(super) fn expand_and_analyze<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     original_file: InFile<SyntaxNode>,
     speculative_file: SyntaxNode,
     offset: TextSize,
     original_token: &SyntaxToken,
-) -> Option<AnalysisResult> {
+) -> Option<AnalysisResult<'db>> {
     // 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()?;
@@ -432,12 +432,13 @@ fn expand(
 
 /// Fill the completion context, this is what does semantic reasoning about the surrounding context
 /// of the completion location.
-fn analyze(
-    sema: &Semantics<'_, RootDatabase>,
+fn analyze<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     expansion_result: ExpansionResult,
     original_token: &SyntaxToken,
     self_token: &SyntaxToken,
-) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
+) -> Option<(CompletionAnalysis<'db>, (Option<Type<'db>>, Option<ast::NameOrNameRef>), QualifierCtx)>
+{
     let _p = tracing::info_span!("CompletionContext::analyze").entered();
     let ExpansionResult {
         original_file,
@@ -555,17 +556,17 @@ fn analyze(
 }
 
 /// Calculate the expected type and name of the cursor position.
-fn expected_type_and_name(
-    sema: &Semantics<'_, RootDatabase>,
+fn expected_type_and_name<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     token: &SyntaxToken,
     name_like: &ast::NameLike,
-) -> (Option<Type>, Option<NameOrNameRef>) {
+) -> (Option<Type<'db>>, Option<NameOrNameRef>) {
     let mut node = match token.parent() {
         Some(it) => it,
         None => return (None, None),
     };
 
-    let strip_refs = |mut ty: Type| match name_like {
+    let strip_refs = |mut ty: Type<'db>| match name_like {
         ast::NameLike::NameRef(n) => {
             let p = match n.syntax().parent() {
                 Some(it) => it,
@@ -805,13 +806,13 @@ fn classify_name(
     Some(NameContext { name, kind })
 }
 
-fn classify_name_ref(
-    sema: &Semantics<'_, RootDatabase>,
+fn classify_name_ref<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     original_file: &SyntaxNode,
     name_ref: ast::NameRef,
     original_offset: TextSize,
     parent: SyntaxNode,
-) -> Option<(NameRefContext, QualifierCtx)> {
+) -> Option<(NameRefContext<'db>, QualifierCtx)> {
     let nameref = find_node_at_offset(original_file, original_offset);
 
     let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 19cdef30bd9..dcaac3997b2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -502,7 +502,7 @@ pub(crate) struct Builder {
 impl Builder {
     pub(crate) fn from_resolution(
         ctx: &CompletionContext<'_>,
-        path_ctx: &PathCompletionCtx,
+        path_ctx: &PathCompletionCtx<'_>,
         local_name: hir::Name,
         resolution: hir::ScopeDef,
     ) -> Self {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 00c0b470f98..c6b8af3c79a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -122,10 +122,10 @@ impl<'a> RenderContext<'a> {
 
 pub(crate) fn render_field(
     ctx: RenderContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
     receiver: Option<SmolStr>,
     field: hir::Field,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
 ) -> CompletionItem {
     let db = ctx.db();
     let is_deprecated = ctx.is_deprecated(field);
@@ -204,7 +204,7 @@ pub(crate) fn render_tuple_field(
     ctx: RenderContext<'_>,
     receiver: Option<SmolStr>,
     field: usize,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
 ) -> CompletionItem {
     let mut item = CompletionItem::new(
         SymbolKind::Field,
@@ -241,7 +241,7 @@ pub(crate) fn render_type_inference(
 
 pub(crate) fn render_path_resolution(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: hir::Name,
     resolution: ScopeDef,
 ) -> Builder {
@@ -259,7 +259,7 @@ pub(crate) fn render_pattern_resolution(
 
 pub(crate) fn render_resolution_with_import(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     import_edit: LocatedImport,
 ) -> Option<Builder> {
     let resolution = ScopeDef::from(import_edit.original_item);
@@ -282,10 +282,10 @@ pub(crate) fn render_resolution_with_import_pat(
 
 pub(crate) fn render_expr(
     ctx: &CompletionContext<'_>,
-    expr: &hir::term_search::Expr,
+    expr: &hir::term_search::Expr<'_>,
 ) -> Option<Builder> {
     let mut i = 1;
-    let mut snippet_formatter = |ty: &hir::Type| {
+    let mut snippet_formatter = |ty: &hir::Type<'_>| {
         let arg_name = ty
             .as_adt()
             .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))
@@ -295,7 +295,7 @@ pub(crate) fn render_expr(
         res
     };
 
-    let mut label_formatter = |ty: &hir::Type| {
+    let mut label_formatter = |ty: &hir::Type<'_>| {
         ty.as_adt()
             .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))
             .unwrap_or_else(|| String::from("..."))
@@ -391,7 +391,7 @@ fn render_resolution_pat(
 
 fn render_resolution_path(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: hir::Name,
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
@@ -460,7 +460,7 @@ fn render_resolution_path(
         }
     }
 
-    let mut set_item_relevance = |ty: Type| {
+    let mut set_item_relevance = |ty: Type<'_>| {
         if !ty.is_unknown() {
             item.detail(ty.display(db, krate).to_string());
         }
@@ -593,8 +593,8 @@ fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> boo
 // FIXME: This checks types without possible coercions which some completions might want to do
 fn match_types(
     ctx: &CompletionContext<'_>,
-    ty1: &hir::Type,
-    ty2: &hir::Type,
+    ty1: &hir::Type<'_>,
+    ty2: &hir::Type<'_>,
 ) -> Option<CompletionRelevanceTypeMatch> {
     if ty1 == ty2 {
         Some(CompletionRelevanceTypeMatch::Exact)
@@ -607,7 +607,7 @@ fn match_types(
 
 fn compute_type_match(
     ctx: &CompletionContext<'_>,
-    completion_ty: &hir::Type,
+    completion_ty: &hir::Type<'_>,
 ) -> Option<CompletionRelevanceTypeMatch> {
     let expected_type = ctx.expected_type.as_ref()?;
 
@@ -626,7 +626,7 @@ fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str)
 
 fn compute_ref_match(
     ctx: &CompletionContext<'_>,
-    completion_ty: &hir::Type,
+    completion_ty: &hir::Type<'_>,
 ) -> Option<CompletionItemRefMode> {
     let expected_type = ctx.expected_type.as_ref()?;
     let expected_without_ref = expected_type.remove_ref();
@@ -658,8 +658,8 @@ fn compute_ref_match(
 
 fn path_ref_match(
     completion: &CompletionContext<'_>,
-    path_ctx: &PathCompletionCtx,
-    ty: &hir::Type,
+    path_ctx: &PathCompletionCtx<'_>,
+    ty: &hir::Type<'_>,
     item: &mut Builder,
 ) {
     if let Some(original_path) = &path_ctx.original_path {
@@ -733,7 +733,7 @@ mod tests {
     ) {
         let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
         actual.retain(|it| kinds.contains(&it.kind));
-        actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
+        actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone()));
         check_relevance_(actual, expect);
     }
 
@@ -743,7 +743,7 @@ mod tests {
         actual.retain(|it| it.kind != CompletionItemKind::Snippet);
         actual.retain(|it| it.kind != CompletionItemKind::Keyword);
         actual.retain(|it| it.kind != CompletionItemKind::BuiltinType);
-        actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
+        actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone()));
         check_relevance_(actual, expect);
     }
 
@@ -824,9 +824,9 @@ fn main() {
                 st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct {  } [type_could_unify]
                 ex dep::test_mod_b::Struct {  }  [type_could_unify]
                 st Struct Struct [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Struct) []
-                md dep  []
                 st Struct Struct [requires_import]
             "#]],
         );
@@ -862,9 +862,9 @@ fn main() {
 "#,
             expect![[r#"
                 un Union Union [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Union) []
-                md dep  []
                 en Union Union [requires_import]
             "#]],
         );
@@ -900,9 +900,9 @@ fn main() {
                 ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type_could_unify]
                 ex dep::test_mod_b::Enum::variant  [type_could_unify]
                 en Enum Enum [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Enum) []
-                md dep  []
                 en Enum Enum [requires_import]
             "#]],
         );
@@ -937,9 +937,9 @@ fn main() {
             expect![[r#"
                 ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type_could_unify]
                 ex dep::test_mod_b::Enum::Variant  [type_could_unify]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(Enum) []
-                md dep  []
             "#]],
         );
     }
@@ -967,9 +967,9 @@ fn main() {
 }
 "#,
             expect![[r#"
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(fn(usize) -> i32) []
-                md dep  []
                 fn function fn(usize) -> i32 [requires_import]
                 fn function(…) fn(isize) -> i32 [requires_import]
             "#]],
@@ -1000,9 +1000,9 @@ fn main() {
 "#,
             expect![[r#"
                 ct CONST i32 [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(i32) []
-                md dep  []
                 ct CONST i64 [requires_import]
             "#]],
         );
@@ -1032,9 +1032,9 @@ fn main() {
 "#,
             expect![[r#"
                 sc STATIC i32 [type_could_unify+requires_import]
+                md dep  []
                 fn main() fn() []
                 fn test(…) fn(i32) []
-                md dep  []
                 sc STATIC i64 [requires_import]
             "#]],
         );
@@ -1090,8 +1090,8 @@ fn func(input: Struct) { }
 
 "#,
             expect![[r#"
-                st Struct Struct [type]
                 st Self Self [type]
+                st Struct Struct [type]
                 sp Self Struct [type]
                 st Struct Struct [type]
                 ex Struct  [type]
@@ -1119,9 +1119,9 @@ fn main() {
 "#,
             expect![[r#"
                 lc input bool [type+name+local]
+                ex false  [type]
                 ex input  [type]
                 ex true  [type]
-                ex false  [type]
                 lc inputbad i32 [local]
                 fn main() fn() []
                 fn test(…) fn(bool) []
@@ -2088,9 +2088,9 @@ fn f() { A { bar: b$0 }; }
 "#,
             expect![[r#"
                 fn bar() fn() -> u8 [type+name]
+                ex bar()  [type]
                 fn baz() fn() -> u8 [type]
                 ex baz()  [type]
-                ex bar()  [type]
                 st A A []
                 fn f() fn() []
             "#]],
@@ -2199,8 +2199,8 @@ fn main() {
                 lc s S [type+name+local]
                 st S S [type]
                 st S S [type]
-                ex s  [type]
                 ex S  [type]
+                ex s  [type]
                 fn foo(…) fn(&mut S) []
                 fn main() fn() []
             "#]],
@@ -2218,8 +2218,8 @@ fn main() {
                 st S S [type]
                 lc ssss S [type+local]
                 st S S [type]
-                ex ssss  [type]
                 ex S  [type]
+                ex ssss  [type]
                 fn foo(…) fn(&mut S) []
                 fn main() fn() []
             "#]],
@@ -2252,11 +2252,11 @@ fn main() {
                 ex Foo  [type]
                 lc foo &Foo [local]
                 lc *foo [type+local]
-                fn bar(…) fn(Foo) []
-                fn main() fn() []
-                md core  []
                 tt Clone  []
                 tt Copy  []
+                fn bar(…) fn(Foo) []
+                md core  []
+                fn main() fn() []
             "#]],
         );
     }
@@ -2297,9 +2297,9 @@ fn main() {
                 st &S [type]
                 st T T []
                 st &T [type]
+                md core  []
                 fn foo(…) fn(&S) []
                 fn main() fn() []
-                md core  []
             "#]],
         )
     }
@@ -2346,9 +2346,9 @@ fn main() {
                 st &mut S [type]
                 st T T []
                 st &mut T [type]
+                md core  []
                 fn foo(…) fn(&mut S) []
                 fn main() fn() []
-                md core  []
             "#]],
         )
     }
@@ -2364,8 +2364,8 @@ fn foo(bar: u32) {
 }
 "#,
             expect![[r#"
-                lc baz i32 [local]
                 lc bar u32 [local]
+                lc baz i32 [local]
                 fn foo(…) fn(u32) []
             "#]],
         );
@@ -2449,9 +2449,9 @@ fn main() {
                 st &T [type]
                 fn bar() fn() -> T []
                 fn &bar() [type]
+                md core  []
                 fn foo(…) fn(&S) []
                 fn main() fn() []
-                md core  []
             "#]],
         )
     }
@@ -2702,8 +2702,8 @@ fn test() {
                 fn fn_builder() fn() -> FooBuilder [type_could_unify]
                 fn fn_ctr_wrapped() fn() -> Option<Foo<T>> [type_could_unify]
                 fn fn_ctr_wrapped_2() fn() -> Result<Foo<T>, u32> [type_could_unify]
-                me fn_returns_unit(…) fn(&self) [type_could_unify]
                 fn fn_other() fn() -> Option<u32> [type_could_unify]
+                me fn_returns_unit(…) fn(&self) [type_could_unify]
             "#]],
         );
     }
@@ -2965,12 +2965,12 @@ fn foo() {
                 ev Foo::B Foo::B [type_could_unify]
                 ev Foo::A(…) Foo::A(T) [type_could_unify]
                 lc foo Foo<u32> [type+local]
-                ex foo  [type]
                 ex Foo::B  [type]
+                ex foo  [type]
                 en Foo Foo<{unknown}> [type_could_unify]
-                fn foo() fn() []
                 fn bar() fn() -> Foo<u8> []
                 fn baz() fn() -> Foo<T> []
+                fn foo() fn() []
             "#]],
         );
     }
@@ -3000,19 +3000,19 @@ fn main() {
             expect![[r#"
                 sn not !expr [snippet]
                 me not() fn(self) -> <Self as Not>::Output [type_could_unify+requires_import]
-                sn if if expr {} []
-                sn while while expr {} []
-                sn ref &expr []
-                sn refm &mut expr []
-                sn deref *expr []
-                sn unsafe unsafe {} []
-                sn const const {} []
-                sn match match expr {} []
                 sn box Box::new(expr) []
+                sn call function(expr) []
+                sn const const {} []
                 sn dbg dbg!(expr) []
                 sn dbgr dbg!(&expr) []
-                sn call function(expr) []
+                sn deref *expr []
+                sn if if expr {} []
+                sn match match expr {} []
+                sn ref &expr []
+                sn refm &mut expr []
                 sn return return expr []
+                sn unsafe unsafe {} []
+                sn while while expr {} []
             "#]],
         );
     }
@@ -3033,19 +3033,19 @@ fn main() {
             &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)],
             expect![[r#"
                 me f() fn(&self) []
-                sn ref &expr []
-                sn refm &mut expr []
-                sn deref *expr []
-                sn unsafe unsafe {} []
-                sn const const {} []
-                sn match match expr {} []
                 sn box Box::new(expr) []
+                sn call function(expr) []
+                sn const const {} []
                 sn dbg dbg!(expr) []
                 sn dbgr dbg!(&expr) []
-                sn call function(expr) []
+                sn deref *expr []
                 sn let let []
                 sn letm let mut []
+                sn match match expr {} []
+                sn ref &expr []
+                sn refm &mut expr []
                 sn return return expr []
+                sn unsafe unsafe {} []
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 2fe517fa8cd..7669aec8f53 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -22,13 +22,13 @@ use crate::{
 
 #[derive(Debug)]
 enum FuncKind<'ctx> {
-    Function(&'ctx PathCompletionCtx),
-    Method(&'ctx DotAccess, Option<SmolStr>),
+    Function(&'ctx PathCompletionCtx<'ctx>),
+    Method(&'ctx DotAccess<'ctx>, Option<SmolStr>),
 }
 
 pub(crate) fn render_fn(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: Option<hir::Name>,
     func: hir::Function,
 ) -> Builder {
@@ -38,7 +38,7 @@ pub(crate) fn render_fn(
 
 pub(crate) fn render_method(
     ctx: RenderContext<'_>,
-    dot_access: &DotAccess,
+    dot_access: &DotAccess<'_>,
     receiver: Option<SmolStr>,
     local_name: Option<hir::Name>,
     func: hir::Function,
@@ -186,8 +186,8 @@ fn render(
 fn compute_return_type_match(
     db: &dyn HirDatabase,
     ctx: &RenderContext<'_>,
-    self_type: hir::Type,
-    ret_type: &hir::Type,
+    self_type: hir::Type<'_>,
+    ret_type: &hir::Type<'_>,
 ) -> CompletionRelevanceReturnType {
     if match_types(ctx.completion, &self_type, ret_type).is_some() {
         // fn([..]) -> Self
@@ -217,8 +217,8 @@ pub(super) fn add_call_parens<'b>(
     name: SmolStr,
     escaped_name: SmolStr,
     self_param: Option<hir::SelfParam>,
-    params: Vec<hir::Param>,
-    ret_type: &hir::Type,
+    params: Vec<hir::Param<'_>>,
+    ret_type: &hir::Type<'_>,
 ) -> &'b mut Builder {
     cov_mark::hit!(inserts_parens_for_function_calls);
 
@@ -288,7 +288,7 @@ pub(super) fn add_call_parens<'b>(
     builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet)
 }
 
-fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str {
+fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type<'_>) -> &'static str {
     if let Some(derefed_ty) = ty.remove_ref() {
         for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) {
             if name.as_str() == arg {
@@ -369,12 +369,12 @@ fn params_display(ctx: &CompletionContext<'_>, detail: &mut String, func: hir::F
     }
 }
 
-fn params(
-    ctx: &CompletionContext<'_>,
+fn params<'db>(
+    ctx: &CompletionContext<'db>,
     func: hir::Function,
     func_kind: &FuncKind<'_>,
     has_dot_receiver: bool,
-) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
+) -> Option<(Option<hir::SelfParam>, Vec<hir::Param<'db>>)> {
     ctx.config.callable.as_ref()?;
 
     // Don't add parentheses if the expected type is a function reference with the same signature.
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index 5a9e35a7290..6c89e49f94e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -21,7 +21,7 @@ use crate::{
 
 pub(crate) fn render_variant_lit(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     local_name: Option<hir::Name>,
     variant: hir::Variant,
     path: Option<hir::ModPath>,
@@ -35,7 +35,7 @@ pub(crate) fn render_variant_lit(
 
 pub(crate) fn render_struct_literal(
     ctx: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     strukt: hir::Struct,
     path: Option<hir::ModPath>,
     local_name: Option<hir::Name>,
@@ -49,7 +49,7 @@ pub(crate) fn render_struct_literal(
 
 fn render(
     ctx @ RenderContext { completion, .. }: RenderContext<'_>,
-    path_ctx: &PathCompletionCtx,
+    path_ctx: &PathCompletionCtx<'_>,
     thing: Variant,
     name: hir::Name,
     path: Option<hir::ModPath>,
@@ -194,7 +194,7 @@ impl Variant {
         }
     }
 
-    fn ty(self, db: &dyn HirDatabase) -> hir::Type {
+    fn ty(self, db: &dyn HirDatabase) -> hir::Type<'_> {
         match self {
             Variant::Struct(it) => it.ty(db),
             Variant::EnumVariant(it) => it.parent_enum(db).ty(db),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 4674dae0314..35fe407b2e6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -12,7 +12,7 @@ use crate::{
 
 pub(crate) fn render_macro(
     ctx: RenderContext<'_>,
-    PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
+    PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx<'_>,
 
     name: hir::Name,
     macro_: hir::Macro,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index dcc51a86a8e..60ec1128233 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -46,7 +46,7 @@ pub(crate) fn render_struct_pat(
 pub(crate) fn render_variant_pat(
     ctx: RenderContext<'_>,
     pattern_ctx: &PatternContext,
-    path_ctx: Option<&PathCompletionCtx>,
+    path_ctx: Option<&PathCompletionCtx<'_>>,
     variant: hir::Variant,
     local_name: Option<Name>,
     path: Option<&hir::ModPath>,
@@ -109,7 +109,7 @@ fn build_completion(
     lookup: SmolStr,
     pat: String,
     def: impl HasDocs + Copy,
-    adt_ty: hir::Type,
+    adt_ty: hir::Type<'_>,
     // Missing in context of match statement completions
     is_variant_missing: bool,
 ) -> CompletionItem {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index b46e4c32061..b2d18b796f1 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -1474,20 +1474,18 @@ fn main() {
 }
 "#,
         expect![[r#"
+            me foo()     fn(&self)
             sn box  Box::new(expr)
             sn call function(expr)
             sn const      const {}
             sn dbg      dbg!(expr)
             sn dbgr    dbg!(&expr)
             sn deref         *expr
-            sn if       if expr {}
             sn match match expr {}
-            sn not           !expr
             sn ref           &expr
             sn refm      &mut expr
             sn return  return expr
             sn unsafe    unsafe {}
-            sn while while expr {}
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
index 4b5a0ac1c2b..b404011dfe6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs
@@ -1,7 +1,7 @@
 //! Completion tests for visibility modifiers.
 use expect_test::expect;
 
-use crate::tests::{check, check_with_trigger_character};
+use crate::tests::{check, check_with_private_editable, check_with_trigger_character};
 
 #[test]
 fn empty_pub() {
@@ -78,3 +78,90 @@ mod bar {}
         "#]],
     );
 }
+
+#[test]
+fn use_inner_public_function() {
+    check(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn outer_public() fn()
+        "#]],
+    );
+}
+
+#[test]
+fn pub_use_inner_public_function() {
+    check(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+pub use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn inner_public() fn()
+            fn outer_public() fn()
+        "#]],
+    );
+}
+
+#[test]
+fn use_inner_public_function_private_editable() {
+    check_with_private_editable(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn inner_public() fn()
+            fn outer_public() fn()
+        "#]],
+    );
+}
+
+#[test]
+fn pub_use_inner_public_function_private_editable() {
+    check_with_private_editable(
+        r#"
+//- /inner.rs crate:inner
+pub fn inner_public() {}
+fn inner_private() {}
+//- /foo.rs crate:foo deps:inner
+pub use inner::inner_public;
+pub fn outer_public() {}
+//- /lib.rs crate:lib deps:foo
+fn x() {
+    foo::$0
+}
+        "#,
+        expect![[r#"
+            fn inner_public() fn()
+            fn outer_public() fn()
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
index 7b5723f37f7..9edfc113f76 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
@@ -13,21 +13,21 @@ use syntax::{
 use crate::RootDatabase;
 
 #[derive(Debug)]
-pub struct ActiveParameter {
-    pub ty: Type,
+pub struct ActiveParameter<'db> {
+    pub ty: Type<'db>,
     pub src: Option<InFile<Either<ast::SelfParam, ast::Param>>>,
 }
 
-impl ActiveParameter {
+impl<'db> ActiveParameter<'db> {
     /// Returns information about the call argument this token is part of.
-    pub fn at_token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Self> {
+    pub fn at_token(sema: &Semantics<'db, RootDatabase>, token: SyntaxToken) -> Option<Self> {
         let (signature, active_parameter) = callable_for_token(sema, token)?;
         Self::from_signature_and_active_parameter(sema, signature, active_parameter)
     }
 
     /// Returns information about the call argument this token is part of.
     pub fn at_arg(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &'db Semantics<'db, RootDatabase>,
         list: ast::ArgList,
         at: TextSize,
     ) -> Option<Self> {
@@ -36,8 +36,8 @@ impl ActiveParameter {
     }
 
     fn from_signature_and_active_parameter(
-        sema: &Semantics<'_, RootDatabase>,
-        signature: hir::Callable,
+        sema: &Semantics<'db, RootDatabase>,
+        signature: hir::Callable<'db>,
         active_parameter: Option<usize>,
     ) -> Option<Self> {
         let idx = active_parameter?;
@@ -63,10 +63,10 @@ impl ActiveParameter {
 }
 
 /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable.
-pub fn callable_for_token(
-    sema: &Semantics<'_, RootDatabase>,
+pub fn callable_for_token<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     token: SyntaxToken,
-) -> Option<(hir::Callable, Option<usize>)> {
+) -> Option<(hir::Callable<'db>, Option<usize>)> {
     let offset = token.text_range().start();
     // Find the calling expression and its NameRef
     let parent = token.parent()?;
@@ -79,21 +79,21 @@ pub fn callable_for_token(
 }
 
 /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable.
-pub fn callable_for_arg_list(
-    sema: &Semantics<'_, RootDatabase>,
+pub fn callable_for_arg_list<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     arg_list: ast::ArgList,
     at: TextSize,
-) -> Option<(hir::Callable, Option<usize>)> {
+) -> Option<(hir::Callable<'db>, Option<usize>)> {
     debug_assert!(arg_list.syntax().text_range().contains(at));
     let callable = arg_list.syntax().parent().and_then(ast::CallableExpr::cast)?;
     callable_for_node(sema, &callable, at)
 }
 
-pub fn callable_for_node(
-    sema: &Semantics<'_, RootDatabase>,
+pub fn callable_for_node<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     calling_node: &ast::CallableExpr,
     offset: TextSize,
-) -> Option<(hir::Callable, Option<usize>)> {
+) -> Option<(hir::Callable<'db>, Option<usize>)> {
     let callable = match calling_node {
         ast::CallableExpr::Call(call) => sema.resolve_expr_as_callable(&call.expr()?),
         ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index d5db1c481b6..a4a140ec57a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -385,17 +385,17 @@ fn find_std_module(
 
 // FIXME: IdentClass as a name no longer fits
 #[derive(Debug)]
-pub enum IdentClass {
-    NameClass(NameClass),
-    NameRefClass(NameRefClass),
+pub enum IdentClass<'db> {
+    NameClass(NameClass<'db>),
+    NameRefClass(NameRefClass<'db>),
     Operator(OperatorClass),
 }
 
-impl IdentClass {
+impl<'db> IdentClass<'db> {
     pub fn classify_node(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         node: &SyntaxNode,
-    ) -> Option<IdentClass> {
+    ) -> Option<IdentClass<'db>> {
         match_ast! {
             match node {
                 ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass),
@@ -418,23 +418,23 @@ impl IdentClass {
     }
 
     pub fn classify_token(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         token: &SyntaxToken,
-    ) -> Option<IdentClass> {
+    ) -> Option<IdentClass<'db>> {
         let parent = token.parent()?;
         Self::classify_node(sema, &parent)
     }
 
     pub fn classify_lifetime(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         lifetime: &ast::Lifetime,
-    ) -> Option<IdentClass> {
+    ) -> Option<IdentClass<'db>> {
         NameRefClass::classify_lifetime(sema, lifetime)
             .map(IdentClass::NameRefClass)
             .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass))
     }
 
-    pub fn definitions(self) -> ArrayVec<(Definition, Option<GenericSubstitution>), 2> {
+    pub fn definitions(self) -> ArrayVec<(Definition, Option<GenericSubstitution<'db>>), 2> {
         let mut res = ArrayVec::new();
         match self {
             IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
@@ -518,7 +518,7 @@ impl IdentClass {
 ///
 /// A model special case is `None` constant in pattern.
 #[derive(Debug)]
-pub enum NameClass {
+pub enum NameClass<'db> {
     Definition(Definition),
     /// `None` in `if let None = Some(82) {}`.
     /// Syntactically, it is a name, but semantically it is a reference.
@@ -528,11 +528,11 @@ pub enum NameClass {
     PatFieldShorthand {
         local_def: Local,
         field_ref: Field,
-        adt_subst: GenericSubstitution,
+        adt_subst: GenericSubstitution<'db>,
     },
 }
 
-impl NameClass {
+impl<'db> NameClass<'db> {
     /// `Definition` defined by this name.
     pub fn defined(self) -> Option<Definition> {
         let res = match self {
@@ -545,7 +545,10 @@ impl NameClass {
         Some(res)
     }
 
-    pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass> {
+    pub fn classify(
+        sema: &Semantics<'db, RootDatabase>,
+        name: &ast::Name,
+    ) -> Option<NameClass<'db>> {
         let _p = tracing::info_span!("NameClass::classify").entered();
 
         let parent = name.syntax().parent()?;
@@ -597,10 +600,10 @@ impl NameClass {
             Some(definition)
         }
 
-        fn classify_ident_pat(
-            sema: &Semantics<'_, RootDatabase>,
+        fn classify_ident_pat<'db>(
+            sema: &Semantics<'db, RootDatabase>,
             ident_pat: ast::IdentPat,
-        ) -> Option<NameClass> {
+        ) -> Option<NameClass<'db>> {
             if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
                 return Some(NameClass::ConstReference(Definition::from(def)));
             }
@@ -638,9 +641,9 @@ impl NameClass {
     }
 
     pub fn classify_lifetime(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         lifetime: &ast::Lifetime,
-    ) -> Option<NameClass> {
+    ) -> Option<NameClass<'db>> {
         let _p = tracing::info_span!("NameClass::classify_lifetime", ?lifetime).entered();
         let parent = lifetime.syntax().parent()?;
 
@@ -723,12 +726,12 @@ impl OperatorClass {
 /// A model special case is field shorthand syntax, which uses a single
 /// reference to point to two different defs.
 #[derive(Debug)]
-pub enum NameRefClass {
-    Definition(Definition, Option<GenericSubstitution>),
+pub enum NameRefClass<'db> {
+    Definition(Definition, Option<GenericSubstitution<'db>>),
     FieldShorthand {
         local_ref: Local,
         field_ref: Field,
-        adt_subst: GenericSubstitution,
+        adt_subst: GenericSubstitution<'db>,
     },
     /// The specific situation where we have an extern crate decl without a rename
     /// Here we have both a declaration and a reference.
@@ -741,13 +744,13 @@ pub enum NameRefClass {
     },
 }
 
-impl NameRefClass {
+impl<'db> NameRefClass<'db> {
     // Note: we don't have unit-tests for this rather important function.
     // It is primarily exercised via goto definition tests in `ide`.
     pub fn classify(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         name_ref: &ast::NameRef,
-    ) -> Option<NameRefClass> {
+    ) -> Option<NameRefClass<'db>> {
         let _p = tracing::info_span!("NameRefClass::classify", ?name_ref).entered();
 
         let parent = name_ref.syntax().parent()?;
@@ -866,9 +869,9 @@ impl NameRefClass {
     }
 
     pub fn classify_lifetime(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         lifetime: &ast::Lifetime,
-    ) -> Option<NameRefClass> {
+    ) -> Option<NameRefClass<'db>> {
         let _p = tracing::info_span!("NameRefClass::classify_lifetime", ?lifetime).entered();
         if lifetime.text() == "'static" {
             return Some(NameRefClass::Definition(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index ac592dfe93c..9f35988924b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -25,26 +25,26 @@ use crate::{
 /// * assists
 /// * etc.
 #[derive(Debug)]
-pub enum ImportCandidate {
+pub enum ImportCandidate<'db> {
     /// A path, qualified (`std::collections::HashMap`) or not (`HashMap`).
     Path(PathImportCandidate),
     /// A trait associated function (with no self parameter) or an associated constant.
     /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type
     /// and `name` is the `test_function`
-    TraitAssocItem(TraitImportCandidate),
+    TraitAssocItem(TraitImportCandidate<'db>),
     /// A trait method with self parameter.
     /// For 'test_enum.test_method()', `ty` is the `test_enum` expression type
     /// and `name` is the `test_method`
-    TraitMethod(TraitImportCandidate),
+    TraitMethod(TraitImportCandidate<'db>),
 }
 
 /// A trait import needed for a given associated item access.
 /// For `some::path::SomeStruct::ASSOC_`, contains the
 /// type of `some::path::SomeStruct` and `ASSOC_` as the item name.
 #[derive(Debug)]
-pub struct TraitImportCandidate {
+pub struct TraitImportCandidate<'db> {
     /// A type of the item that has the associated item accessed at.
-    pub receiver_ty: Type,
+    pub receiver_ty: Type<'db>,
     /// The associated item name that the trait to import should contain.
     pub assoc_item_name: NameToImport,
 }
@@ -100,16 +100,16 @@ impl NameToImport {
 
 /// A struct to find imports in the project, given a certain name (or its part) and the context.
 #[derive(Debug)]
-pub struct ImportAssets {
-    import_candidate: ImportCandidate,
+pub struct ImportAssets<'db> {
+    import_candidate: ImportCandidate<'db>,
     candidate_node: SyntaxNode,
     module_with_candidate: Module,
 }
 
-impl ImportAssets {
+impl<'db> ImportAssets<'db> {
     pub fn for_method_call(
         method_call: &ast::MethodCallExpr,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         let candidate_node = method_call.syntax().clone();
         Some(Self {
@@ -121,7 +121,7 @@ impl ImportAssets {
 
     pub fn for_exact_path(
         fully_qualified_path: &ast::Path,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         let candidate_node = fully_qualified_path.syntax().clone();
         if let Some(use_tree) = candidate_node.ancestors().find_map(ast::UseTree::cast) {
@@ -139,7 +139,7 @@ impl ImportAssets {
         })
     }
 
-    pub fn for_ident_pat(sema: &Semantics<'_, RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
+    pub fn for_ident_pat(sema: &Semantics<'db, RootDatabase>, pat: &ast::IdentPat) -> Option<Self> {
         if !pat.is_simple_ident() {
             return None;
         }
@@ -156,7 +156,7 @@ impl ImportAssets {
         module_with_candidate: Module,
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         candidate_node: SyntaxNode,
     ) -> Option<Self> {
         Some(Self {
@@ -168,7 +168,7 @@ impl ImportAssets {
 
     pub fn for_fuzzy_method_call(
         module_with_method_call: Module,
-        receiver_ty: Type,
+        receiver_ty: Type<'db>,
         fuzzy_method_name: String,
         candidate_node: SyntaxNode,
     ) -> Option<Self> {
@@ -229,14 +229,14 @@ impl LocatedImport {
     }
 }
 
-impl ImportAssets {
-    pub fn import_candidate(&self) -> &ImportCandidate {
+impl<'db> ImportAssets<'db> {
+    pub fn import_candidate(&self) -> &ImportCandidate<'db> {
         &self.import_candidate
     }
 
     pub fn search_for_imports(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         cfg: ImportPathConfig,
         prefix_kind: PrefixKind,
     ) -> impl Iterator<Item = LocatedImport> {
@@ -247,7 +247,7 @@ impl ImportAssets {
     /// This may return non-absolute paths if a part of the returned path is already imported into scope.
     pub fn search_for_relative_paths(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         cfg: ImportPathConfig,
     ) -> impl Iterator<Item = LocatedImport> {
         let _p = tracing::info_span!("ImportAssets::search_for_relative_paths").entered();
@@ -286,7 +286,7 @@ impl ImportAssets {
 
     fn search_for(
         &self,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         prefixed: Option<PrefixKind>,
         cfg: ImportPathConfig,
     ) -> impl Iterator<Item = LocatedImport> {
@@ -533,11 +533,11 @@ fn item_for_path_search_assoc(db: &RootDatabase, assoc_item: AssocItem) -> Optio
     })
 }
 
-fn trait_applicable_items(
-    db: &RootDatabase,
+fn trait_applicable_items<'db>(
+    db: &'db RootDatabase,
     current_crate: Crate,
-    scope: &SemanticsScope<'_>,
-    trait_candidate: &TraitImportCandidate,
+    scope: &SemanticsScope<'db>,
+    trait_candidate: &TraitImportCandidate<'db>,
     trait_assoc_item: bool,
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
     scope_filter: impl Fn(hir::Trait) -> bool,
@@ -709,9 +709,9 @@ fn get_mod_path(
     }
 }
 
-impl ImportCandidate {
+impl<'db> ImportCandidate<'db> {
     fn for_method_call(
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
         method_call: &ast::MethodCallExpr,
     ) -> Option<Self> {
         match sema.resolve_method_call(method_call) {
@@ -725,7 +725,7 @@ impl ImportCandidate {
         }
     }
 
-    fn for_regular_path(sema: &Semantics<'_, RootDatabase>, path: &ast::Path) -> Option<Self> {
+    fn for_regular_path(sema: &Semantics<'db, RootDatabase>, path: &ast::Path) -> Option<Self> {
         if sema.resolve_path(path).is_some() {
             return None;
         }
@@ -736,7 +736,7 @@ impl ImportCandidate {
         )
     }
 
-    fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<Self> {
+    fn for_name(sema: &Semantics<'db, RootDatabase>, name: &ast::Name) -> Option<Self> {
         if sema
             .scope(name.syntax())?
             .speculative_resolve(&make::ext::ident_path(&name.text()))
@@ -753,17 +753,17 @@ impl ImportCandidate {
     fn for_fuzzy_path(
         qualifier: Option<ast::Path>,
         fuzzy_name: String,
-        sema: &Semantics<'_, RootDatabase>,
+        sema: &Semantics<'db, RootDatabase>,
     ) -> Option<Self> {
         path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name))
     }
 }
 
-fn path_import_candidate(
-    sema: &Semantics<'_, RootDatabase>,
+fn path_import_candidate<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     qualifier: Option<ast::Path>,
     name: NameToImport,
-) -> Option<ImportCandidate> {
+) -> Option<ImportCandidate<'db>> {
     Some(match qualifier {
         Some(qualifier) => match sema.resolve_path(&qualifier) {
             Some(PathResolution::Def(ModuleDef::BuiltinType(_))) | None => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index c5ad64ed594..7d460f72492 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -429,7 +429,7 @@ pub struct FindUsages<'a> {
     /// The container of our definition should it be an assoc item
     assoc_item_container: Option<hir::AssocItemContainer>,
     /// whether to search for the `Self` type of the definition
-    include_self_kw_refs: Option<hir::Type>,
+    include_self_kw_refs: Option<hir::Type<'a>>,
     /// whether to search for the `self` module
     search_self_mod: bool,
 }
@@ -1087,12 +1087,12 @@ impl<'a> FindUsages<'a> {
 
     fn found_self_ty_name_ref(
         &self,
-        self_ty: &hir::Type,
+        self_ty: &hir::Type<'_>,
         name_ref: &ast::NameRef,
         sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool,
     ) -> bool {
         // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845
-        let ty_eq = |ty: hir::Type| match (ty.as_adt(), self_ty.as_adt()) {
+        let ty_eq = |ty: hir::Type<'_>| match (ty.as_adt(), self_ty.as_adt()) {
             (Some(ty), Some(self_ty)) => ty == self_ty,
             (None, None) => ty == *self_ty,
             _ => false,
@@ -1315,7 +1315,7 @@ impl<'a> FindUsages<'a> {
     }
 }
 
-fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option<hir::Type> {
+fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Option<hir::Type<'db>> {
     match def {
         Definition::Adt(adt) => Some(adt.ty(sema.db)),
         Definition::TypeAlias(it) => Some(it.ty(sema.db)),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 9b9f450bc73..995bf72dca1 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -151,10 +151,10 @@ impl NameGenerator {
     /// - If `ty` is an `impl Trait`, it will suggest the name of the first trait.
     ///
     /// If the suggested name conflicts with reserved keywords, it will return `None`.
-    pub fn for_type(
+    pub fn for_type<'db>(
         &mut self,
-        ty: &hir::Type,
-        db: &RootDatabase,
+        ty: &hir::Type<'db>,
+        db: &'db RootDatabase,
         edition: Edition,
     ) -> Option<SmolStr> {
         let name = name_of_type(ty, db, edition)?;
@@ -373,7 +373,11 @@ fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<Smo
     name_of_type(&ty, sema.db, edition)
 }
 
-fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<SmolStr> {
+fn name_of_type<'db>(
+    ty: &hir::Type<'db>,
+    db: &'db RootDatabase,
+    edition: Edition,
+) -> Option<SmolStr> {
     let name = if let Some(adt) = ty.as_adt() {
         let name = adt.name(db).display(db, edition).to_string();
 
@@ -407,7 +411,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
     normalize(&name)
 }
 
-fn sequence_name(inner_ty: Option<&hir::Type>, db: &RootDatabase, edition: Edition) -> SmolStr {
+fn sequence_name<'db>(
+    inner_ty: Option<&hir::Type<'db>>,
+    db: &'db RootDatabase,
+    edition: Edition,
+) -> SmolStr {
     let items_str = SmolStr::new_static("items");
     let Some(inner_ty) = inner_ty else {
         return items_str;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
index 63ce0ddbb8f..095256d8294 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
@@ -10,7 +10,7 @@ use syntax::ast::{self, Pat, make};
 use crate::RootDatabase;
 
 /// Enum types that implement `std::ops::Try` trait.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 pub enum TryEnum {
     Result,
     Option,
@@ -20,7 +20,7 @@ impl TryEnum {
     const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
 
     /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
-    pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type) -> Option<TryEnum> {
+    pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type<'_>) -> Option<TryEnum> {
         let enum_ = match ty.as_adt() {
             Some(hir::Adt::Enum(it)) => it,
             _ => return None,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
index a4a93e36f0e..f63cd92694b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
@@ -11,7 +11,7 @@ use syntax::{
 pub fn use_trivial_constructor(
     db: &crate::RootDatabase,
     path: Path,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     edition: Edition,
 ) -> Option<Expr> {
     match ty.as_adt() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index 7d2ac373dc0..afd1687ae07 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -7,7 +7,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 // This diagnostic is triggered if a call is made on something that is not callable.
 pub(crate) fn expected_function(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::ExpectedFunction,
+    d: &hir::ExpectedFunction<'_>,
 ) -> Diagnostic {
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 7a6e98fe1b5..a59077b757b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -18,7 +18,7 @@ macro_rules! format_ty {
 // Diagnostic: invalid-cast
 //
 // This diagnostic is triggered if the code contains an illegal cast
-pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -> Diagnostic {
+pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast<'_>) -> Diagnostic {
     let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into()));
     let (code, message) = match d.error {
         CastError::CastToBool => (
@@ -106,7 +106,10 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -
 // Diagnostic: cast-to-unsized
 //
 // This diagnostic is triggered when casting to an unsized type
-pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsized) -> Diagnostic {
+pub(crate) fn cast_to_unsized(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::CastToUnsized<'_>,
+) -> Diagnostic {
     let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into()));
     Diagnostic::new(
         DiagnosticCode::RustcHardError("E0620"),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 2b76efb1965..8a5d82b48c0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -106,7 +106,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 }
             });
 
-            let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
+            let generate_fill_expr = |ty: &Type<'_>| match ctx.config.expr_fill_default {
                 ExprFillDefaultMode::Todo => make::ext::expr_todo(),
                 ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
                 ExprFillDefaultMode::Default => {
@@ -180,7 +180,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
 }
 
 fn make_ty(
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     db: &dyn HirDatabase,
     module: hir::Module,
     edition: Edition,
@@ -198,7 +198,7 @@ fn make_ty(
 fn get_default_constructor(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::MissingFields,
-    ty: &Type,
+    ty: &Type<'_>,
 ) -> Option<ast::Expr> {
     if let Some(builtin_ty) = ty.as_builtin() {
         if builtin_ty.is_int() || builtin_ty.is_uint() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 6bd5417b25d..d8f6e813d80 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -630,6 +630,17 @@ fn main() {
         // Checks that we don't place orphan arguments for formatting under an unsafe block.
         check_diagnostics(
             r#"
+//- minicore: fmt_before_1_89_0
+fn foo() {
+    let p = 0xDEADBEEF as *const i32;
+    format_args!("", *p);
+                  // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
+}
+        "#,
+        );
+
+        check_diagnostics(
+            r#"
 //- minicore: fmt
 fn foo() {
     let p = 0xDEADBEEF as *const i32;
@@ -958,4 +969,18 @@ impl FooTrait for S2 {
         "#,
         );
     }
+
+    #[test]
+    fn no_false_positive_on_format_args_since_1_89_0() {
+        check_diagnostics(
+            r#"
+//- minicore: fmt
+fn test() {
+    let foo = 10;
+    let bar = true;
+    let _x = format_args!("{} {0} {} {last}", foo, bar, last = "!");
+}
+            "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 01cf5e8fa52..0928262d22f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -4,7 +4,10 @@ use hir::HirDisplay;
 // Diagnostic: moved-out-of-ref
 //
 // This diagnostic is triggered on moving non copy things out of references.
-pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOfRef) -> Diagnostic {
+pub(crate) fn moved_out_of_ref(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::MovedOutOfRef<'_>,
+) -> Diagnostic {
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0507"),
@@ -217,4 +220,23 @@ fn test() {
             "#,
         )
     }
+
+    #[test]
+    fn regression_18201() {
+        check_diagnostics(
+            r#"
+//- minicore: copy
+struct NotCopy;
+struct S(NotCopy);
+impl S {
+    fn f(&mut self) {
+        || {
+            if let ref mut _cb = self.0 {
+            }
+        };
+    }
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index ef42f2dc744..0edab5e0b3b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,5 +1,4 @@
 use either::Either;
-use hir::{Field, HasCrate};
 use hir::{HasSource, HirDisplay, Semantics, VariantId, db::ExpandDatabase};
 use ide_db::text_edit::TextEdit;
 use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange};
@@ -8,7 +7,10 @@ use syntax::{
     ast::{self, edit::IndentLevel, make},
 };
 
-use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
+use crate::{
+    Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix,
+    handlers::private_field::field_is_private_fixes,
+};
 
 // Diagnostic: no-such-field
 //
@@ -37,8 +39,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assis
                 field_is_private_fixes(
                     &ctx.sema,
                     d.field.file_id.original_file(ctx.sema.db),
-                    node,
                     private_field,
+                    ctx.sema.original_range(node.syntax()).range,
                 )
             } else {
                 missing_record_expr_field_fixes(
@@ -52,31 +54,6 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assis
     }
 }
 
-fn field_is_private_fixes(
-    sema: &Semantics<'_, RootDatabase>,
-    usage_file_id: EditionedFileId,
-    record_expr_field: &ast::RecordExprField,
-    private_field: Field,
-) -> Option<Vec<Assist>> {
-    let def_crate = private_field.krate(sema.db);
-    let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate();
-    let visibility = if usage_crate == def_crate { "pub(crate) " } else { "pub " };
-
-    let source = private_field.source(sema.db)?;
-    let (range, _) = source.syntax().original_file_range_opt(sema.db)?;
-    let source_change = SourceChange::from_text_edit(
-        range.file_id.file_id(sema.db),
-        TextEdit::insert(range.range.start(), visibility.into()),
-    );
-
-    Some(vec![fix(
-        "increase_field_visibility",
-        "Increase field visibility",
-        source_change,
-        sema.original_range(record_expr_field.syntax()).range,
-    )])
-}
-
 fn missing_record_expr_field_fixes(
     sema: &Semantics<'_, RootDatabase>,
     usage_file_id: EditionedFileId,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index 5b4273a5a62..69cd0d27cb0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -1,4 +1,8 @@
-use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+use hir::{EditionedFileId, FileRange, HasCrate, HasSource, Semantics};
+use ide_db::{RootDatabase, assists::Assist, source_change::SourceChange, text_edit::TextEdit};
+use syntax::{AstNode, TextRange, TextSize, ast::HasVisibility};
+
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
 
 // Diagnostic: private-field
 //
@@ -16,11 +20,59 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
         d.expr.map(|it| it.into()),
     )
     .stable()
+    .with_fixes(field_is_private_fixes(
+        &ctx.sema,
+        d.expr.file_id.original_file(ctx.sema.db),
+        d.field,
+        ctx.sema.original_range(d.expr.to_node(ctx.sema.db).syntax()).range,
+    ))
+}
+
+pub(crate) fn field_is_private_fixes(
+    sema: &Semantics<'_, RootDatabase>,
+    usage_file_id: EditionedFileId,
+    private_field: hir::Field,
+    fix_range: TextRange,
+) -> Option<Vec<Assist>> {
+    let def_crate = private_field.krate(sema.db);
+    let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate();
+    let mut visibility_text = if usage_crate == def_crate { "pub(crate) " } else { "pub " };
+
+    let source = private_field.source(sema.db)?;
+    let existing_visibility = match &source.value {
+        hir::FieldSource::Named(it) => it.visibility(),
+        hir::FieldSource::Pos(it) => it.visibility(),
+    };
+    let range = match existing_visibility {
+        Some(visibility) => {
+            // If there is an existing visibility, don't insert whitespace after.
+            visibility_text = visibility_text.trim_end();
+            source.with_value(visibility.syntax()).original_file_range_opt(sema.db)?.0
+        }
+        None => {
+            let (range, _) = source.syntax().original_file_range_opt(sema.db)?;
+            FileRange {
+                file_id: range.file_id,
+                range: TextRange::at(range.range.start(), TextSize::new(0)),
+            }
+        }
+    };
+    let source_change = SourceChange::from_text_edit(
+        range.file_id.file_id(sema.db),
+        TextEdit::replace(range.range, visibility_text.into()),
+    );
+
+    Some(vec![fix(
+        "increase_field_visibility",
+        "Increase field visibility",
+        source_change,
+        fix_range,
+    )])
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::check_diagnostics;
+    use crate::tests::{check_diagnostics, check_fix};
 
     #[test]
     fn private_field() {
@@ -29,7 +81,7 @@ mod tests {
 mod module { pub struct Struct { field: u32 } }
 fn main(s: module::Struct) {
     s.field;
-  //^^^^^^^ error: field `field` of `Struct` is private
+  //^^^^^^^ 💡 error: field `field` of `Struct` is private
 }
 "#,
         );
@@ -42,7 +94,7 @@ fn main(s: module::Struct) {
 mod module { pub struct Struct(u32); }
 fn main(s: module::Struct) {
     s.0;
-  //^^^ error: field `0` of `Struct` is private
+  //^^^ 💡 error: field `0` of `Struct` is private
 }
 "#,
         );
@@ -113,4 +165,68 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn change_visibility_fix() {
+        check_fix(
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field$0;
+}
+            "#,
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            pub(crate) field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field;
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn change_visibility_with_existing_visibility() {
+        check_fix(
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            pub(super) field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field$0;
+}
+            "#,
+            r#"
+pub mod foo {
+    pub mod bar {
+        pub struct Struct {
+            pub(crate) field: i32,
+        }
+    }
+}
+
+fn foo(v: foo::bar::Struct) {
+    v.field;
+}
+            "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 076df1ab0f8..e2957fcaefb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -20,7 +20,7 @@ use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_dis
 //
 // This diagnostic is triggered when the type of an expression or pattern does not match
 // the expected type.
-pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
+pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Diagnostic {
     let display_range = adjusted_display_range(ctx, d.expr_or_pat, &|node| {
         let Either::Left(expr) = node else { return None };
         let salient_token_range = match expr {
@@ -39,7 +39,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         cov_mark::hit!(type_mismatch_range_adjustment);
         Some(salient_token_range)
     });
-    let mut diag = Diagnostic::new(
+    Diagnostic::new(
         DiagnosticCode::RustcHardError("E0308"),
         format!(
             "expected {}, found {}",
@@ -52,14 +52,10 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         ),
         display_range,
     )
-    .with_fixes(fixes(ctx, d));
-    if diag.fixes.is_some() {
-        diag.experimental = false;
-    }
-    diag
+    .with_fixes(fixes(ctx, d))
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Option<Vec<Assist>> {
     let mut fixes = Vec::new();
 
     if let Some(expr_ptr) = d.expr_or_pat.value.cast::<ast::Expr>() {
@@ -76,7 +72,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assi
 
 fn add_reference(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -98,7 +94,7 @@ fn add_reference(
 
 fn add_missing_ok_or_some(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -188,7 +184,7 @@ fn add_missing_ok_or_some(
 
 fn remove_unnecessary_wrapper(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -271,7 +267,7 @@ fn remove_unnecessary_wrapper(
 
 fn remove_semicolon(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
@@ -301,7 +297,7 @@ fn remove_semicolon(
 
 fn str_ref_to_owned(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
+    d: &hir::TypeMismatch<'_>,
     expr_ptr: &InFile<AstPtr<ast::Expr>>,
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 1915a88dd00..8d427702690 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -20,7 +20,7 @@ use syntax::AstNode;
 // Diagnostic: typed-hole
 //
 // This diagnostic is triggered when an underscore expression is used in an invalid position.
-pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Diagnostic {
+pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole<'_>) -> Diagnostic {
     let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into()));
     let (message, fixes) = if d.expected.is_unknown() {
         ("`_` expressions may only appear on the left-hand side of an assignment".to_owned(), None)
@@ -41,7 +41,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
         .with_fixes(fixes)
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole<'_>) -> Option<Vec<Assist>> {
     let db = ctx.sema.db;
     let root = db.parse_or_expand(d.expr.file_id);
     let (original_range, _) =
@@ -61,7 +61,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
     };
     let paths = term_search(&term_search_ctx);
 
-    let mut formatter = |_: &hir::Type| String::from("_");
+    let mut formatter = |_: &hir::Type<'_>| String::from("_");
 
     let assists: Vec<Assist> = d
         .expected
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 0649c97f820..69015898967 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -25,7 +25,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_ran
 // This diagnostic is triggered if a field does not exist on a given type.
 pub(crate) fn unresolved_field(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::UnresolvedField,
+    d: &hir::UnresolvedField<'_>,
 ) -> Diagnostic {
     let method_suffix = if d.method_with_same_name_exists {
         ", but a method with a similar name exists"
@@ -54,7 +54,7 @@ pub(crate) fn unresolved_field(
     .with_fixes(fixes(ctx, d))
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Option<Vec<Assist>> {
     let mut fixes = Vec::new();
     if d.method_with_same_name_exists {
         fixes.extend(method_fix(ctx, &d.expr));
@@ -64,7 +64,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<A
 }
 
 // FIXME: Add Snippet Support
-fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Assist> {
+fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Option<Assist> {
     // Get the FileRange of the invalid field access
     let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
     let expr = d.expr.value.to_node(&root).left()?;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 00c2a8c4c46..1f2d671249d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -18,7 +18,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_ran
 // This diagnostic is triggered if a method does not exist on a given type.
 pub(crate) fn unresolved_method(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::UnresolvedMethodCall,
+    d: &hir::UnresolvedMethodCall<'_>,
 ) -> Diagnostic {
     let suffix = if d.field_with_same_name.is_some() {
         ", but a field with a similar name exists"
@@ -49,7 +49,7 @@ pub(crate) fn unresolved_method(
     .with_fixes(fixes(ctx, d))
 }
 
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Vec<Assist>> {
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall<'_>) -> Option<Vec<Assist>> {
     let field_fix = if let Some(ty) = &d.field_with_same_name {
         field_fix(ctx, d, ty)
     } else {
@@ -72,8 +72,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<
 
 fn field_fix(
     ctx: &DiagnosticsContext<'_>,
-    d: &hir::UnresolvedMethodCall,
-    ty: &hir::Type,
+    d: &hir::UnresolvedMethodCall<'_>,
+    ty: &hir::Type<'_>,
 ) -> Option<Assist> {
     if !ty.impls_fnonce(ctx.sema.db) {
         return None;
@@ -107,7 +107,10 @@ fn field_fix(
     })
 }
 
-fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Assist> {
+fn assoc_func_fix(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::UnresolvedMethodCall<'_>,
+) -> Option<Assist> {
     if let Some(f) = d.assoc_func_with_same_name {
         let db = ctx.sema.db;
 
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 43c56ac8bec..e4b20f3f1aa 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -110,7 +110,7 @@ pub struct SsrMatches {
 pub struct MatchFinder<'db> {
     /// Our source of information about the user's code.
     sema: Semantics<'db, ide_db::RootDatabase>,
-    rules: Vec<ResolvedRule>,
+    rules: Vec<ResolvedRule<'db>>,
     resolution_scope: resolving::ResolutionScope<'db>,
     restrict_ranges: Vec<ide_db::FileRange>,
 }
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index cff4eede042..b350315ba54 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -84,12 +84,12 @@ pub(crate) struct MatchFailed {
 /// Checks if `code` matches the search pattern found in `search_scope`, returning information about
 /// the match, if it does. Since we only do matching in this module and searching is done by the
 /// parent module, we don't populate nested matches.
-pub(crate) fn get_match(
+pub(crate) fn get_match<'db>(
     debug_active: bool,
-    rule: &ResolvedRule,
+    rule: &ResolvedRule<'db>,
     code: &SyntaxNode,
     restrict_range: &Option<FileRange>,
-    sema: &Semantics<'_, ide_db::RootDatabase>,
+    sema: &Semantics<'db, ide_db::RootDatabase>,
 ) -> Result<Match, MatchFailed> {
     record_match_fails_reasons_scope(debug_active, || {
         Matcher::try_match(rule, code, restrict_range, sema)
@@ -102,7 +102,7 @@ struct Matcher<'db, 'sema> {
     /// If any placeholders come from anywhere outside of this range, then the match will be
     /// rejected.
     restrict_range: Option<FileRange>,
-    rule: &'sema ResolvedRule,
+    rule: &'sema ResolvedRule<'db>,
 }
 
 /// Which phase of matching we're currently performing. We do two phases because most attempted
@@ -117,7 +117,7 @@ enum Phase<'a> {
 
 impl<'db, 'sema> Matcher<'db, 'sema> {
     fn try_match(
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         code: &SyntaxNode,
         restrict_range: &Option<FileRange>,
         sema: &'sema Semantics<'db, ide_db::RootDatabase>,
@@ -535,7 +535,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
     fn attempt_match_ufcs_to_method_call(
         &self,
         phase: &mut Phase<'_>,
-        pattern_ufcs: &UfcsCallInfo,
+        pattern_ufcs: &UfcsCallInfo<'db>,
         code: &ast::MethodCallExpr,
     ) -> Result<(), MatchFailed> {
         use ast::HasArgList;
@@ -597,7 +597,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
     fn attempt_match_ufcs_to_ufcs(
         &self,
         phase: &mut Phase<'_>,
-        pattern_ufcs: &UfcsCallInfo,
+        pattern_ufcs: &UfcsCallInfo<'db>,
         code: &ast::CallExpr,
     ) -> Result<(), MatchFailed> {
         use ast::HasArgList;
@@ -615,7 +615,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
     /// times. Returns the number of times it needed to be dereferenced.
     fn check_expr_type(
         &self,
-        pattern_type: &hir::Type,
+        pattern_type: &hir::Type<'db>,
         expr: &ast::Expr,
     ) -> Result<usize, MatchFailed> {
         use hir::HirDisplay;
@@ -656,10 +656,10 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
 }
 
 impl Match {
-    fn render_template_paths(
+    fn render_template_paths<'db>(
         &mut self,
-        template: &ResolvedPattern,
-        sema: &Semantics<'_, ide_db::RootDatabase>,
+        template: &ResolvedPattern<'db>,
+        sema: &Semantics<'db, ide_db::RootDatabase>,
     ) -> Result<(), MatchFailed> {
         let module = sema
             .scope(&self.matched_node)
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
index 3c92697926f..752edd6535a 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
@@ -14,21 +14,21 @@ use crate::{Match, SsrMatches, fragments, resolving::ResolvedRule};
 /// Returns a text edit that will replace each match in `matches` with its corresponding replacement
 /// template. Placeholders in the template will have been substituted with whatever they matched to
 /// in the original code.
-pub(crate) fn matches_to_edit(
-    db: &dyn hir::db::ExpandDatabase,
+pub(crate) fn matches_to_edit<'db>(
+    db: &'db dyn hir::db::ExpandDatabase,
     matches: &SsrMatches,
     file_src: &str,
-    rules: &[ResolvedRule],
+    rules: &[ResolvedRule<'db>],
 ) -> TextEdit {
     matches_to_edit_at_offset(db, matches, file_src, 0.into(), rules)
 }
 
-fn matches_to_edit_at_offset(
-    db: &dyn hir::db::ExpandDatabase,
+fn matches_to_edit_at_offset<'db>(
+    db: &'db dyn hir::db::ExpandDatabase,
     matches: &SsrMatches,
     file_src: &str,
     relative_start: TextSize,
-    rules: &[ResolvedRule],
+    rules: &[ResolvedRule<'db>],
 ) -> TextEdit {
     let mut edit_builder = TextEdit::builder();
     for m in &matches.matches {
@@ -40,12 +40,12 @@ fn matches_to_edit_at_offset(
     edit_builder.finish()
 }
 
-struct ReplacementRenderer<'a> {
-    db: &'a dyn hir::db::ExpandDatabase,
+struct ReplacementRenderer<'a, 'db> {
+    db: &'db dyn hir::db::ExpandDatabase,
     match_info: &'a Match,
     file_src: &'a str,
-    rules: &'a [ResolvedRule],
-    rule: &'a ResolvedRule,
+    rules: &'a [ResolvedRule<'db>],
+    rule: &'a ResolvedRule<'db>,
     out: String,
     // Map from a range within `out` to a token in `template` that represents a placeholder. This is
     // used to validate that the generated source code doesn't split any placeholder expansions (see
@@ -58,11 +58,11 @@ struct ReplacementRenderer<'a> {
     edition: Edition,
 }
 
-fn render_replace(
-    db: &dyn hir::db::ExpandDatabase,
+fn render_replace<'db>(
+    db: &'db dyn hir::db::ExpandDatabase,
     match_info: &Match,
     file_src: &str,
-    rules: &[ResolvedRule],
+    rules: &[ResolvedRule<'db>],
     edition: Edition,
 ) -> String {
     let rule = &rules[match_info.rule_index];
@@ -89,7 +89,7 @@ fn render_replace(
     renderer.out
 }
 
-impl ReplacementRenderer<'_> {
+impl<'db> ReplacementRenderer<'_, 'db> {
     fn render_node_children(&mut self, node: &SyntaxNode) {
         for node_or_token in node.children_with_tokens() {
             self.render_node_or_token(&node_or_token);
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs
index a687db4bf58..8f28a1cd3a6 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs
@@ -15,18 +15,18 @@ pub(crate) struct ResolutionScope<'db> {
     node: SyntaxNode,
 }
 
-pub(crate) struct ResolvedRule {
-    pub(crate) pattern: ResolvedPattern,
-    pub(crate) template: Option<ResolvedPattern>,
+pub(crate) struct ResolvedRule<'db> {
+    pub(crate) pattern: ResolvedPattern<'db>,
+    pub(crate) template: Option<ResolvedPattern<'db>>,
     pub(crate) index: usize,
 }
 
-pub(crate) struct ResolvedPattern {
+pub(crate) struct ResolvedPattern<'db> {
     pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
     pub(crate) node: SyntaxNode,
     // Paths in `node` that we've resolved.
     pub(crate) resolved_paths: FxHashMap<SyntaxNode, ResolvedPath>,
-    pub(crate) ufcs_function_calls: FxHashMap<SyntaxNode, UfcsCallInfo>,
+    pub(crate) ufcs_function_calls: FxHashMap<SyntaxNode, UfcsCallInfo<'db>>,
     pub(crate) contains_self: bool,
 }
 
@@ -36,18 +36,18 @@ pub(crate) struct ResolvedPath {
     pub(crate) depth: u32,
 }
 
-pub(crate) struct UfcsCallInfo {
+pub(crate) struct UfcsCallInfo<'db> {
     pub(crate) call_expr: ast::CallExpr,
     pub(crate) function: hir::Function,
-    pub(crate) qualifier_type: Option<hir::Type>,
+    pub(crate) qualifier_type: Option<hir::Type<'db>>,
 }
 
-impl ResolvedRule {
+impl<'db> ResolvedRule<'db> {
     pub(crate) fn new(
         rule: parsing::ParsedRule,
-        resolution_scope: &ResolutionScope<'_>,
+        resolution_scope: &ResolutionScope<'db>,
         index: usize,
-    ) -> Result<ResolvedRule, SsrError> {
+    ) -> Result<ResolvedRule<'db>, SsrError> {
         let resolver =
             Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in };
         let resolved_template = match rule.template {
@@ -74,8 +74,8 @@ struct Resolver<'a, 'db> {
     placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
 }
 
-impl Resolver<'_, '_> {
-    fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result<ResolvedPattern, SsrError> {
+impl<'db> Resolver<'_, 'db> {
+    fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result<ResolvedPattern<'db>, SsrError> {
         use syntax::ast::AstNode;
         use syntax::{SyntaxElement, T};
         let mut resolved_paths = FxHashMap::default();
@@ -250,7 +250,7 @@ impl<'db> ResolutionScope<'db> {
         }
     }
 
-    fn qualifier_type(&self, path: &SyntaxNode) -> Option<hir::Type> {
+    fn qualifier_type(&self, path: &SyntaxNode) -> Option<hir::Type<'db>> {
         use syntax::ast::AstNode;
         if let Some(path) = ast::Path::cast(path.clone()) {
             if let Some(qualifier) = path.qualifier() {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
index 9afbedbb1ab..99a98fb2a71 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
@@ -21,13 +21,13 @@ pub(crate) struct UsageCache {
     usages: Vec<(Definition, UsageSearchResult)>,
 }
 
-impl MatchFinder<'_> {
+impl<'db> MatchFinder<'db> {
     /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make
     /// replacement impossible, so further processing is required in order to properly nest matches
     /// and remove overlapping matches. This is done in the `nesting` module.
     pub(crate) fn find_matches_for_rule(
         &self,
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         usage_cache: &mut UsageCache,
         matches_out: &mut Vec<Match>,
     ) {
@@ -49,8 +49,8 @@ impl MatchFinder<'_> {
 
     fn find_matches_for_pattern_tree(
         &self,
-        rule: &ResolvedRule,
-        pattern: &ResolvedPattern,
+        rule: &ResolvedRule<'db>,
+        pattern: &ResolvedPattern<'db>,
         usage_cache: &mut UsageCache,
         matches_out: &mut Vec<Match>,
     ) {
@@ -144,7 +144,7 @@ impl MatchFinder<'_> {
         SearchScope::files(&files)
     }
 
-    fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec<Match>) {
+    fn slow_scan(&self, rule: &ResolvedRule<'db>, matches_out: &mut Vec<Match>) {
         self.search_files_do(|file_id| {
             let file = self.sema.parse_guess_edition(file_id);
             let code = file.syntax();
@@ -177,7 +177,7 @@ impl MatchFinder<'_> {
     fn slow_scan_node(
         &self,
         code: &SyntaxNode,
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         restrict_range: &Option<FileRange>,
         matches_out: &mut Vec<Match>,
     ) {
@@ -206,7 +206,7 @@ impl MatchFinder<'_> {
 
     fn try_add_match(
         &self,
-        rule: &ResolvedRule,
+        rule: &ResolvedRule<'db>,
         code: &SyntaxNode,
         restrict_range: &Option<FileRange>,
         matches_out: &mut Vec<Match>,
@@ -274,7 +274,7 @@ impl UsageCache {
 /// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't
 /// something that we can find references to. We then somewhat arbitrarily pick the path that is the
 /// longest as this is hopefully more likely to be less common, making it faster to find.
-fn pick_path_for_usages(pattern: &ResolvedPattern) -> Option<&ResolvedPath> {
+fn pick_path_for_usages<'a>(pattern: &'a ResolvedPattern<'_>) -> Option<&'a ResolvedPath> {
     // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are
     // private to the current module, then we definitely would want to pick them over say a path
     // from std. Possibly we should go further than this and intersect the search scopes for all
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index 1bc28f28b6f..02d96a64732 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -83,7 +83,7 @@ pub(crate) fn goto_implementation(
     Some(RangeInfo { range, info: navs })
 }
 
-fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec<NavigationTarget> {
+fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type<'_>) -> Vec<NavigationTarget> {
     Impl::all_for_type(sema.db, ty)
         .into_iter()
         .filter_map(|imp| imp.try_to_nav(sema.db))
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index 9781e7116de..86d72fefe05 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -38,7 +38,7 @@ pub(crate) fn goto_type_definition(
             }
         }
     };
-    let mut process_ty = |ty: hir::Type| {
+    let mut process_ty = |ty: hir::Type<'_>| {
         // collect from each `ty` into the `res` result vec
         let ty = ty.strip_references();
         ty.walk(db, |t| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 5404a9dc2ce..e4d6279759e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -426,7 +426,7 @@ pub(crate) fn hover_for_definition(
     sema: &Semantics<'_, RootDatabase>,
     file_id: FileId,
     def: Definition,
-    subst: Option<GenericSubstitution>,
+    subst: Option<GenericSubstitution<'_>>,
     scope_node: &SyntaxNode,
     macro_arm: Option<u32>,
     render_extras: bool,
@@ -483,10 +483,10 @@ pub(crate) fn hover_for_definition(
     }
 }
 
-fn notable_traits(
-    db: &RootDatabase,
-    ty: &hir::Type,
-) -> Vec<(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)> {
+fn notable_traits<'db>(
+    db: &'db RootDatabase,
+    ty: &hir::Type<'db>,
+) -> Vec<(hir::Trait, Vec<(Option<hir::Type<'db>>, hir::Name)>)> {
     db.notable_traits_in_deps(ty.krate(db).into())
         .iter()
         .flat_map(|it| &**it)
@@ -567,8 +567,8 @@ fn runnable_action(
 fn goto_type_action_for_def(
     db: &RootDatabase,
     def: Definition,
-    notable_traits: &[(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)],
-    subst_types: Option<Vec<(hir::Symbol, hir::Type)>>,
+    notable_traits: &[(hir::Trait, Vec<(Option<hir::Type<'_>>, hir::Name)>)],
+    subst_types: Option<Vec<(hir::Symbol, hir::Type<'_>)>>,
     edition: Edition,
 ) -> Option<HoverAction> {
     let mut targets: Vec<hir::ModuleDef> = Vec::new();
@@ -622,7 +622,7 @@ fn goto_type_action_for_def(
 
 fn walk_and_push_ty(
     db: &RootDatabase,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     push_new_def: &mut dyn FnMut(hir::ModuleDef),
 ) {
     ty.walk(db, |t| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index c24864a18bd..670210d4998 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -476,10 +476,10 @@ pub(super) fn definition(
     db: &RootDatabase,
     def: Definition,
     famous_defs: Option<&FamousDefs<'_, '_>>,
-    notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
+    notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
     macro_arm: Option<u32>,
     render_extras: bool,
-    subst_types: Option<&Vec<(Symbol, Type)>>,
+    subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
     config: &HoverConfig,
     edition: Edition,
     display_target: DisplayTarget,
@@ -938,7 +938,7 @@ pub(super) fn literal(
 
 fn render_notable_trait(
     db: &RootDatabase,
-    notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
+    notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<String> {
@@ -979,7 +979,7 @@ fn render_notable_trait(
 fn type_info(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
-    ty: TypeInfo,
+    ty: TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<HoverResult> {
@@ -1038,7 +1038,7 @@ fn type_info(
 fn closure_ty(
     sema: &Semantics<'_, RootDatabase>,
     config: &HoverConfig,
-    TypeInfo { original, adjusted }: &TypeInfo,
+    TypeInfo { original, adjusted }: &TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<HoverResult> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index b094b098462..19e5509681a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -722,14 +722,14 @@ impl InlayHintLabelBuilder<'_> {
 fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     display_target: DisplayTarget,
 ) -> Option<InlayHintLabel> {
     fn rec(
         sema: &Semantics<'_, RootDatabase>,
         famous_defs: &FamousDefs<'_, '_>,
         mut max_length: Option<usize>,
-        ty: &hir::Type,
+        ty: &hir::Type<'_>,
         label_builder: &mut InlayHintLabelBuilder<'_>,
         config: &InlayHintsConfig,
         display_target: DisplayTarget,
@@ -788,11 +788,11 @@ fn label_of_ty(
 }
 
 /// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator.
-fn hint_iterator(
-    sema: &Semantics<'_, RootDatabase>,
-    famous_defs: &FamousDefs<'_, '_>,
-    ty: &hir::Type,
-) -> Option<(hir::Trait, hir::TypeAlias, hir::Type)> {
+fn hint_iterator<'db>(
+    sema: &Semantics<'db, RootDatabase>,
+    famous_defs: &FamousDefs<'_, 'db>,
+    ty: &hir::Type<'db>,
+) -> Option<(hir::Trait, hir::TypeAlias, hir::Type<'db>)> {
     let db = sema.db;
     let strukt = ty.strip_references().as_adt()?;
     let krate = strukt.module(db).krate();
@@ -826,7 +826,7 @@ fn ty_to_text_edit(
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
     node_for_hint: &SyntaxNode,
-    ty: &hir::Type,
+    ty: &hir::Type<'_>,
     offset_to_insert_ty: TextSize,
     additional_edits: &dyn Fn(&mut TextEditBuilder),
     prefix: impl Into<String>,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 5ff9fee60ab..5174228466c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -87,10 +87,10 @@ pub(super) fn hints(
     Some(())
 }
 
-fn get_callable(
-    sema: &Semantics<'_, RootDatabase>,
+fn get_callable<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     expr: &ast::Expr,
-) -> Option<(hir::Callable, ast::ArgList)> {
+) -> Option<(hir::Callable<'db>, ast::ArgList)> {
     match expr {
         ast::Expr::CallExpr(expr) => {
             let descended = sema.descend_node_into_attributes(expr.clone()).pop();
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 82dbcde4c06..b3b8deb61fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -409,7 +409,7 @@ impl Analysis {
         self.with_db(|db| typing::on_enter(db, position))
     }
 
-    pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS;
+    pub const SUPPORTED_TRIGGER_CHARS: &[char] = typing::TRIGGER_CHARS;
 
     /// Returns an edit which should be applied after a character was typed.
     ///
@@ -421,7 +421,7 @@ impl Analysis {
         char_typed: char,
     ) -> Cancellable<Option<SourceChange>> {
         // Fast path to not even parse the file.
-        if !typing::TRIGGER_CHARS.contains(char_typed) {
+        if !typing::TRIGGER_CHARS.contains(&char_typed) {
             return Ok(None);
         }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 0e17b355907..e30a3ebefb9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -278,7 +278,7 @@ fn signature_help_for_call(
     }
     res.signature.push(')');
 
-    let mut render = |ret_type: hir::Type| {
+    let mut render = |ret_type: hir::Type<'_>| {
         if !ret_type.is_unit() {
             format_to!(res.signature, " -> {}", ret_type.display(db, display_target));
         }
@@ -597,11 +597,11 @@ fn signature_help_for_tuple_expr(
     Some(res)
 }
 
-fn signature_help_for_record_(
-    sema: &Semantics<'_, RootDatabase>,
+fn signature_help_for_record_<'db>(
+    sema: &Semantics<'db, RootDatabase>,
     field_list_children: SyntaxElementChildren,
     path: &ast::Path,
-    fields2: impl Iterator<Item = (hir::Field, hir::Type)>,
+    fields2: impl Iterator<Item = (hir::Field, hir::Type<'db>)>,
     token: SyntaxToken,
     edition: Edition,
     display_target: DisplayTarget,
@@ -689,13 +689,13 @@ fn signature_help_for_record_(
     Some(res)
 }
 
-fn signature_help_for_tuple_pat_ish(
-    db: &RootDatabase,
+fn signature_help_for_tuple_pat_ish<'db>(
+    db: &'db RootDatabase,
     mut res: SignatureHelp,
     pat: &SyntaxNode,
     token: SyntaxToken,
     mut field_pats: AstChildren<ast::Pat>,
-    fields: impl ExactSizeIterator<Item = hir::Type>,
+    fields: impl ExactSizeIterator<Item = hir::Type<'db>>,
     display_target: DisplayTarget,
 ) -> SignatureHelp {
     let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index 4df7e25223d..ed55ac5bf04 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -15,6 +15,7 @@
 
 mod on_enter;
 
+use either::Either;
 use hir::EditionedFileId;
 use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
 use span::Edition;
@@ -33,7 +34,7 @@ use crate::SourceChange;
 pub(crate) use on_enter::on_enter;
 
 // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
-pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|";
+pub(crate) const TRIGGER_CHARS: &[char] = &['.', '=', '<', '>', '{', '(', '|', '+'];
 
 struct ExtendedTextEdit {
     edit: TextEdit,
@@ -66,7 +67,7 @@ pub(crate) fn on_char_typed(
     position: FilePosition,
     char_typed: char,
 ) -> Option<SourceChange> {
-    if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
+    if !TRIGGER_CHARS.contains(&char_typed) {
         return None;
     }
     // FIXME: We need to figure out the edition of the file here, but that means hitting the
@@ -101,6 +102,7 @@ fn on_char_typed_(
         '>' => on_right_angle_typed(&file.tree(), offset),
         '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition),
         '|' => on_pipe_typed(&file.tree(), offset),
+        '+' => on_plus_typed(&file.tree(), offset),
         _ => None,
     }
     .map(conv)
@@ -402,6 +404,28 @@ fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
     Some(TextEdit::insert(after_lpipe, "|".to_owned()))
 }
 
+fn on_plus_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
+    let plus_token = file.syntax().token_at_offset(offset).right_biased()?;
+    if plus_token.kind() != SyntaxKind::PLUS {
+        return None;
+    }
+    let mut ancestors = plus_token.parent_ancestors();
+    ancestors.next().and_then(ast::TypeBoundList::cast)?;
+    let trait_type =
+        ancestors.next().and_then(<Either<ast::DynTraitType, ast::ImplTraitType>>::cast)?;
+    let kind = ancestors.next()?.kind();
+
+    if ast::RefType::can_cast(kind) || ast::PtrType::can_cast(kind) || ast::RetType::can_cast(kind)
+    {
+        let mut builder = TextEdit::builder();
+        builder.insert(trait_type.syntax().text_range().start(), "(".to_owned());
+        builder.insert(trait_type.syntax().text_range().end(), ")".to_owned());
+        Some(builder.finish())
+    } else {
+        None
+    }
+}
+
 /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
 fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
     let file_text = file.syntax().text();
@@ -1597,4 +1621,64 @@ fn foo() {
 "#,
         );
     }
+
+    #[test]
+    fn adds_parentheses_around_trait_object_in_ref_type() {
+        type_char(
+            '+',
+            r#"
+fn foo(x: &dyn A$0) {}
+"#,
+            r#"
+fn foo(x: &(dyn A+)) {}
+"#,
+        );
+        type_char(
+            '+',
+            r#"
+fn foo(x: &'static dyn A$0B) {}
+"#,
+            r#"
+fn foo(x: &'static (dyn A+B)) {}
+"#,
+        );
+        type_char_noop(
+            '+',
+            r#"
+fn foo(x: &(dyn A$0)) {}
+"#,
+        );
+        type_char_noop(
+            '+',
+            r#"
+fn foo(x: Box<dyn A$0>) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn adds_parentheses_around_trait_object_in_ptr_type() {
+        type_char(
+            '+',
+            r#"
+fn foo(x: *const dyn A$0) {}
+"#,
+            r#"
+fn foo(x: *const (dyn A+)) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn adds_parentheses_around_trait_object_in_return_type() {
+        type_char(
+            '+',
+            r#"
+fn foo(x: fn() -> dyn A$0) {}
+"#,
+            r#"
+fn foo(x: fn() -> (dyn A+)) {}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index 140ae4265be..63701a4d15e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -107,7 +107,7 @@ pub(crate) fn view_memory_layout(
     fn read_layout(
         nodes: &mut Vec<MemoryLayoutNode>,
         db: &RootDatabase,
-        ty: &Type,
+        ty: &Type<'_>,
         layout: &Layout,
         parent_idx: usize,
         display_target: DisplayTarget,
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index d5cbb7328c1..adc581309d1 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -496,6 +496,7 @@ define_symbols! {
     vectorcall,
     wasm,
     win64,
+    args,
     array,
     boxed_slice,
     completions,
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 89b8631cd25..52f59679b58 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -42,7 +42,7 @@ pub fn load_workspace_at(
     root: &Path,
     cargo_config: &CargoConfig,
     load_config: &LoadCargoConfig,
-    progress: &dyn Fn(String),
+    progress: &(dyn Fn(String) + Sync),
 ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> {
     let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root));
     let root = ProjectManifest::discover_single(&root)?;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index e0c38ccf333..4435376eab6 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -20,7 +20,9 @@ use toolchain::Tool;
 
 use crate::{
     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
-    TargetKind, utf8_stdout,
+    TargetKind,
+    toolchain_info::{QueryConfig, version},
+    utf8_stdout,
 };
 
 /// Output of the build script and proc-macro building steps for a workspace.
@@ -446,10 +448,30 @@ impl WorkspaceBuildScripts {
             }
         };
 
-        if config.wrap_rustc_in_build_scripts {
+        // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is
+        // available in current toolchain's cargo, use it to build compile time deps only.
+        const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version {
+            major: 1,
+            minor: 90,
+            patch: 0,
+            pre: semver::Prerelease::EMPTY,
+            build: semver::BuildMetadata::EMPTY,
+        };
+
+        let query_config = QueryConfig::Cargo(sysroot, manifest_path);
+        let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
+        let cargo_comp_time_deps_available =
+            toolchain.is_some_and(|v| v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION);
+
+        if cargo_comp_time_deps_available {
+            cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly");
+            cmd.arg("-Zunstable-options");
+            cmd.arg("--compile-time-deps");
+        } else if config.wrap_rustc_in_build_scripts {
             // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
             // that to compile only proc macros and build scripts during the initial
             // `cargo check`.
+            // We don't need this if we are using `--compile-time-deps` flag.
             let myself = std::env::current_exe()?;
             cmd.env("RUSTC_WRAPPER", myself);
             cmd.env("RA_RUSTC_WRAPPER", "1");
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 1fade7b3323..58507418e4d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -7,16 +7,25 @@ use anyhow::Context;
 use base_db::Env;
 use cargo_metadata::{CargoOpt, MetadataCommand};
 use la_arena::{Arena, Idx};
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use serde_derive::Deserialize;
 use serde_json::from_value;
 use span::Edition;
+use stdx::process::spawn_with_streaming_output;
 use toolchain::Tool;
 
 use crate::{CfgOverrides, InvocationStrategy};
 use crate::{ManifestPath, Sysroot};
 
+const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version = semver::Version {
+    major: 1,
+    minor: 82,
+    patch: 0,
+    pre: semver::Prerelease::EMPTY,
+    build: semver::BuildMetadata::EMPTY,
+};
+
 /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
 /// workspace. It pretty closely mirrors `cargo metadata` output.
 ///
@@ -290,6 +299,13 @@ pub struct CargoMetadataConfig {
     pub extra_args: Vec<String>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, Option<String>>,
+    /// The target dir for this workspace load.
+    pub target_dir: Utf8PathBuf,
+    /// What kind of metadata are we fetching: workspace, rustc, or sysroot.
+    pub kind: &'static str,
+    /// The toolchain version, if known.
+    /// Used to conditionally enable unstable cargo features.
+    pub toolchain_version: Option<semver::Version>,
 }
 
 // Deserialize helper for the cargo metadata
@@ -382,28 +398,74 @@ impl CargoWorkspace {
                 config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]),
             );
         }
+        if no_deps {
+            other_options.push("--no-deps".to_owned());
+        }
+
+        let mut using_lockfile_copy = false;
         // The manifest is a rust file, so this means its a script manifest
         if cargo_toml.is_rust_manifest() {
-            // Deliberately don't set up RUSTC_BOOTSTRAP or a nightly override here, the user should
-            // opt into it themselves.
             other_options.push("-Zscript".to_owned());
+        } else if config
+            .toolchain_version
+            .as_ref()
+            .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH)
+        {
+            let lockfile = <_ as AsRef<Utf8Path>>::as_ref(cargo_toml).with_extension("lock");
+            let target_lockfile = config
+                .target_dir
+                .join("rust-analyzer")
+                .join("metadata")
+                .join(config.kind)
+                .join("Cargo.lock");
+            match std::fs::copy(&lockfile, &target_lockfile) {
+                Ok(_) => {
+                    using_lockfile_copy = true;
+                    other_options.push("--lockfile-path".to_owned());
+                    other_options.push(target_lockfile.to_string());
+                }
+                Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
+                    // There exists no lockfile yet
+                    using_lockfile_copy = true;
+                    other_options.push("--lockfile-path".to_owned());
+                    other_options.push(target_lockfile.to_string());
+                }
+                Err(e) => {
+                    tracing::warn!(
+                        "Failed to copy lock file from `{lockfile}` to `{target_lockfile}`: {e}",
+                    );
+                }
+            }
         }
-        if locked {
-            other_options.push("--locked".to_owned());
+        if using_lockfile_copy {
+            other_options.push("-Zunstable-options".to_owned());
+            meta.env("RUSTC_BOOTSTRAP", "1");
         }
-        if no_deps {
-            other_options.push("--no-deps".to_owned());
+        // No need to lock it if we copied the lockfile, we won't modify the original after all/
+        // This way cargo cannot error out on us if the lockfile requires updating.
+        if !using_lockfile_copy && locked {
+            other_options.push("--locked".to_owned());
         }
         meta.other_options(other_options);
 
         // FIXME: Fetching metadata is a slow process, as it might require
         // calling crates.io. We should be reporting progress here, but it's
         // unclear whether cargo itself supports it.
-        progress("metadata".to_owned());
-
-        (|| -> anyhow::Result<(_, _)> {
-            let output = meta.cargo_command().output()?;
+        progress("cargo metadata: started".to_owned());
+
+        let res = (|| -> anyhow::Result<(_, _)> {
+            let mut errored = false;
+            let output =
+                spawn_with_streaming_output(meta.cargo_command(), &mut |_| (), &mut |line| {
+                    errored = errored || line.starts_with("error") || line.starts_with("warning");
+                    if errored {
+                        progress("cargo metadata: ?".to_owned());
+                        return;
+                    }
+                    progress(format!("cargo metadata: {line}"));
+                })?;
             if !output.status.success() {
+                progress(format!("cargo metadata: failed {}", output.status));
                 let error = cargo_metadata::Error::CargoMetadata {
                     stderr: String::from_utf8(output.stderr)?,
                 }
@@ -416,8 +478,8 @@ impl CargoWorkspace {
                         current_dir,
                         config,
                         sysroot,
-                        locked,
                         true,
+                        locked,
                         progress,
                     ) {
                         return Ok((metadata, Some(error)));
@@ -431,7 +493,9 @@ impl CargoWorkspace {
                 .ok_or(cargo_metadata::Error::NoJson)?;
             Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None))
         })()
-        .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
+        .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()));
+        progress("cargo metadata: finished".to_owned());
+        res
     }
 
     pub fn new(
diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
index 4f43be2f38f..fba8cc9709d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
@@ -1,7 +1,7 @@
 //! See [`ManifestPath`].
 use std::{borrow::Borrow, fmt, ops};
 
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path};
 
 /// More or less [`AbsPathBuf`] with non-None parent.
 ///
@@ -78,6 +78,12 @@ impl AsRef<std::ffi::OsStr> for ManifestPath {
     }
 }
 
+impl AsRef<Utf8Path> for ManifestPath {
+    fn as_ref(&self) -> &Utf8Path {
+        self.file.as_ref()
+    }
+}
+
 impl Borrow<AbsPath> for ManifestPath {
     fn borrow(&self) -> &AbsPath {
         self.file.borrow()
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index ebd86e3dc48..4b34fc00711 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -4,6 +4,7 @@
 //! but we can't process `.rlib` and need source code instead. The source code
 //! is typically installed with `rustup component add rust-src` command.
 
+use core::fmt;
 use std::{env, fs, ops::Not, path::Path, process::Command};
 
 use anyhow::{Result, format_err};
@@ -34,6 +35,19 @@ pub enum RustLibSrcWorkspace {
     Empty,
 }
 
+impl fmt::Display for RustLibSrcWorkspace {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()),
+            RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()),
+            RustLibSrcWorkspace::Stitched(stitched) => {
+                write!(f, "stitched with {} crates", stitched.crates.len())
+            }
+            RustLibSrcWorkspace::Empty => write!(f, "empty"),
+        }
+    }
+}
+
 impl Sysroot {
     pub const fn empty() -> Sysroot {
         Sysroot {
@@ -195,6 +209,8 @@ impl Sysroot {
     pub fn load_workspace(
         &self,
         sysroot_source_config: &RustSourceWorkspaceConfig,
+        current_dir: &AbsPath,
+        progress: &dyn Fn(String),
     ) -> Option<RustLibSrcWorkspace> {
         assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
         let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self
@@ -204,10 +220,16 @@ impl Sysroot {
         if let RustSourceWorkspaceConfig::CargoMetadata(cargo_config) = sysroot_source_config {
             let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap();
             if fs::metadata(&library_manifest).is_ok() {
-                if let Some(loaded) =
-                    self.load_library_via_cargo(library_manifest, src_root, cargo_config)
-                {
-                    return Some(loaded);
+                match self.load_library_via_cargo(
+                    &library_manifest,
+                    current_dir,
+                    cargo_config,
+                    progress,
+                ) {
+                    Ok(loaded) => return Some(loaded),
+                    Err(e) => {
+                        tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}")
+                    }
                 }
             }
             tracing::debug!("Stitching sysroot library: {src_root}");
@@ -293,10 +315,11 @@ impl Sysroot {
 
     fn load_library_via_cargo(
         &self,
-        library_manifest: ManifestPath,
-        rust_lib_src_dir: &AbsPathBuf,
+        library_manifest: &ManifestPath,
+        current_dir: &AbsPath,
         cargo_config: &CargoMetadataConfig,
-    ) -> Option<RustLibSrcWorkspace> {
+        progress: &dyn Fn(String),
+    ) -> Result<RustLibSrcWorkspace> {
         tracing::debug!("Loading library metadata: {library_manifest}");
         let mut cargo_config = cargo_config.clone();
         // the sysroot uses `public-dependency`, so we make cargo think it's a nightly
@@ -305,22 +328,16 @@ impl Sysroot {
             Some("nightly".to_owned()),
         );
 
-        let (mut res, _) = match CargoWorkspace::fetch_metadata(
-            &library_manifest,
-            rust_lib_src_dir,
+        let (mut res, _) = CargoWorkspace::fetch_metadata(
+            library_manifest,
+            current_dir,
             &cargo_config,
             self,
             false,
             // Make sure we never attempt to write to the sysroot
             true,
-            &|_| (),
-        ) {
-            Ok(it) => it,
-            Err(e) => {
-                tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}");
-                return None;
-            }
-        };
+            progress,
+        )?;
 
         // Patch out `rustc-std-workspace-*` crates to point to the real crates.
         // This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing.
@@ -371,8 +388,9 @@ impl Sysroot {
             res.packages.remove(idx);
         });
 
-        let cargo_workspace = CargoWorkspace::new(res, library_manifest, Default::default(), true);
-        Some(RustLibSrcWorkspace::Workspace(cargo_workspace))
+        let cargo_workspace =
+            CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true);
+        Ok(RustLibSrcWorkspace::Workspace(cargo_workspace))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index c69891b7463..4f11af2d06c 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -1,3 +1,5 @@
+use std::env::temp_dir;
+
 use base_db::{CrateGraphBuilder, ProcMacroPaths};
 use cargo_metadata::Metadata;
 use cfg::{CfgAtom, CfgDiff};
@@ -235,11 +237,18 @@ fn smoke_test_real_sysroot_cargo() {
         AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
     );
-    let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+    let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo"));
+    std::fs::create_dir_all(&cwd).unwrap();
+    let loaded_sysroot =
+        sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &cwd, &|_| ());
     if let Some(loaded_sysroot) = loaded_sysroot {
         sysroot.set_workspace(loaded_sysroot);
     }
-    assert!(matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)));
+    assert!(
+        matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)),
+        "got {}",
+        sysroot.workspace()
+    );
     let project_workspace = ProjectWorkspace {
         kind: ProjectWorkspaceKind::Cargo {
             cargo: cargo_workspace,
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index eec0077ea6e..a6743a32b14 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -12,7 +12,7 @@ use base_db::{
 };
 use cfg::{CfgAtom, CfgDiff, CfgOptions};
 use intern::{Symbol, sym};
-use paths::{AbsPath, AbsPathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::{Edition, FileId};
@@ -170,7 +170,7 @@ impl ProjectWorkspace {
     pub fn load(
         manifest: ProjectManifest,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> anyhow::Result<ProjectWorkspace> {
         ProjectWorkspace::load_inner(&manifest, config, progress)
             .with_context(|| format!("Failed to load the project at {manifest}"))
@@ -179,7 +179,7 @@ impl ProjectWorkspace {
     fn load_inner(
         manifest: &ProjectManifest,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> anyhow::Result<ProjectWorkspace> {
         let res = match manifest {
             ProjectManifest::ProjectJson(project_json) => {
@@ -206,9 +206,10 @@ impl ProjectWorkspace {
     fn load_cargo(
         cargo_toml: &ManifestPath,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> Result<ProjectWorkspace, anyhow::Error> {
         progress("Discovering sysroot".to_owned());
+        let workspace_dir = cargo_toml.parent();
         let CargoConfig {
             features,
             rustc_source,
@@ -224,15 +225,9 @@ impl ProjectWorkspace {
             ..
         } = config;
         let mut sysroot = match (sysroot, sysroot_src) {
-            (Some(RustLibSource::Discover), None) => {
-                Sysroot::discover(cargo_toml.parent(), extra_env)
-            }
+            (Some(RustLibSource::Discover), None) => Sysroot::discover(workspace_dir, extra_env),
             (Some(RustLibSource::Discover), Some(sysroot_src)) => {
-                Sysroot::discover_with_src_override(
-                    cargo_toml.parent(),
-                    extra_env,
-                    sysroot_src.clone(),
-                )
+                Sysroot::discover_with_src_override(workspace_dir, extra_env, sysroot_src.clone())
             }
             (Some(RustLibSource::Path(path)), None) => {
                 Sysroot::discover_rust_lib_src_dir(path.clone())
@@ -248,24 +243,23 @@ impl ProjectWorkspace {
         let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml);
         let targets =
             target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default();
+        let toolchain = version::get(toolchain_config, extra_env)
+            .inspect_err(|e| {
+                tracing::error!(%e,
+                    "failed fetching toolchain version for {cargo_toml:?} workspace"
+                )
+            })
+            .ok()
+            .flatten();
+
+        let target_dir =
+            config.target_dir.clone().unwrap_or_else(|| workspace_dir.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
         // We can speed up loading a bit by spawning all of these processes in parallel (especially
         // on systems were process spawning is delayed)
         let join = thread::scope(|s| {
-            let workspace_dir = cargo_toml.parent();
-            let toolchain = s.spawn(|| {
-                version::get(toolchain_config, extra_env)
-                    .inspect_err(|e| {
-                        tracing::error!(%e,
-                            "failed fetching toolchain version for {cargo_toml:?} workspace"
-                        )
-                    })
-                    .ok()
-                    .flatten()
-            });
-
             let rustc_cfg = s.spawn(|| {
                 rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env)
             });
@@ -300,11 +294,14 @@ impl ProjectWorkspace {
                             targets: targets.clone(),
                             extra_args: extra_args.clone(),
                             extra_env: extra_env.clone(),
+                            target_dir: target_dir.clone(),
+                            toolchain_version: toolchain.clone(),
+                            kind: "rustc-dev"
                         },
                         &sysroot,
                         *no_deps,
-                        false,
-                        &|_| (),
+                        true,
+                        progress,
                     ) {
                         Ok((meta, _error)) => {
                             let workspace = CargoWorkspace::new(
@@ -343,22 +340,31 @@ impl ProjectWorkspace {
                         targets: targets.clone(),
                         extra_args: extra_args.clone(),
                         extra_env: extra_env.clone(),
+                        target_dir: target_dir.clone(),
+                        toolchain_version: toolchain.clone(),
+                        kind: "workspace",
                     },
                     &sysroot,
                     *no_deps,
                     false,
-                    &|_| (),
+                    progress,
                 )
             });
             let loaded_sysroot = s.spawn(|| {
-                sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
-                    sysroot_metadata_config(extra_env, &targets),
-                ))
+                sysroot.load_workspace(
+                    &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
+                        config,
+                        &targets,
+                        toolchain.clone(),
+                        target_dir.clone(),
+                    )),
+                    workspace_dir,
+                    progress,
+                )
             });
             let cargo_config_extra_env =
                 s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot));
             thread::Result::Ok((
-                toolchain.join()?,
                 rustc_cfg.join()?,
                 data_layout.join()?,
                 rustc_dir.join()?,
@@ -368,18 +374,11 @@ impl ProjectWorkspace {
             ))
         });
 
-        let (
-            toolchain,
-            rustc_cfg,
-            data_layout,
-            rustc,
-            loaded_sysroot,
-            cargo_metadata,
-            cargo_config_extra_env,
-        ) = match join {
-            Ok(it) => it,
-            Err(e) => std::panic::resume_unwind(e),
-        };
+        let (rustc_cfg, data_layout, rustc, loaded_sysroot, cargo_metadata, cargo_config_extra_env) =
+            match join {
+                Ok(it) => it,
+                Err(e) => std::panic::resume_unwind(e),
+            };
 
         let (meta, error) = cargo_metadata.with_context(|| {
             format!(
@@ -388,6 +387,7 @@ impl ProjectWorkspace {
         })?;
         let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env, false);
         if let Some(loaded_sysroot) = loaded_sysroot {
+            tracing::info!(src_root = ?sysroot.rust_lib_src_root(), root = %loaded_sysroot, "Loaded sysroot");
             sysroot.set_workspace(loaded_sysroot);
         }
 
@@ -411,7 +411,7 @@ impl ProjectWorkspace {
     pub fn load_inline(
         mut project_json: ProjectJson,
         config: &CargoConfig,
-        progress: &dyn Fn(String),
+        progress: &(dyn Fn(String) + Sync),
     ) -> ProjectWorkspace {
         progress("Discovering sysroot".to_owned());
         let mut sysroot =
@@ -423,14 +423,13 @@ impl ProjectWorkspace {
         let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref());
         let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
             .unwrap_or_default();
+        let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
         // We can speed up loading a bit by spawning all of these processes in parallel (especially
         // on systems were process spawning is delayed)
         let join = thread::scope(|s| {
-            let toolchain =
-                s.spawn(|| version::get(query_config, &config.extra_env).ok().flatten());
             let rustc_cfg = s.spawn(|| {
                 rustc_cfg::get(query_config, targets.first().map(Deref::deref), &config.extra_env)
             });
@@ -442,24 +441,35 @@ impl ProjectWorkspace {
                 )
             });
             let loaded_sysroot = s.spawn(|| {
+                let project_root = project_json.project_root();
                 if let Some(sysroot_project) = sysroot_project {
-                    sysroot.load_workspace(&RustSourceWorkspaceConfig::Json(*sysroot_project))
+                    sysroot.load_workspace(
+                        &RustSourceWorkspaceConfig::Json(*sysroot_project),
+                        project_root,
+                        progress,
+                    )
                 } else {
-                    sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
-                        sysroot_metadata_config(&config.extra_env, &targets),
-                    ))
+                    let target_dir = config
+                        .target_dir
+                        .clone()
+                        .unwrap_or_else(|| project_root.join("target").into());
+                    sysroot.load_workspace(
+                        &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
+                            config,
+                            &targets,
+                            toolchain.clone(),
+                            target_dir,
+                        )),
+                        project_root,
+                        progress,
+                    )
                 }
             });
 
-            thread::Result::Ok((
-                toolchain.join()?,
-                rustc_cfg.join()?,
-                data_layout.join()?,
-                loaded_sysroot.join()?,
-            ))
+            thread::Result::Ok((rustc_cfg.join()?, data_layout.join()?, loaded_sysroot.join()?))
         });
 
-        let (toolchain, rustc_cfg, target_layout, loaded_sysroot) = match join {
+        let (rustc_cfg, target_layout, loaded_sysroot) = match join {
             Ok(it) => it,
             Err(e) => std::panic::resume_unwind(e),
         };
@@ -497,9 +507,17 @@ impl ProjectWorkspace {
             .unwrap_or_default();
         let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
         let data_layout = target_data_layout::get(query_config, None, &config.extra_env);
-        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata(
-            sysroot_metadata_config(&config.extra_env, &targets),
-        ));
+        let target_dir = config.target_dir.clone().unwrap_or_else(|| dir.join("target").into());
+        let loaded_sysroot = sysroot.load_workspace(
+            &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
+                config,
+                &targets,
+                toolchain.clone(),
+                target_dir.clone(),
+            )),
+            dir,
+            &|_| (),
+        );
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
@@ -512,6 +530,9 @@ impl ProjectWorkspace {
                 targets,
                 extra_args: config.extra_args.clone(),
                 extra_env: config.extra_env.clone(),
+                target_dir,
+                toolchain_version: toolchain.clone(),
+                kind: "detached-file",
             },
             &sysroot,
             config.no_deps,
@@ -1804,13 +1825,18 @@ fn add_dep_inner(graph: &mut CrateGraphBuilder, from: CrateBuilderId, dep: Depen
 }
 
 fn sysroot_metadata_config(
-    extra_env: &FxHashMap<String, Option<String>>,
+    config: &CargoConfig,
     targets: &[String],
+    toolchain_version: Option<Version>,
+    target_dir: Utf8PathBuf,
 ) -> CargoMetadataConfig {
     CargoMetadataConfig {
         features: Default::default(),
         targets: targets.to_vec(),
         extra_args: Default::default(),
-        extra_env: extra_env.clone(),
+        extra_env: config.extra_env.clone(),
+        target_dir,
+        toolchain_version,
+        kind: "sysroot",
     }
 }
diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs
index baac3e8bbfe..c151cca0727 100644
--- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs
+++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs
@@ -74,8 +74,8 @@ impl ToTokens for TrackedQuery {
                 quote! {
                     #sig {
                         #annotation
-                        fn #shim(
-                            db: &dyn #trait_name,
+                        fn #shim<'db>(
+                            db: &'db dyn #trait_name,
                             _input: #input_struct_name,
                             #(#pat_and_tys),*
                         ) #ret
@@ -88,8 +88,8 @@ impl ToTokens for TrackedQuery {
                 quote! {
                     #sig {
                         #annotation
-                        fn #shim(
-                            db: &dyn #trait_name,
+                        fn #shim<'db>(
+                            db: &'db dyn #trait_name,
                             #(#pat_and_tys),*
                         ) #ret
                             #invoke_block
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 12b393b80c0..0ee01982fea 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -532,7 +532,7 @@ impl flags::AnalysisStats {
                 }
 
                 let todo = syntax::ast::make::ext::expr_todo().to_string();
-                let mut formatter = |_: &hir::Type| todo.clone();
+                let mut formatter = |_: &hir::Type<'_>| todo.clone();
                 let mut syntax_hit_found = false;
                 for term in found_terms {
                     let generated = term
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index e3b372c9149..740fcd81ea9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -9,7 +9,6 @@ use hir::{ChangeWithProcMacros, Crate};
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use ide_db::base_db;
 use itertools::Either;
-use paths::Utf8PathBuf;
 use profile::StopWatch;
 use project_model::toolchain_info::{QueryConfig, target_data_layout};
 use project_model::{
@@ -64,9 +63,9 @@ fn detect_errors_from_rustc_stderr_file(p: PathBuf) -> FxHashMap<DiagnosticCode,
 
 impl Tester {
     fn new() -> Result<Self> {
-        let mut path = std::env::temp_dir();
-        path.push("ra-rustc-test.rs");
-        let tmp_file = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).unwrap()).unwrap();
+        let mut path = AbsPathBuf::assert_utf8(std::env::temp_dir());
+        path.push("ra-rustc-test");
+        let tmp_file = path.join("ra-rustc-test.rs");
         std::fs::write(&tmp_file, "")?;
         let cargo_config = CargoConfig {
             sysroot: Some(RustLibSource::Discover),
@@ -76,7 +75,8 @@ impl Tester {
         };
 
         let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env);
-        let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo());
+        let loaded_sysroot =
+            sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &path, &|_| ());
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 762b63f54b0..05e1b832cd1 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -452,6 +452,8 @@ config_data! {
         assist_emitMustUse: bool               = false,
         /// Placeholder expression to use for missing expressions in assists.
         assist_expressionFillDefault: ExprFillDefaultDef              = ExprFillDefaultDef::Todo,
+        /// When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible.
+        assist_preferSelf: bool = false,
         /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.
         assist_termSearch_borrowcheck: bool = true,
         /// Term search fuel in "units of work" for assists (Defaults to 1800).
@@ -760,7 +762,11 @@ config_data! {
         /// though Cargo might be the eventual consumer.
         vfs_extraIncludes: Vec<String> = vec![],
 
-        /// Exclude imports from symbol search.
+        /// Exclude all imports from workspace symbol search.
+        ///
+        /// In addition to regular imports (which are always excluded),
+        /// this option removes public imports (better known as re-exports)
+        /// and removes imports that rename the imported symbol.
         workspace_symbol_search_excludeImports: bool = false,
         /// Workspace symbol search kind.
         workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
@@ -1505,6 +1511,7 @@ impl Config {
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
                 ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore,
             },
+            prefer_self_ty: *self.assist_preferSelf(source_root),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index b7373f274f0..200e972e428 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -239,7 +239,7 @@ pub(crate) fn handle_did_change_configuration(
                         let (config, e, _) = config.apply_change(change);
                         this.config_errors = e.is_empty().not().then_some(e);
 
-                        // Client config changes neccesitates .update_config method to be called.
+                        // Client config changes necessitates .update_config method to be called.
                         this.update_configuration(config);
                     }
                 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 418fe957590..04e31f37fd2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -77,7 +77,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             _ => Some(OneOf::Left(false)),
         },
         document_on_type_formatting_provider: Some({
-            let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars();
+            let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.iter();
             DocumentOnTypeFormattingOptions {
                 first_trigger_character: chars.next().unwrap().to_string(),
                 more_trigger_character: Some(chars.map(|c| c.to_string()).collect()),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 4677880daaf..189d95ec7ed 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -114,6 +114,16 @@ impl GlobalState {
                 Durability::HIGH,
             );
         }
+
+        if self.config.cargo(None) != old_config.cargo(None) {
+            let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
+            self.fetch_workspaces_queue.request_op("cargo config changed".to_owned(), req)
+        }
+
+        if self.config.cfg_set_test(None) != old_config.cfg_set_test(None) {
+            let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
+            self.fetch_workspaces_queue.request_op("cfg_set_test config changed".to_owned(), req)
+        }
     }
 
     pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
index 9c0bc33af64..e7528dbc939 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs
@@ -103,6 +103,7 @@ impl CargoTestHandle {
     ) -> std::io::Result<Self> {
         let mut cmd = toolchain::command(Tool::Cargo.path(), root, &options.extra_env);
         cmd.env("RUSTC_BOOTSTRAP", "1");
+        cmd.arg("--color=always");
         cmd.arg("test");
 
         cmd.arg("--package");
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 9a292eacd7f..978c50d807b 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -13,6 +13,7 @@ pub mod panic_context;
 pub mod process;
 pub mod rand;
 pub mod thread;
+pub mod variance;
 
 pub use itertools;
 
diff --git a/src/tools/rust-analyzer/crates/stdx/src/variance.rs b/src/tools/rust-analyzer/crates/stdx/src/variance.rs
new file mode 100644
index 00000000000..8465d72bf37
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/stdx/src/variance.rs
@@ -0,0 +1,270 @@
+//! This is a copy of [`std::marker::variance`].
+
+use std::any::type_name;
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+
+macro_rules! first_token {
+    ($first:tt $($rest:tt)*) => {
+        $first
+    };
+}
+macro_rules! phantom_type {
+    ($(
+        $(#[$attr:meta])*
+        pub struct $name:ident <$t:ident> ($($inner:tt)*);
+    )*) => {$(
+        $(#[$attr])*
+        pub struct $name<$t>($($inner)*) where T: ?Sized;
+
+        impl<T> $name<T>
+            where T: ?Sized
+        {
+            /// Constructs a new instance of the variance marker.
+            pub const fn new() -> Self {
+                Self(PhantomData)
+            }
+        }
+
+        impl<T> self::sealed::Sealed for $name<T> where T: ?Sized {
+            const VALUE: Self = Self::new();
+        }
+
+        impl<T> Variance for $name<T> where T: ?Sized {}
+
+        impl<T> Default for $name<T>
+            where T: ?Sized
+        {
+            fn default() -> Self {
+                Self(PhantomData)
+            }
+        }
+
+        impl<T> fmt::Debug for $name<T>
+            where T: ?Sized
+        {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}<{}>", stringify!($name), type_name::<T>())
+            }
+        }
+
+        impl<T> Clone for $name<T>
+            where T: ?Sized
+        {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
+
+        impl<T> Copy for $name<T> where T: ?Sized {}
+
+        impl<T> PartialEq for $name<T>
+            where T: ?Sized
+        {
+            fn eq(&self, _: &Self) -> bool {
+                true
+            }
+        }
+
+        impl<T> Eq for $name<T> where T: ?Sized {}
+
+        #[allow(clippy::non_canonical_partial_ord_impl)]
+        impl<T> PartialOrd for $name<T>
+            where T: ?Sized
+        {
+            fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
+                Some(Ordering::Equal)
+            }
+        }
+
+        impl<T> Ord for $name<T>
+            where T: ?Sized
+        {
+            fn cmp(&self, _: &Self) -> Ordering {
+                Ordering::Equal
+            }
+        }
+
+        impl<T> Hash for $name<T>
+            where T: ?Sized
+        {
+            fn hash<H: Hasher>(&self, _: &mut H) {}
+        }
+    )*};
+}
+
+macro_rules! phantom_lifetime {
+    ($(
+        $(#[$attr:meta])*
+        pub struct $name:ident <$lt:lifetime> ($($inner:tt)*);
+    )*) => {$(
+        $(#[$attr])*
+
+        #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+        pub struct $name<$lt>($($inner)*);
+
+        impl $name<'_> {
+            /// Constructs a new instance of the variance marker.
+            pub const fn new() -> Self {
+                Self(first_token!($($inner)*)(PhantomData))
+            }
+        }
+
+        impl self::sealed::Sealed for $name<'_> {
+            const VALUE: Self = Self::new();
+        }
+
+        impl Variance for $name<'_> {}
+
+        impl fmt::Debug for $name<'_> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}", stringify!($name))
+            }
+        }
+    )*};
+}
+
+phantom_lifetime! {
+    /// Zero-sized type used to mark a lifetime as covariant.
+    ///
+    /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more
+    /// information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomCovariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomCovariantLifetime<'a>>() == 1`
+
+    pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>);
+    /// Zero-sized type used to mark a lifetime as contravariant.
+    ///
+    /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for
+    /// more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomContravariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomContravariantLifetime<'a>>() == 1`
+
+    pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>);
+    /// Zero-sized type used to mark a lifetime as invariant.
+    ///
+    /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer.
+    /// See [the reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `'a`, the following are guaranteed:
+    /// * `size_of::<PhantomInvariantLifetime<'a>>() == 0`
+    /// * `align_of::<PhantomInvariantLifetime<'a>>() == 1`
+
+    pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>);
+
+}
+
+phantom_type! {
+    /// Zero-sized type used to mark a type parameter as covariant.
+    ///
+    /// Types used as part of the return value from a function are covariant. If the type is _also_
+    /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for
+    /// more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomCovariant<T>>() == 0`
+    /// * `align_of::<PhantomCovariant<T>>() == 1`
+
+    pub struct PhantomCovariant<T>(PhantomData<fn() -> T>);
+    /// Zero-sized type used to mark a type parameter as contravariant.
+    ///
+    /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the
+    /// return value from a function then it is [invariant][PhantomInvariant]. See [the
+    /// reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomContravariant<T>>() == 0`
+    /// * `align_of::<PhantomContravariant<T>>() == 1`
+
+    pub struct PhantomContravariant<T>(PhantomData<fn(T)>);
+    /// Zero-sized type used to mark a type parameter as invariant.
+    ///
+    /// Types that are both passed as an argument _and_ used as part of the return value from a
+    /// function are invariant. See [the reference][1] for more information.
+    ///
+    /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance
+    ///
+    /// ## Layout
+    ///
+    /// For all `T`, the following are guaranteed:
+    /// * `size_of::<PhantomInvariant<T>>() == 0`
+    /// * `align_of::<PhantomInvariant<T>>() == 1`
+
+    pub struct PhantomInvariant<T>(PhantomData<fn(T) -> T>);
+
+}
+
+mod sealed {
+
+    pub trait Sealed {
+        const VALUE: Self;
+    }
+}
+/// A marker trait for phantom variance types.
+pub trait Variance: sealed::Sealed + Default {}
+/// Construct a variance marker; equivalent to [`Default::default`].
+///
+/// This type can be any of the following. You generally should not need to explicitly name the
+/// type, however.
+///
+/// - [`PhantomCovariant`]
+/// - [`PhantomContravariant`]
+/// - [`PhantomInvariant`]
+/// - [`PhantomCovariantLifetime`]
+/// - [`PhantomContravariantLifetime`]
+/// - [`PhantomInvariantLifetime`]
+///
+/// # Example
+///
+/// ```rust
+/// #![feature(phantom_variance_markers)]
+///
+/// use core::marker::{PhantomCovariant, variance};
+///
+/// struct BoundFn<F, P, R>
+/// where
+///     F: Fn(P) -> R,
+/// {
+///     function: F,
+///     parameter: P,
+///     return_value: PhantomCovariant<R>,
+/// }
+///
+/// let bound_fn = BoundFn {
+///     function: core::convert::identity,
+///     parameter: 5u8,
+///     return_value: variance(),
+/// };
+/// ```
+pub const fn variance<T>() -> T
+where
+    T: Variance,
+{
+    T::VALUE
+}
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 fab4cb287c3..955aadaa25d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -134,6 +134,13 @@ pub fn name_ref(name_ref: &str) -> ast::NameRef {
         }
     }
 }
+pub fn name_ref_self_ty() -> ast::NameRef {
+    quote! {
+        NameRef {
+            [Self]
+        }
+    }
+}
 fn raw_ident_esc(ident: &str) -> &'static str {
     if is_raw_identifier(ident, Edition::CURRENT) { "r#" } else { "" }
 }
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 7240069753e..1d821e96e55 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -412,22 +412,36 @@ impl MiniCore {
         }
 
         let mut active_regions = Vec::new();
+        let mut inactive_regions = Vec::new();
         let mut seen_regions = Vec::new();
         for line in lines {
             let trimmed = line.trim();
             if let Some(region) = trimmed.strip_prefix("// region:") {
-                active_regions.push(region);
-                continue;
+                if let Some(region) = region.strip_prefix('!') {
+                    inactive_regions.push(region);
+                    continue;
+                } else {
+                    active_regions.push(region);
+                    continue;
+                }
             }
             if let Some(region) = trimmed.strip_prefix("// endregion:") {
-                let prev = active_regions.pop().unwrap();
+                let (prev, region) = if let Some(region) = region.strip_prefix('!') {
+                    (inactive_regions.pop().unwrap(), region)
+                } else {
+                    (active_regions.pop().unwrap(), region)
+                };
                 assert_eq!(prev, region, "unbalanced region pairs");
                 continue;
             }
 
-            let mut line_region = false;
-            if let Some(idx) = trimmed.find("// :") {
-                line_region = true;
+            let mut active_line_region = false;
+            let mut inactive_line_region = false;
+            if let Some(idx) = trimmed.find("// :!") {
+                inactive_line_region = true;
+                inactive_regions.push(&trimmed[idx + "// :!".len()..]);
+            } else if let Some(idx) = trimmed.find("// :") {
+                active_line_region = true;
                 active_regions.push(&trimmed[idx + "// :".len()..]);
             }
 
@@ -438,18 +452,30 @@ impl MiniCore {
                 seen_regions.push(region);
                 keep &= self.has_flag(region);
             }
+            for &region in &inactive_regions {
+                assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}");
+                self.assert_valid_flag(region);
+                seen_regions.push(region);
+                keep &= !self.has_flag(region);
+            }
 
             if keep {
                 buf.push_str(line);
             }
-            if line_region {
+            if active_line_region {
                 active_regions.pop().unwrap();
             }
+            if inactive_line_region {
+                inactive_regions.pop().unwrap();
+            }
         }
 
         if !active_regions.is_empty() {
             panic!("unclosed regions: {active_regions:?} Add an `endregion` comment");
         }
+        if !inactive_regions.is_empty() {
+            panic!("unclosed regions: {inactive_regions:?} Add an `endregion` comment");
+        }
 
         for flag in &self.valid_flags {
             if !seen_regions.iter().any(|it| it == flag) {
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 4bdd791eb16..d13a81d287f 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -31,6 +31,7 @@
 //!     eq: sized
 //!     error: fmt
 //!     fmt: option, result, transmute, coerce_unsized, copy, clone, derive
+//!     fmt_before_1_89_0: fmt
 //!     fn: tuple
 //!     from: sized, result
 //!     future: pin
@@ -1175,6 +1176,7 @@ pub mod fmt {
             }
         }
 
+        // region:fmt_before_1_89_0
         #[lang = "format_unsafe_arg"]
         pub struct UnsafeArg {
             _private: (),
@@ -1185,6 +1187,7 @@ pub mod fmt {
                 UnsafeArg { _private: () }
             }
         }
+        // endregion:fmt_before_1_89_0
     }
 
     #[derive(Copy, Clone)]
@@ -1204,6 +1207,7 @@ pub mod fmt {
             Arguments { pieces, fmt: None, args: &[] }
         }
 
+        // region:fmt_before_1_89_0
         pub fn new_v1_formatted(
             pieces: &'a [&'static str],
             args: &'a [rt::Argument<'a>],
@@ -1212,6 +1216,17 @@ pub mod fmt {
         ) -> Arguments<'a> {
             Arguments { pieces, fmt: Some(fmt), args }
         }
+        // endregion:fmt_before_1_89_0
+
+        // region:!fmt_before_1_89_0
+        pub unsafe fn new_v1_formatted(
+            pieces: &'a [&'static str],
+            args: &'a [rt::Argument<'a>],
+            fmt: &'a [rt::Placeholder],
+        ) -> Arguments<'a> {
+            Arguments { pieces, fmt: Some(fmt), args }
+        }
+        // endregion:!fmt_before_1_89_0
 
         pub const fn as_str(&self) -> Option<&'static str> {
             match (self.pieces, self.args) {
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 4eb9cfc4e5b..9404b1454a0 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -13,6 +13,13 @@ Default: `"todo"`
 Placeholder expression to use for missing expressions in assists.
 
 
+## rust-analyzer.assist.preferSelf {#assist.preferSelf}
+
+Default: `false`
+
+When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible.
+
+
 ## rust-analyzer.assist.termSearch.borrowcheck {#assist.termSearch.borrowcheck}
 
 Default: `true`
@@ -1535,7 +1542,11 @@ https://github.com/facebook/buck2/tree/main/integrations/rust-project.
 
 Default: `false`
 
-Exclude imports from symbol search.
+Exclude all imports from workspace symbol search.
+
+In addition to regular imports (which are always excluded),
+this option removes public imports (better known as re-exports)
+and removes imports that rename the imported symbol.
 
 
 ## rust-analyzer.workspace.symbol.search.kind {#workspace.symbol.search.kind}
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index dcdb4fe30ee..26a21c1468d 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -683,6 +683,16 @@
             {
                 "title": "assist",
                 "properties": {
+                    "rust-analyzer.assist.preferSelf": {
+                        "markdownDescription": "When inserting a type (e.g. in \"fill match arms\" assist), prefer to use `Self` over the type name where possible.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "assist",
+                "properties": {
                     "rust-analyzer.assist.termSearch.borrowcheck": {
                         "markdownDescription": "Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.",
                         "default": true,
@@ -2895,7 +2905,7 @@
                 "title": "workspace",
                 "properties": {
                     "rust-analyzer.workspace.symbol.search.excludeImports": {
-                        "markdownDescription": "Exclude imports from symbol search.",
+                        "markdownDescription": "Exclude all imports from workspace symbol search.\n\nIn addition to regular imports (which are always excluded),\nthis option removes public imports (better known as re-exports)\nand removes imports that rename the imported symbol.",
                         "default": false,
                         "type": "boolean"
                     }
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index f36e18a73da..d2dc740c09b 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -20,15 +20,9 @@ export class Config {
     configureLang: vscode.Disposable | undefined;
 
     readonly rootSection = "rust-analyzer";
-    private readonly requiresServerReloadOpts = [
-        "cargo",
-        "procMacro",
-        "serverPath",
-        "server",
-        "files",
-        "cfg",
-        "showSyntaxTree",
-    ].map((opt) => `${this.rootSection}.${opt}`);
+    private readonly requiresServerReloadOpts = ["server", "files", "showSyntaxTree"].map(
+        (opt) => `${this.rootSection}.${opt}`,
+    );
 
     private readonly requiresWindowReloadOpts = ["testExplorer"].map(
         (opt) => `${this.rootSection}.${opt}`,
@@ -208,7 +202,7 @@ export class Config {
     }
 
     get serverPath() {
-        return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
+        return this.get<null | string>("server.path");
     }
 
     get serverExtraEnv(): Env {
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index af0dd5c9acd..a454087b0cd 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-7c10378e1fee5ddc6573b916aeb884ab10e0de17
+27733d46d79f4eb92e240fbba502c43022665735
diff --git a/src/tools/rust-installer/install-template.sh b/src/tools/rust-installer/install-template.sh
index f7f408be882..337aaa95b9a 100644
--- a/src/tools/rust-installer/install-template.sh
+++ b/src/tools/rust-installer/install-template.sh
@@ -160,7 +160,7 @@ valopt() {
     local doc="$*"
     if [ $HELP -eq 0 ]
     then
-        local uop=$(echo $op | tr 'a-z-' 'A-Z_')
+        local uop=$(echo $op | tr '[a-z]-' '[A-Z]_')
         local v="CFG_${uop}"
         eval $v="$default"
         for arg in $CFG_ARGS
@@ -206,8 +206,8 @@ opt() {
         do
             if [ "$arg" = "--${flag}-${op}" ]
             then
-                op=$(echo $op | tr 'a-z-' 'A-Z_')
-                flag=$(echo $flag | tr 'a-z' 'A-Z')
+                op=$(echo $op | tr '[a-z]-' '[A-Z]_')
+                flag=$(echo $flag | tr '[a-z]' '[A-Z]')
                 local v="CFG_${flag}_${op}"
                 eval $v=1
                 putvar $v
@@ -235,7 +235,7 @@ flag() {
         do
             if [ "$arg" = "--${op}" ]
             then
-                op=$(echo $op | tr 'a-z-' 'A-Z_')
+                op=$(echo $op | tr '[a-z]-' '[A-Z]_')
                 local v="CFG_${op}"
                 eval $v=1
                 putvar $v
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index be6b483bfff..08aedff2b20 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -2289,8 +2289,10 @@ fn rewrite_expr_addrof(
 ) -> RewriteResult {
     let operator_str = match (mutability, borrow_kind) {
         (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
+        (ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
         (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
         (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
+        (ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
         (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
     };
     rewrite_unary_prefix(context, operator_str, expr, shape)
diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs
index 370dfbc196a..e5b47339b92 100644
--- a/src/tools/rustfmt/tests/source/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/source/pin_sugar.rs
@@ -18,3 +18,13 @@ impl Foo {
 mut self) {}
     fn i(&pin      mut   self) {}
 }
+
+fn borrows() {
+    let mut foo = 0_i32;
+    let x: Pin<&mut _> = & pin 
+    mut    foo;
+
+    let x: Pin<&_> = &
+    pin                const 
+    foo;
+}
diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs
index 7d04efb1b32..09ad23a5807 100644
--- a/src/tools/rustfmt/tests/target/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/target/pin_sugar.rs
@@ -16,3 +16,10 @@ impl Foo {
     fn h<'a>(&'a pin mut self) {}
     fn i(&pin mut self) {}
 }
+
+fn borrows() {
+    let mut foo = 0_i32;
+    let x: Pin<&mut _> = &pin mut foo;
+
+    let x: Pin<&_> = &pin const foo;
+}
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 716d42c32eb..4e0bbcd7c6c 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -206,6 +206,7 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
     ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
     ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"),
+    ("wasmtime-math", "Apache-2.0 WITH LLVM-exception"),
     // tidy-alphabetical-end
 ];
 
@@ -537,6 +538,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "indexmap",
     "libc",
     "libloading",
+    "libm",
     "log",
     "mach2",
     "memchr",
@@ -554,6 +556,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "target-lexicon",
     "unicode-ident",
     "wasmtime-jit-icache-coherence",
+    "wasmtime-math",
     "windows-sys",
     "windows-targets",
     "windows_aarch64_gnullvm",
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index e2d1b85797f..bb61412f678 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -43,9 +43,18 @@ macro_rules! verbose_print {
     };
 }
 
-pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut bool) {
+pub fn check(
+    root_path: &Path,
+    search_paths: &[&Path],
+    verbose: bool,
+    ci_info: &crate::CiInfo,
+    bad: &mut bool,
+) {
     let mut errors = Vec::new();
 
+    // Check that no error code explanation was removed.
+    check_removed_error_code_explanation(ci_info, bad);
+
     // Stage 1: create list
     let error_codes = extract_error_codes(root_path, &mut errors);
     if verbose {
@@ -68,6 +77,27 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
     }
 }
 
+fn check_removed_error_code_explanation(ci_info: &crate::CiInfo, bad: &mut bool) {
+    let Some(base_commit) = &ci_info.base_commit else {
+        eprintln!("Skipping error code explanation removal check");
+        return;
+    };
+    let Some(diff) = crate::git_diff(base_commit, "--name-status") else {
+        *bad = true;
+        eprintln!("removed error code explanation tidy check: Failed to run git diff");
+        return;
+    };
+    if diff.lines().any(|line| {
+        line.starts_with('D') && line.contains("compiler/rustc_error_codes/src/error_codes/")
+    }) {
+        *bad = true;
+        eprintln!("tidy check error: Error code explanations should never be removed!");
+        eprintln!("Take a look at E0001 to see how to handle it.");
+        return;
+    }
+    println!("No error code explanation was removed!");
+}
+
 /// Stage 1: Parses a list of error codes from `error_codes.rs`.
 fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String> {
     let path = root_path.join(Path::new(ERROR_CODES_PATH));
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index b3517b2e9da..24356c31da4 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2070,7 +2070,6 @@ ui/issues/issue-32782.rs
 ui/issues/issue-32797.rs
 ui/issues/issue-32805.rs
 ui/issues/issue-3290.rs
-ui/issues/issue-32950.rs
 ui/issues/issue-32995-2.rs
 ui/issues/issue-32995.rs
 ui/issues/issue-33202.rs
@@ -2340,7 +2339,6 @@ ui/issues/issue-49934.rs
 ui/issues/issue-49955.rs
 ui/issues/issue-49973.rs
 ui/issues/issue-50187.rs
-ui/issues/issue-50403.rs
 ui/issues/issue-50411.rs
 ui/issues/issue-50415.rs
 ui/issues/issue-50442.rs
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 28aa80225b1..237737f0f16 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -3,6 +3,12 @@
 //! This library contains the tidy lints and exposes it
 //! to be used by tools.
 
+use std::ffi::OsStr;
+use std::process::Command;
+
+use build_helper::ci::CiEnv;
+use build_helper::git::{GitConfig, get_closest_upstream_commit};
+use build_helper::stage0_parser::{Stage0Config, parse_stage0_file};
 use termcolor::WriteColor;
 
 macro_rules! static_regex {
@@ -63,6 +69,61 @@ fn tidy_error(args: &str) -> std::io::Result<()> {
     Ok(())
 }
 
+pub struct CiInfo {
+    pub git_merge_commit_email: String,
+    pub nightly_branch: String,
+    pub base_commit: Option<String>,
+    pub ci_env: CiEnv,
+}
+
+impl CiInfo {
+    pub fn new(bad: &mut bool) -> Self {
+        let stage0 = parse_stage0_file();
+        let Stage0Config { nightly_branch, git_merge_commit_email, .. } = stage0.config;
+
+        let mut info = Self {
+            nightly_branch,
+            git_merge_commit_email,
+            ci_env: CiEnv::current(),
+            base_commit: None,
+        };
+        let base_commit = match get_closest_upstream_commit(None, &info.git_config(), info.ci_env) {
+            Ok(Some(commit)) => Some(commit),
+            Ok(None) => {
+                info.error_if_in_ci("no base commit found", bad);
+                None
+            }
+            Err(error) => {
+                info.error_if_in_ci(&format!("failed to retrieve base commit: {error}"), bad);
+                None
+            }
+        };
+        info.base_commit = base_commit;
+        info
+    }
+
+    pub fn git_config(&self) -> GitConfig<'_> {
+        GitConfig {
+            nightly_branch: &self.nightly_branch,
+            git_merge_commit_email: &self.git_merge_commit_email,
+        }
+    }
+
+    pub fn error_if_in_ci(&self, msg: &str, bad: &mut bool) {
+        if self.ci_env.is_running_in_ci() {
+            *bad = true;
+            eprintln!("tidy check error: {msg}");
+        } else {
+            eprintln!("tidy check warning: {msg}. Some checks will be skipped.");
+        }
+    }
+}
+
+pub fn git_diff<S: AsRef<OsStr>>(base_commit: &str, extra_arg: S) -> Option<String> {
+    let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?;
+    Some(String::from_utf8_lossy(&output.stdout).into())
+}
+
 pub mod alphabetical;
 pub mod bins;
 pub mod debug_artifacts;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 0b66017b865..ef6ff5c9277 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -48,7 +48,9 @@ fn main() {
     let extra_checks =
         cfg_args.iter().find(|s| s.starts_with("--extra-checks=")).map(String::as_str);
 
-    let bad = std::sync::Arc::new(AtomicBool::new(false));
+    let mut bad = false;
+    let ci_info = CiInfo::new(&mut bad);
+    let bad = std::sync::Arc::new(AtomicBool::new(bad));
 
     let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
         // poll all threads for completion before awaiting the oldest one
@@ -110,12 +112,12 @@ fn main() {
         check!(rustdoc_css_themes, &librustdoc_path);
         check!(rustdoc_templates, &librustdoc_path);
         check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path);
-        check!(rustdoc_json, &src_path);
+        check!(rustdoc_json, &src_path, &ci_info);
         check!(known_bug, &crashes_path);
         check!(unknown_revision, &tests_path);
 
         // Checks that only make sense for the compiler.
-        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
+        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info);
         check!(fluent_alphabetical, &compiler_path, bless);
         check!(fluent_period, &compiler_path);
         check!(target_policy, &root_path);
diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs
index 2377356e14d..dfbb35d69f1 100644
--- a/src/tools/tidy/src/rustdoc_json.rs
+++ b/src/tools/tidy/src/rustdoc_json.rs
@@ -1,56 +1,20 @@
 //! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was
 //! updated as well.
 
-use std::ffi::OsStr;
 use std::path::Path;
-use std::process::Command;
 use std::str::FromStr;
 
-use build_helper::ci::CiEnv;
-use build_helper::git::{GitConfig, get_closest_upstream_commit};
-use build_helper::stage0_parser::parse_stage0_file;
-
 const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types";
 
-fn git_diff<S: AsRef<OsStr>>(base_commit: &str, extra_arg: S) -> Option<String> {
-    let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?;
-    Some(String::from_utf8_lossy(&output.stdout).into())
-}
-
-fn error_if_in_ci(ci_env: CiEnv, msg: &str, bad: &mut bool) {
-    if ci_env.is_running_in_ci() {
-        *bad = true;
-        eprintln!("error in `rustdoc_json` tidy check: {msg}");
-    } else {
-        eprintln!("{msg}. Skipping `rustdoc_json` tidy check");
-    }
-}
-
-pub fn check(src_path: &Path, bad: &mut bool) {
+pub fn check(src_path: &Path, ci_info: &crate::CiInfo, bad: &mut bool) {
     println!("Checking tidy rustdoc_json...");
-    let stage0 = parse_stage0_file();
-    let ci_env = CiEnv::current();
-    let base_commit = match get_closest_upstream_commit(
-        None,
-        &GitConfig {
-            nightly_branch: &stage0.config.nightly_branch,
-            git_merge_commit_email: &stage0.config.git_merge_commit_email,
-        },
-        ci_env,
-    ) {
-        Ok(Some(commit)) => commit,
-        Ok(None) => {
-            error_if_in_ci(ci_env, "no base commit found", bad);
-            return;
-        }
-        Err(error) => {
-            error_if_in_ci(ci_env, &format!("failed to retrieve base commit: {error}"), bad);
-            return;
-        }
+    let Some(base_commit) = &ci_info.base_commit else {
+        eprintln!("No base commit, skipping rustdoc_json check");
+        return;
     };
 
     // First we check that `src/rustdoc-json-types` was modified.
-    match git_diff(&base_commit, "--name-status") {
+    match crate::git_diff(&base_commit, "--name-status") {
         Some(output) => {
             if !output
                 .lines()
@@ -68,7 +32,7 @@ pub fn check(src_path: &Path, bad: &mut bool) {
         }
     }
     // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated.
-    match git_diff(&base_commit, src_path.join("rustdoc-json-types")) {
+    match crate::git_diff(&base_commit, src_path.join("rustdoc-json-types")) {
         Some(output) => {
             let mut format_version_updated = false;
             let mut latest_feature_comment_updated = false;
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 8f9b07c49ac..53226fcb80e 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1623;
+const ISSUES_ENTRY_LIMIT: u32 = 1619;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index db11549382f..3e9841b179c 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -16,6 +16,7 @@
 
 #![feature(
     no_core,
+    intrinsics,
     lang_items,
     auto_traits,
     freeze_impls,
@@ -196,3 +197,9 @@ impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a
 trait Drop {
     fn drop(&mut self);
 }
+
+pub mod mem {
+    #[rustc_nounwind]
+    #[rustc_intrinsic]
+    pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst;
+}
diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs
index 75f845572a4..78989ec5df2 100644
--- a/tests/codegen/min-function-alignment.rs
+++ b/tests/codegen/min-function-alignment.rs
@@ -1,17 +1,19 @@
 //@ revisions: align16 align1024
-//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0
+//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code
 //@ [align16] compile-flags: -Zmin-function-alignment=16
 //@ [align1024] compile-flags: -Zmin-function-alignment=1024
 
 #![crate_type = "lib"]
 #![feature(fn_align)]
 
-// functions without explicit alignment use the global minimum
+// Functions without explicit alignment use the global minimum.
 //
-// CHECK-LABEL: @no_explicit_align
+// NOTE: this function deliberately has zero (0) attributes! That is to make sure that
+// `-Zmin-function-alignment` is applied regardless of whether attributes are used.
+//
+// CHECK-LABEL: no_explicit_align
 // align16: align 16
 // align1024: align 1024
-#[no_mangle]
 pub fn no_explicit_align() {}
 
 // CHECK-LABEL: @lower_align
diff --git a/tests/crashes/132430.rs b/tests/crashes/132430.rs
deleted file mode 100644
index 81c8c6d6f7d..00000000000
--- a/tests/crashes/132430.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ known-bug: #132430
-
-//@ compile-flags: --crate-type=lib
-//@ edition: 2018
-#![feature(cmse_nonsecure_entry)]
-struct Test;
-
-impl Test {
-    pub async unsafe extern "C-cmse-nonsecure-entry" fn test(val: &str) {}
-}
diff --git a/tests/crashes/138738.rs b/tests/crashes/138738.rs
deleted file mode 100644
index 74e5effa56f..00000000000
--- a/tests/crashes/138738.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ known-bug: #138738
-//@ only-x86_64
-
-#![feature(abi_ptx)]
-fn main() {
-    let a = unsafe { core::mem::transmute::<usize, extern "ptx-kernel" fn(i32)>(4) }(2);
-}
diff --git a/tests/incremental/issue-61323.rs b/tests/incremental/issue-61323.rs
index b7423c81fc1..4845648d49c 100644
--- a/tests/incremental/issue-61323.rs
+++ b/tests/incremental/issue-61323.rs
@@ -1,7 +1,7 @@
 //@ revisions: rpass cfail
 
 enum A {
-    //[cfail]~^ ERROR 3:1: 3:7: recursive types `A` and `C` have infinite size [E0072]
+    //[cfail]~^ ERROR recursive types `A` and `C` have infinite size [E0072]
     B(C),
 }
 
diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp
new file mode 100644
index 00000000000..212e0e174da
--- /dev/null
+++ b/tests/pretty/pin-ergonomics-hir.pp
@@ -0,0 +1,44 @@
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:pin-ergonomics-hir.pp
+
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn baz(&mut self) { }
+
+    fn baz_const(&self) { }
+
+    fn baz_lt<'a>(&mut self) { }
+
+    fn baz_const_lt(&self) { }
+}
+
+fn foo(_: Pin<&'_ mut Foo>) { }
+fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
+
+fn foo_const(_: Pin<&'_ Foo>) { }
+fn foo_const_lt(_: Pin<&'_ Foo>) { }
+
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_const(x);
+    foo_const(x);
+}
+
+fn main() { }
diff --git a/tests/pretty/pin-ergonomics-hir.rs b/tests/pretty/pin-ergonomics-hir.rs
new file mode 100644
index 00000000000..5f2158258f0
--- /dev/null
+++ b/tests/pretty/pin-ergonomics-hir.rs
@@ -0,0 +1,40 @@
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:pin-ergonomics-hir.pp
+
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn baz(&mut self) { }
+
+    fn baz_const(&self) { }
+
+    fn baz_lt<'a>(&mut self) { }
+
+    fn baz_const_lt(&self) { }
+}
+
+fn foo(_: Pin<&'_ mut Foo>) { }
+fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
+
+fn foo_const(_: Pin<&'_ Foo>) { }
+fn foo_const_lt(_: Pin<&'_ Foo>) { }
+
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_const(x);
+    foo_const(x);
+}
+
+fn main() { }
diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs
index 47ffc97b118..8e8ced791b1 100644
--- a/tests/pretty/pin-ergonomics.rs
+++ b/tests/pretty/pin-ergonomics.rs
@@ -3,6 +3,8 @@
 #![feature(pin_ergonomics)]
 #![allow(dead_code, incomplete_features)]
 
+use std::pin::Pin;
+
 struct Foo;
 
 impl Foo {
@@ -21,4 +23,15 @@ fn foo_lt<'a>(_: &'a pin mut Foo) {}
 fn foo_const(_: &pin const Foo) {}
 fn foo_const_lt(_: &'_ pin const Foo) {}
 
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x);
+
+    let x: Pin<&_> = &pin const Foo;
+    foo_const(x);
+    foo_const(x);
+}
+
 fn main() {}
diff --git a/tests/run-make/arm64ec-import-export-static/export.rs b/tests/run-make/arm64ec-import-export-static/export.rs
new file mode 100644
index 00000000000..ca6ccf00ca1
--- /dev/null
+++ b/tests/run-make/arm64ec-import-export-static/export.rs
@@ -0,0 +1,27 @@
+#![crate_type = "dylib"]
+#![allow(internal_features)]
+#![feature(no_core, lang_items)]
+#![no_core]
+#![no_std]
+
+// This is needed because of #![no_core]:
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+#[lang = "sync"]
+trait Sync {}
+impl Sync for i32 {}
+#[lang = "copy"]
+pub trait Copy {}
+impl Copy for i32 {}
+#[lang = "drop_in_place"]
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
+#[no_mangle]
+extern "system" fn _DllMainCRTStartup(_: *const u8, _: u32, _: *const u8) -> u32 {
+    1
+}
+
+pub static VALUE: i32 = 42;
diff --git a/tests/run-make/arm64ec-import-export-static/import.rs b/tests/run-make/arm64ec-import-export-static/import.rs
new file mode 100644
index 00000000000..9d52db25125
--- /dev/null
+++ b/tests/run-make/arm64ec-import-export-static/import.rs
@@ -0,0 +1,12 @@
+#![crate_type = "cdylib"]
+#![allow(internal_features)]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+extern crate export;
+
+#[no_mangle]
+pub extern "C" fn func() -> i32 {
+    export::VALUE
+}
diff --git a/tests/run-make/arm64ec-import-export-static/rmake.rs b/tests/run-make/arm64ec-import-export-static/rmake.rs
new file mode 100644
index 00000000000..7fa31144810
--- /dev/null
+++ b/tests/run-make/arm64ec-import-export-static/rmake.rs
@@ -0,0 +1,15 @@
+// Test that a static can be exported from one crate and imported into another.
+//
+// This was broken for Arm64EC as only functions, not variables, should be
+// decorated with `#`.
+// See https://github.com/rust-lang/rust/issues/138541
+
+//@ needs-llvm-components: aarch64
+//@ only-windows
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc().input("export.rs").target("aarch64-pc-windows-msvc").panic("abort").run();
+    rustc().input("import.rs").target("aarch64-pc-windows-msvc").panic("abort").run();
+}
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
index 426d65b7af3..cca528c4252 100644
--- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
+++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
@@ -5,6 +5,7 @@
 
 //@ needs-target-std
 //@ ignore-android: FIXME(#142855)
+//@ ignore-sgx: (x86 machine code cannot be directly executed)
 
 use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name};
 
diff --git a/tests/run-make/reproducible-build-2/rmake.rs b/tests/run-make/reproducible-build-2/rmake.rs
index 5971fa01f92..1de5ca1e6f7 100644
--- a/tests/run-make/reproducible-build-2/rmake.rs
+++ b/tests/run-make/reproducible-build-2/rmake.rs
@@ -7,22 +7,36 @@
 // See https://github.com/rust-lang/rust/issues/34902
 
 //@ ignore-cross-compile
-//@ ignore-windows
-// Reasons:
-// 1. The object files are reproducible, but their paths are not, which causes
-// the first assertion in the test to fail.
-// 2. When the sysroot gets copied, some symlinks must be re-created,
-// which is a privileged action on Windows.
 
-use run_make_support::{rfs, rust_lib_name, rustc};
+//@ ignore-windows-gnu
+// GNU Linker for Windows is non-deterministic.
+
+use run_make_support::{bin_name, is_windows_msvc, rfs, rust_lib_name, rustc};
 
 fn main() {
     // test 1: fat lto
     rustc().input("reproducible-build-aux.rs").run();
-    rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
-    rfs::rename("reproducible-build", "reproducible-build-a");
-    rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
-    assert_eq!(rfs::read("reproducible-build"), rfs::read("reproducible-build-a"));
+    let make_reproducible_build = || {
+        let mut reproducible_build = rustc();
+        reproducible_build
+            .input("reproducible-build.rs")
+            .arg("-Clto=fat")
+            .output(bin_name("reproducible-build"));
+        if is_windows_msvc() {
+            // Avoids timestamps, etc. when linking.
+            reproducible_build.arg("-Clink-arg=/Brepro");
+        }
+        reproducible_build.run();
+    };
+    make_reproducible_build();
+    rfs::rename(bin_name("reproducible-build"), "reproducible-build-a");
+    if is_windows_msvc() {
+        // Linker acts differently if there is already a PDB file with the same
+        // name.
+        rfs::remove_file("reproducible-build.pdb");
+    }
+    make_reproducible_build();
+    assert_eq!(rfs::read(bin_name("reproducible-build")), rfs::read("reproducible-build-a"));
 
     // test 2: sysroot
     let sysroot = rustc().print("sysroot").run().stdout_utf8();
diff --git a/tests/run-make/sanitizer-dylib-link/program.rs b/tests/run-make/sanitizer-dylib-link/program.rs
index 1026c7f89ba..dbf885d343f 100644
--- a/tests/run-make/sanitizer-dylib-link/program.rs
+++ b/tests/run-make/sanitizer-dylib-link/program.rs
@@ -1,4 +1,4 @@
-#[cfg_attr(windows, link(name = "library.dll.lib", modifiers = "+verbatim"))]
+#[cfg_attr(windows, link(name = "library", kind = "raw-dylib"))]
 #[cfg_attr(not(windows), link(name = "library"))]
 extern "C" {
     fn overflow();
diff --git a/tests/rustdoc-js/big-result.rs b/tests/rustdoc-js/big-result.rs
index 4dfecd6aaad..c7a52aac1a2 100644
--- a/tests/rustdoc-js/big-result.rs
+++ b/tests/rustdoc-js/big-result.rs
@@ -1,4 +1,3 @@
-#![feature(concat_idents)]
 #![allow(nonstandard_style)]
 /// Generate 250 items that all match the query, starting with the longest.
 /// Those long items should be dropped from the result set, and the short ones
diff --git a/tests/rustdoc-json/attrs/cold.rs b/tests/rustdoc-json/attrs/cold.rs
new file mode 100644
index 00000000000..e219345d669
--- /dev/null
+++ b/tests/rustdoc-json/attrs/cold.rs
@@ -0,0 +1,3 @@
+//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]'
+#[cold]
+pub fn cold_fn() {}
diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs
new file mode 100644
index 00000000000..0bed0ad18c3
--- /dev/null
+++ b/tests/rustdoc-json/attrs/optimize.rs
@@ -0,0 +1,13 @@
+#![feature(optimize_attribute)]
+
+//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]'
+#[optimize(speed)]
+pub fn speed() {}
+
+//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]'
+#[optimize(size)]
+pub fn size() {}
+
+//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]'
+#[optimize(none)]
+pub fn none() {}
diff --git a/tests/rustdoc-json/generic-args.rs b/tests/rustdoc-json/generic-args.rs
index 0f588820da7..b4a73a046b5 100644
--- a/tests/rustdoc-json/generic-args.rs
+++ b/tests/rustdoc-json/generic-args.rs
@@ -17,4 +17,7 @@ pub fn my_fn1(_: <MyStruct as MyTrait>::MyType) {}
 //@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" null
 pub fn my_fn2(_: IntoIterator<Item = MyStruct, IntoIter = impl Clone>) {}
 
+//@ is "$.index[?(@.name=='my_fn3')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.args.parenthesized.inputs" []
+pub fn my_fn3(f: impl FnMut()) {}
+
 fn main() {}
diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs
index fa651baa7bc..87504b8301f 100644
--- a/tests/ui-fulldeps/run-compiler-twice.rs
+++ b/tests/ui-fulldeps/run-compiler-twice.rs
@@ -18,7 +18,7 @@ extern crate rustc_span;
 use std::path::{Path, PathBuf};
 
 use rustc_interface::{Linker, interface};
-use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes};
+use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes, Sysroot};
 use rustc_span::FileName;
 
 fn main() {
@@ -32,7 +32,7 @@ fn main() {
         panic!("expected sysroot (and optional linker)");
     }
 
-    let sysroot = PathBuf::from(&args[1]);
+    let sysroot = Sysroot::new(Some(PathBuf::from(&args[1])));
     let linker = args.get(2).map(PathBuf::from);
 
     // compiletest sets the current dir to `output_base_dir` when running.
@@ -43,7 +43,7 @@ fn main() {
     compile(src.to_string(), tmpdir.join("out"), sysroot.clone(), linker.as_deref());
 }
 
-fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path>) {
+fn compile(code: String, output: PathBuf, sysroot: Sysroot, linker: Option<&Path>) {
     let mut opts = Options::default();
     opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
     opts.sysroot = sysroot;
diff --git a/tests/ui/abi/cannot-be-called.avr.stderr b/tests/ui/abi/cannot-be-called.avr.stderr
index 64ce3efe52b..a0f7f18f701 100644
--- a/tests/ui/abi/cannot-be-called.avr.stderr
+++ b/tests/ui/abi/cannot-be-called.avr.stderr
@@ -1,132 +1,75 @@
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:38:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "msp430-interrupt" fn msp430() {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:42:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-m" fn riscv_m() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:44:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-s" fn riscv_s() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:46:8
    |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" fn x86() {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:36:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:65:25
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
+   |                         ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:40:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:77:26
    |
-LL | extern "riscv-interrupt-m" fn riscv_m() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:42:1
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:83:26
    |
-LL | extern "riscv-interrupt-s" fn riscv_s() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:44:1
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:89:22
    |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
 error: functions with the "avr-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:50:5
+  --> $DIR/cannot-be-called.rs:53:5
    |
 LL |     avr();
    |     ^^^^^
    |
 note: an `extern "avr-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:50:5
+  --> $DIR/cannot-be-called.rs:53:5
    |
 LL |     avr();
    |     ^^^^^
 
 error: functions with the "avr-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:70:5
+  --> $DIR/cannot-be-called.rs:73:5
    |
 LL |     f()
    |     ^^^
    |
 note: an `extern "avr-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:70:5
+  --> $DIR/cannot-be-called.rs:73:5
    |
 LL |     f()
    |     ^^^
 
-error: aborting due to 6 previous errors; 4 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/cannot-be-called.i686.stderr b/tests/ui/abi/cannot-be-called.i686.stderr
index 113b40eb67b..f59fdba2f35 100644
--- a/tests/ui/abi/cannot-be-called.i686.stderr
+++ b/tests/ui/abi/cannot-be-called.i686.stderr
@@ -1,72 +1,59 @@
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:38:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "msp430-interrupt" fn msp430() {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:40:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "avr-interrupt" fn avr() {}
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:42:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-m" fn riscv_m() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:44:8
    |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-s" fn riscv_s() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:36:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:65:25
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
+   |                         ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:38:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:71:22
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:40:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:77:26
    |
-LL | extern "riscv-interrupt-m" fn riscv_m() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:42:1
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:83:26
    |
-LL | extern "riscv-interrupt-s" fn riscv_s() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
 error: functions with the "x86-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:56:5
+  --> $DIR/cannot-be-called.rs:59:5
    |
 LL |     x86();
    |     ^^^^^
    |
 note: an `extern "x86-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:56:5
+  --> $DIR/cannot-be-called.rs:59:5
    |
 LL |     x86();
    |     ^^^^^
@@ -83,50 +70,6 @@ note: an `extern "x86-interrupt"` function can only be called using inline assem
 LL |     f()
    |     ^^^
 
-error: aborting due to 6 previous errors; 4 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/cannot-be-called.msp430.stderr b/tests/ui/abi/cannot-be-called.msp430.stderr
index d7630d96f8c..fa339f0dd2a 100644
--- a/tests/ui/abi/cannot-be-called.msp430.stderr
+++ b/tests/ui/abi/cannot-be-called.msp430.stderr
@@ -1,132 +1,75 @@
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:40:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "avr-interrupt" fn avr() {}
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:42:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-m" fn riscv_m() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:44:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-s" fn riscv_s() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:46:8
    |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" fn x86() {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:38:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:71:22
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:40:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:77:26
    |
-LL | extern "riscv-interrupt-m" fn riscv_m() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:42:1
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:83:26
    |
-LL | extern "riscv-interrupt-s" fn riscv_s() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:44:1
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:89:22
    |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
 error: functions with the "msp430-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:48:5
+  --> $DIR/cannot-be-called.rs:51:5
    |
 LL |     msp430();
    |     ^^^^^^^^
    |
 note: an `extern "msp430-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:48:5
+  --> $DIR/cannot-be-called.rs:51:5
    |
 LL |     msp430();
    |     ^^^^^^^^
 
 error: functions with the "msp430-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:63:5
+  --> $DIR/cannot-be-called.rs:67:5
    |
 LL |     f()
    |     ^^^
    |
 note: an `extern "msp430-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:63:5
+  --> $DIR/cannot-be-called.rs:67:5
    |
 LL |     f()
    |     ^^^
 
-error: aborting due to 6 previous errors; 4 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/cannot-be-called.riscv32.stderr b/tests/ui/abi/cannot-be-called.riscv32.stderr
index 9fadbd639b8..040b60c7657 100644
--- a/tests/ui/abi/cannot-be-called.riscv32.stderr
+++ b/tests/ui/abi/cannot-be-called.riscv32.stderr
@@ -1,130 +1,87 @@
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:38:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "msp430-interrupt" fn msp430() {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:40:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "avr-interrupt" fn avr() {}
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:46:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" fn x86() {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:36:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:65:25
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
+   |                         ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:38:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:71:22
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:44:1
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:89:22
    |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
 error: functions with the "riscv-interrupt-m" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:52:5
+  --> $DIR/cannot-be-called.rs:55:5
    |
 LL |     riscv_m();
    |     ^^^^^^^^^
    |
 note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:52:5
+  --> $DIR/cannot-be-called.rs:55:5
    |
 LL |     riscv_m();
    |     ^^^^^^^^^
 
 error: functions with the "riscv-interrupt-s" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:54:5
+  --> $DIR/cannot-be-called.rs:57:5
    |
 LL |     riscv_s();
    |     ^^^^^^^^^
    |
 note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:54:5
+  --> $DIR/cannot-be-called.rs:57:5
    |
 LL |     riscv_s();
    |     ^^^^^^^^^
 
 error: functions with the "riscv-interrupt-m" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:77:5
+  --> $DIR/cannot-be-called.rs:79:5
    |
 LL |     f()
    |     ^^^
    |
 note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:77:5
+  --> $DIR/cannot-be-called.rs:79:5
    |
 LL |     f()
    |     ^^^
 
 error: functions with the "riscv-interrupt-s" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:84:5
+  --> $DIR/cannot-be-called.rs:85:5
    |
 LL |     f()
    |     ^^^
    |
 note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:84:5
+  --> $DIR/cannot-be-called.rs:85:5
    |
 LL |     f()
    |     ^^^
 
-error: aborting due to 7 previous errors; 3 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/cannot-be-called.riscv64.stderr b/tests/ui/abi/cannot-be-called.riscv64.stderr
index 9fadbd639b8..040b60c7657 100644
--- a/tests/ui/abi/cannot-be-called.riscv64.stderr
+++ b/tests/ui/abi/cannot-be-called.riscv64.stderr
@@ -1,130 +1,87 @@
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:38:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "msp430-interrupt" fn msp430() {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:40:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "avr-interrupt" fn avr() {}
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:46:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" fn x86() {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:36:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:65:25
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
+   |                         ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:38:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:71:22
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:44:1
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:89:22
    |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
 error: functions with the "riscv-interrupt-m" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:52:5
+  --> $DIR/cannot-be-called.rs:55:5
    |
 LL |     riscv_m();
    |     ^^^^^^^^^
    |
 note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:52:5
+  --> $DIR/cannot-be-called.rs:55:5
    |
 LL |     riscv_m();
    |     ^^^^^^^^^
 
 error: functions with the "riscv-interrupt-s" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:54:5
+  --> $DIR/cannot-be-called.rs:57:5
    |
 LL |     riscv_s();
    |     ^^^^^^^^^
    |
 note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:54:5
+  --> $DIR/cannot-be-called.rs:57:5
    |
 LL |     riscv_s();
    |     ^^^^^^^^^
 
 error: functions with the "riscv-interrupt-m" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:77:5
+  --> $DIR/cannot-be-called.rs:79:5
    |
 LL |     f()
    |     ^^^
    |
 note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:77:5
+  --> $DIR/cannot-be-called.rs:79:5
    |
 LL |     f()
    |     ^^^
 
 error: functions with the "riscv-interrupt-s" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:84:5
+  --> $DIR/cannot-be-called.rs:85:5
    |
 LL |     f()
    |     ^^^
    |
 note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:84:5
+  --> $DIR/cannot-be-called.rs:85:5
    |
 LL |     f()
    |     ^^^
 
-error: aborting due to 7 previous errors; 3 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:88:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/cannot-be-called.rs b/tests/ui/abi/cannot-be-called.rs
index 89173655a4a..6918c2f56a3 100644
--- a/tests/ui/abi/cannot-be-called.rs
+++ b/tests/ui/abi/cannot-be-called.rs
@@ -1,3 +1,8 @@
+/*! Tests entry-point ABIs cannot be called
+
+Interrupt ABIs share similar semantics, in that they are special entry-points unusable by Rust.
+So we test that they error in essentially all of the same places.
+*/
 //@ add-core-stubs
 //@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430
 //
@@ -18,21 +23,18 @@
 #![no_core]
 #![feature(
     no_core,
-    lang_items,
-    abi_ptx,
     abi_msp430_interrupt,
     abi_avr_interrupt,
     abi_gpu_kernel,
     abi_x86_interrupt,
     abi_riscv_interrupt,
-    abi_c_cmse_nonsecure_call,
-    abi_vectorcall,
-    cmse_nonsecure_entry
 )]
 
 extern crate minicore;
 use minicore::*;
 
+/* extern "interrupt" definition */
+
 extern "msp430-interrupt" fn msp430() {}
 //[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI
 extern "avr-interrupt" fn avr() {}
@@ -44,6 +46,7 @@ extern "riscv-interrupt-s" fn riscv_s() {}
 extern "x86-interrupt" fn x86() {}
 //[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI
 
+/* extern "interrupt" calls  */
 fn call_the_interrupts() {
     msp430();
     //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called
@@ -57,37 +60,34 @@ fn call_the_interrupts() {
     //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called
 }
 
+/* extern "interrupt" fnptr calls */
+
 fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-    //[x64,x64_win,i686,riscv32,riscv64,avr]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,i686,riscv32,riscv64,avr]~^^ WARN this was previously accepted
+    //[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI
     f()
     //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called
 }
 
 fn avr_ptr(f: extern "avr-interrupt" fn()) {
-    //[x64,x64_win,i686,riscv32,riscv64,msp430]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,i686,riscv32,riscv64,msp430]~^^ WARN this was previously accepted
+    //[x64,x64_win,i686,riscv32,riscv64,msp430]~^ ERROR is not a supported ABI
     f()
     //[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called
 }
 
 fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-    //[x64,x64_win,i686,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,i686,avr,msp430]~^^ WARN this was previously accepted
+    //[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI
     f()
     //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called
 }
 
 fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-    //[x64,x64_win,i686,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,i686,avr,msp430]~^^ WARN this was previously accepted
+    //[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI
     f()
     //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-s" ABI cannot be called
 }
 
 fn x86_ptr(f: extern "x86-interrupt" fn()) {
-    //[riscv32,riscv64,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[riscv32,riscv64,avr,msp430]~^^ WARN this was previously accepted
+    //[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI
     f()
     //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called
 }
diff --git a/tests/ui/abi/cannot-be-called.x64.stderr b/tests/ui/abi/cannot-be-called.x64.stderr
index 113b40eb67b..f59fdba2f35 100644
--- a/tests/ui/abi/cannot-be-called.x64.stderr
+++ b/tests/ui/abi/cannot-be-called.x64.stderr
@@ -1,72 +1,59 @@
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:38:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "msp430-interrupt" fn msp430() {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:40:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "avr-interrupt" fn avr() {}
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:42:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-m" fn riscv_m() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:44:8
    |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-s" fn riscv_s() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:36:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:65:25
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
+   |                         ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:38:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:71:22
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:40:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:77:26
    |
-LL | extern "riscv-interrupt-m" fn riscv_m() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:42:1
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:83:26
    |
-LL | extern "riscv-interrupt-s" fn riscv_s() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
 error: functions with the "x86-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:56:5
+  --> $DIR/cannot-be-called.rs:59:5
    |
 LL |     x86();
    |     ^^^^^
    |
 note: an `extern "x86-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:56:5
+  --> $DIR/cannot-be-called.rs:59:5
    |
 LL |     x86();
    |     ^^^^^
@@ -83,50 +70,6 @@ note: an `extern "x86-interrupt"` function can only be called using inline assem
 LL |     f()
    |     ^^^
 
-error: aborting due to 6 previous errors; 4 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/cannot-be-called.x64_win.stderr b/tests/ui/abi/cannot-be-called.x64_win.stderr
index 113b40eb67b..f59fdba2f35 100644
--- a/tests/ui/abi/cannot-be-called.x64_win.stderr
+++ b/tests/ui/abi/cannot-be-called.x64_win.stderr
@@ -1,72 +1,59 @@
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:38:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | extern "msp430-interrupt" fn msp430() {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:40:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "avr-interrupt" fn avr() {}
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:42:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-m" fn riscv_m() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:44:8
    |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-s" fn riscv_s() {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:36:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:65:25
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
+   |                         ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:38:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:71:22
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
+   |                      ^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:40:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:77:26
    |
-LL | extern "riscv-interrupt-m" fn riscv_m() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target
-  --> $DIR/cannot-be-called.rs:42:1
+error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target
+  --> $DIR/cannot-be-called.rs:83:26
    |
-LL | extern "riscv-interrupt-s" fn riscv_s() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
+   |                          ^^^^^^^^^^^^^^^^^^^
 
 error: functions with the "x86-interrupt" ABI cannot be called
-  --> $DIR/cannot-be-called.rs:56:5
+  --> $DIR/cannot-be-called.rs:59:5
    |
 LL |     x86();
    |     ^^^^^
    |
 note: an `extern "x86-interrupt"` function can only be called using inline assembly
-  --> $DIR/cannot-be-called.rs:56:5
+  --> $DIR/cannot-be-called.rs:59:5
    |
 LL |     x86();
    |     ^^^^^
@@ -83,50 +70,6 @@ note: an `extern "x86-interrupt"` function can only be called using inline assem
 LL |     f()
    |     ^^^
 
-error: aborting due to 6 previous errors; 4 warnings emitted
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/cannot-be-called.rs:67:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/cannot-be-called.rs:74:19
-   |
-LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-s" is not supported on this target
-  --> $DIR/cannot-be-called.rs:81:19
-   |
-LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/unsupported-abi-transmute.rs b/tests/ui/abi/unsupported-abi-transmute.rs
new file mode 100644
index 00000000000..31501bc6d10
--- /dev/null
+++ b/tests/ui/abi/unsupported-abi-transmute.rs
@@ -0,0 +1,15 @@
+//@ add-core-stubs
+//@ compile-flags: --crate-type=lib --target x86_64-unknown-none
+//@ needs-llvm-components: x86
+//@ edition: 2018
+#![no_core]
+#![feature(no_core, lang_items)]
+extern crate minicore;
+use minicore::*;
+
+// Check we error before unsupported ABIs reach codegen stages.
+
+fn anything() {
+    let a = unsafe { mem::transmute::<usize, extern "thiscall" fn(i32)>(4) }(2);
+    //~^ ERROR: is not a supported ABI for the current target [E0570]
+}
diff --git a/tests/ui/abi/unsupported-abi-transmute.stderr b/tests/ui/abi/unsupported-abi-transmute.stderr
new file mode 100644
index 00000000000..63056180c71
--- /dev/null
+++ b/tests/ui/abi/unsupported-abi-transmute.stderr
@@ -0,0 +1,9 @@
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported-abi-transmute.rs:13:53
+   |
+LL |     let a = unsafe { mem::transmute::<usize, extern "thiscall" fn(i32)>(4) }(2);
+   |                                                     ^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported-varargs-fnptr.rs b/tests/ui/abi/unsupported-varargs-fnptr.rs
new file mode 100644
index 00000000000..733e16c7e4b
--- /dev/null
+++ b/tests/ui/abi/unsupported-varargs-fnptr.rs
@@ -0,0 +1,18 @@
+// FIXME(workingjubilee): add revisions and generalize to other platform-specific varargs ABIs,
+// preferably after the only-arch directive is enhanced with an "or pattern" syntax
+//@ only-x86_64
+
+// We have to use this flag to force ABI computation of an invalid ABI
+//@ compile-flags: -Clink-dead-code
+
+#![feature(extended_varargs_abi_support)]
+
+// sometimes fn ptrs with varargs make layout and ABI computation ICE
+// as found in https://github.com/rust-lang/rust/issues/142107
+
+fn aapcs(f: extern "aapcs" fn(usize, ...)) {
+//~^ ERROR [E0570]
+// Note we DO NOT have to actually make a call to trigger the ICE!
+}
+
+fn main() {}
diff --git a/tests/ui/abi/unsupported-varargs-fnptr.stderr b/tests/ui/abi/unsupported-varargs-fnptr.stderr
new file mode 100644
index 00000000000..445e57df9d8
--- /dev/null
+++ b/tests/ui/abi/unsupported-varargs-fnptr.stderr
@@ -0,0 +1,9 @@
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported-varargs-fnptr.rs:13:20
+   |
+LL | fn aapcs(f: extern "aapcs" fn(usize, ...)) {
+   |                    ^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index 7b9b9d5c978..85e251a65d2 100644
--- a/tests/ui/abi/unsupported.aarch64.stderr
+++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -1,403 +1,226 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:55:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:47:8
    |
-LL | extern "aapcs" {}
-   | ^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" fn aapcs() {}
+   |        ^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:49:24
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
+   |                        ^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:53:8
    |
-LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" {}
+   |        ^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "msp430-interrupt" {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
 LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:86:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:62:8
    |
 LL | extern "riscv-interrupt-m" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:65:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:97:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:68:8
    |
-LL | extern "x86-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" fn thiscall() {}
+   |        ^^^^^^^^^^
 
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:70:27
    |
 LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                           ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:107:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:74:8
    |
 LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
+
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:77:8
+   |
+LL | extern "stdcall" fn stdcall() {}
+   |        ^^^^^^^^^
+   |
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:81:26
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |                          ^^^^^^^^^
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:87:8
    |
 LL | extern "stdcall" {}
-   | ^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    |
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:125:1
+error[E0570]: "stdcall-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:91:8
    |
 LL | extern "stdcall-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:133:17
-   |
-LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:138:1
-   |
-LL | extern "cdecl" {}
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:141:1
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:111:8
    |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C-unwind"` instead
+LL | extern "vectorcall" fn vectorcall() {}
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:113:29
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:152:1
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:117:8
    |
 LL | extern "vectorcall" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
 LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:141:17
    |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: extern "thiscall" fn(),
+   |                 ^^^^^^^^^^
 
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:146:16
    |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
-   |
-LL | extern "aapcs" fn aapcs() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     pub extern "thiscall" fn inherent_fn(self) {
+   |                ^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:153:12
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self);
+   |            ^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:158:12
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self) {
+   |            ^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:78:1
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:99:17
    |
-LL | extern "riscv-interrupt-m" fn riscv() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:89:1
-   |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:100:1
-   |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:110:1
-   |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:130:1
-   |
-LL | extern "cdecl" fn cdecl() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
+   |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:145:1
-   |
-LL | extern "vectorcall" fn vectorcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 22 previous errors; 15 warnings emitted
-
-For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
-   |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
-   |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:104:1
    |
-LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" {}
+   | ^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+warning: "cdecl-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:107:1
    |
-LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl-unwind" {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C-unwind"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:96:1
    |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" fn cdecl() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+error: aborting due to 29 previous errors; 4 warnings emitted
 
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index 5b057bdcbae..a4274d0ac60 100644
--- a/tests/ui/abi/unsupported.arm.stderr
+++ b/tests/ui/abi/unsupported.arm.stderr
@@ -1,371 +1,208 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
 LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |        ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
 LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:86:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:62:8
    |
 LL | extern "riscv-interrupt-m" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:65:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:97:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:68:8
    |
-LL | extern "x86-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" fn thiscall() {}
+   |        ^^^^^^^^^^
 
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:70:27
    |
 LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                           ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:107:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:74:8
    |
 LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
 
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:77:8
+   |
+LL | extern "stdcall" fn stdcall() {}
+   |        ^^^^^^^^^
+   |
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:81:26
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |                          ^^^^^^^^^
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:87:8
    |
 LL | extern "stdcall" {}
-   | ^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    |
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:125:1
+error[E0570]: "stdcall-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:91:8
    |
 LL | extern "stdcall-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:133:17
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:111:8
    |
-LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:138:1
-   |
-LL | extern "cdecl" {}
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:141:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C-unwind"` instead
+LL | extern "vectorcall" fn vectorcall() {}
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:113:29
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:152:1
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:117:8
    |
 LL | extern "vectorcall" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
 LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
-   |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
-   |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
-   |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:141:17
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: extern "thiscall" fn(),
+   |                 ^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:78:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:146:16
    |
-LL | extern "riscv-interrupt-m" fn riscv() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     pub extern "thiscall" fn inherent_fn(self) {
+   |                ^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:89:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:153:12
    |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self);
+   |            ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:100:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:158:12
    |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:110:1
-   |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+LL |     extern "thiscall" fn trait_fn(self) {
+   |            ^^^^^^^^^^
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:130:1
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:99:17
    |
-LL | extern "cdecl" fn cdecl() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
+   |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:145:1
-   |
-LL | extern "vectorcall" fn vectorcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 20 previous errors; 14 warnings emitted
-
-For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
-   |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:104:1
    |
-LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" {}
+   | ^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+warning: "cdecl-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:107:1
    |
-LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl-unwind" {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C-unwind"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:96:1
    |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" fn cdecl() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+error: aborting due to 26 previous errors; 4 warnings emitted
 
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr
index 56884166019..5e5d74c1d98 100644
--- a/tests/ui/abi/unsupported.i686.stderr
+++ b/tests/ui/abi/unsupported.i686.stderr
@@ -1,234 +1,87 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:55:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:47:8
    |
-LL | extern "aapcs" {}
-   | ^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" fn aapcs() {}
+   |        ^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:49:24
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
+   |                        ^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:53:8
    |
-LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" {}
+   |        ^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "msp430-interrupt" {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
 LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:86:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:62:8
    |
 LL | extern "riscv-interrupt-m" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
 LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
-   |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
-   |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
-   |
-LL | extern "aapcs" fn aapcs() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
-   |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
-   |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:78:1
-   |
-LL | extern "riscv-interrupt-m" fn riscv() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: functions with the "x86-interrupt" ABI cannot be called
-  --> $DIR/unsupported.rs:94:5
-   |
-LL |     f()
-   |     ^^^
-   |
-note: an `extern "x86-interrupt"` function can only be called using inline assembly
-  --> $DIR/unsupported.rs:94:5
-   |
-LL |     f()
-   |     ^^^
-
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 14 previous errors; 7 warnings emitted
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
-   |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
-   |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr
index 124ba13cc23..7ef7cae5057 100644
--- a/tests/ui/abi/unsupported.riscv32.stderr
+++ b/tests/ui/abi/unsupported.riscv32.stderr
@@ -1,383 +1,220 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:55:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:47:8
    |
-LL | extern "aapcs" {}
-   | ^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" fn aapcs() {}
+   |        ^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:49:24
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
+   |                        ^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:53:8
    |
-LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" {}
+   |        ^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "msp430-interrupt" {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
 LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:65:8
    |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:97:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:68:8
    |
-LL | extern "x86-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" fn thiscall() {}
+   |        ^^^^^^^^^^
 
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:70:27
    |
 LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                           ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:107:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:74:8
    |
 LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
 
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:77:8
+   |
+LL | extern "stdcall" fn stdcall() {}
+   |        ^^^^^^^^^
+   |
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:81:26
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |                          ^^^^^^^^^
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:87:8
    |
 LL | extern "stdcall" {}
-   | ^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    |
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:125:1
+error[E0570]: "stdcall-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:91:8
    |
 LL | extern "stdcall-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:133:17
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:111:8
    |
-LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:138:1
-   |
-LL | extern "cdecl" {}
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:141:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C-unwind"` instead
+LL | extern "vectorcall" fn vectorcall() {}
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:113:29
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:152:1
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:117:8
    |
 LL | extern "vectorcall" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
 LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:141:17
    |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: extern "thiscall" fn(),
+   |                 ^^^^^^^^^^
 
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:146:16
    |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     pub extern "thiscall" fn inherent_fn(self) {
+   |                ^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:153:12
    |
-LL | extern "aapcs" fn aapcs() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
-   |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self);
+   |            ^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:158:12
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self) {
+   |            ^^^^^^^^^^
 
-error: functions with the "riscv-interrupt-m" ABI cannot be called
-  --> $DIR/unsupported.rs:83:5
-   |
-LL |     f()
-   |     ^^^
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:99:17
    |
-note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
-  --> $DIR/unsupported.rs:83:5
-   |
-LL |     f()
-   |     ^^^
-
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:89:1
-   |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:100:1
-   |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:110:1
-   |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:130:1
-   |
-LL | extern "cdecl" fn cdecl() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
+   |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:145:1
-   |
-LL | extern "vectorcall" fn vectorcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 21 previous errors; 14 warnings emitted
-
-For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
-   |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
-   |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:104:1
    |
-LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" {}
+   | ^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+warning: "cdecl-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:107:1
    |
-LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl-unwind" {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C-unwind"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:96:1
    |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" fn cdecl() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+error: aborting due to 28 previous errors; 4 warnings emitted
 
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr
index 124ba13cc23..7ef7cae5057 100644
--- a/tests/ui/abi/unsupported.riscv64.stderr
+++ b/tests/ui/abi/unsupported.riscv64.stderr
@@ -1,383 +1,220 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:55:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:47:8
    |
-LL | extern "aapcs" {}
-   | ^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" fn aapcs() {}
+   |        ^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:49:24
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
+   |                        ^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:53:8
    |
-LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" {}
+   |        ^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "msp430-interrupt" {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
 LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
+error[E0570]: "x86-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:65:8
    |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "x86-interrupt" {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:97:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:68:8
    |
-LL | extern "x86-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" fn thiscall() {}
+   |        ^^^^^^^^^^
 
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:70:27
    |
 LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                           ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:107:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:74:8
    |
 LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
 
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:77:8
+   |
+LL | extern "stdcall" fn stdcall() {}
+   |        ^^^^^^^^^
+   |
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:81:26
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |                          ^^^^^^^^^
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:87:8
    |
 LL | extern "stdcall" {}
-   | ^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    |
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:125:1
+error[E0570]: "stdcall-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:91:8
    |
 LL | extern "stdcall-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:133:17
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:111:8
    |
-LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:138:1
-   |
-LL | extern "cdecl" {}
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:141:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C-unwind"` instead
+LL | extern "vectorcall" fn vectorcall() {}
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:113:29
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:152:1
+error[E0570]: "vectorcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:117:8
    |
 LL | extern "vectorcall" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
 LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:141:17
    |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: extern "thiscall" fn(),
+   |                 ^^^^^^^^^^
 
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:146:16
    |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     pub extern "thiscall" fn inherent_fn(self) {
+   |                ^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:153:12
    |
-LL | extern "aapcs" fn aapcs() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
-   |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self);
+   |            ^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:158:12
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self) {
+   |            ^^^^^^^^^^
 
-error: functions with the "riscv-interrupt-m" ABI cannot be called
-  --> $DIR/unsupported.rs:83:5
-   |
-LL |     f()
-   |     ^^^
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:99:17
    |
-note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly
-  --> $DIR/unsupported.rs:83:5
-   |
-LL |     f()
-   |     ^^^
-
-error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:89:1
-   |
-LL | extern "x86-interrupt" fn x86() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:100:1
-   |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:110:1
-   |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:130:1
-   |
-LL | extern "cdecl" fn cdecl() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
+   |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:145:1
-   |
-LL | extern "vectorcall" fn vectorcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 21 previous errors; 14 warnings emitted
-
-For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
-   |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "x86-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:91:15
-   |
-LL | fn x86_ptr(f: extern "x86-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
-   |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:104:1
    |
-LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" {}
+   | ^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:147:22
+warning: "cdecl-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:107:1
    |
-LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl-unwind" {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C-unwind"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:96:1
    |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" fn cdecl() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+error: aborting due to 28 previous errors; 4 warnings emitted
 
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs
index 4ddcbae409b..4bb732c94ac 100644
--- a/tests/ui/abi/unsupported.rs
+++ b/tests/ui/abi/unsupported.rs
@@ -36,8 +36,7 @@ use minicore::*;
 extern "ptx-kernel" fn ptx() {}
 //~^ ERROR is not a supported ABI
 fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-    //~^ WARN unsupported_fn_ptr_calling_conventions
-    //~^^ WARN this was previously accepted
+//~^ ERROR is not a supported ABI
     f()
 }
 extern "ptx-kernel" {}
@@ -48,60 +47,28 @@ extern "gpu-kernel" fn gpu() {}
 extern "aapcs" fn aapcs() {}
 //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
 fn aapcs_ptr(f: extern "aapcs" fn()) {
-    //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
+    //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
     f()
 }
 extern "aapcs" {}
 //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
 
-extern "msp430-interrupt" fn msp430() {}
-//~^ ERROR is not a supported ABI
-fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-    //~^ WARN unsupported_fn_ptr_calling_conventions
-    //~^^ WARN this was previously accepted
-    f()
-}
 extern "msp430-interrupt" {}
 //~^ ERROR is not a supported ABI
 
-extern "avr-interrupt" fn avr() {}
-//~^ ERROR is not a supported ABI
-fn avr_ptr(f: extern "avr-interrupt" fn()) {
-    //~^ WARN unsupported_fn_ptr_calling_conventions
-    //~^^ WARN this was previously accepted
-    f()
-}
 extern "avr-interrupt" {}
 //~^ ERROR is not a supported ABI
 
-extern "riscv-interrupt-m" fn riscv() {}
-//[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI
-fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-    //[x64,x64_win,i686,arm,aarch64]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,i686,arm,aarch64]~^^ WARN this was previously accepted
-    f()
-    //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called
-}
 extern "riscv-interrupt-m" {}
 //[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI
 
-extern "x86-interrupt" fn x86() {}
-//[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI
-fn x86_ptr(f: extern "x86-interrupt" fn()) {
-    //[aarch64,arm,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[aarch64,arm,riscv32,riscv64]~^^ WARN this was previously accepted
-    f()
-    //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called
-}
 extern "x86-interrupt" {}
 //[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI
 
 extern "thiscall" fn thiscall() {}
 //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
 fn thiscall_ptr(f: extern "thiscall" fn()) {
-    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
+    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
     f()
 }
 extern "thiscall" {}
@@ -112,10 +79,9 @@ extern "stdcall" fn stdcall() {}
 //[x64_win]~^^ WARN unsupported_calling_conventions
 //[x64_win]~^^^ WARN this was previously accepted
 fn stdcall_ptr(f: extern "stdcall" fn()) {
-    //[x64_win]~^ WARN unsupported_calling_conventions
-    //[x64_win]~| WARN this was previously accepted
-    //[x64,arm,aarch64,riscv32,riscv64]~^^^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,arm,aarch64,riscv32,riscv64]~| WARN this was previously accepted
+    //[x64,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
+    //[x64_win]~^^ WARN unsupported_calling_conventions
+    //[x64_win]~|  WARN this was previously accepted
     f()
 }
 extern "stdcall" {}
@@ -132,7 +98,7 @@ extern "cdecl" fn cdecl() {}
 //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
 fn cdecl_ptr(f: extern "cdecl" fn()) {
     //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_calling_conventions
-    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
+    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~| WARN this was previously accepted
     f()
 }
 extern "cdecl" {}
@@ -145,24 +111,21 @@ extern "cdecl-unwind" {}
 extern "vectorcall" fn vectorcall() {}
 //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
 fn vectorcall_ptr(f: extern "vectorcall" fn()) {
-    //[arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
+    //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
     f()
 }
 extern "vectorcall" {}
 //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI
 
 fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-    //~^ WARN unsupported_fn_ptr_calling_conventions
-    //~^^ WARN this was previously accepted
+//~^ ERROR is not a supported ABI
     f()
 }
 
 extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
 //~^ ERROR is not a supported ABI
 fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-    //~^ WARN unsupported_fn_ptr_calling_conventions
-    //~^^ WARN this was previously accepted
+//~^ ERROR is not a supported ABI
     f()
 }
 extern "C-cmse-nonsecure-entry" {}
@@ -171,5 +134,29 @@ extern "C-cmse-nonsecure-entry" {}
 #[cfg(windows)]
 #[link(name = "foo", kind = "raw-dylib")]
 extern "cdecl" {}
-//[x64_win]~^ WARN use of calling convention not supported on this target
+//[x64_win]~^ WARN unsupported_calling_conventions
 //[x64_win]~^^ WARN this was previously accepted
+
+struct FnPtrBearer {
+    ptr: extern "thiscall" fn(),
+    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI
+}
+
+impl FnPtrBearer {
+    pub extern "thiscall" fn inherent_fn(self) {
+        //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI
+        (self.ptr)()
+    }
+}
+
+trait Trait {
+    extern "thiscall" fn trait_fn(self);
+    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI
+}
+
+impl Trait for FnPtrBearer {
+    extern "thiscall" fn trait_fn(self) {
+        //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI
+        self.inherent_fn()
+    }
+}
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr
index 737c4c670b8..7b021dff7c9 100644
--- a/tests/ui/abi/unsupported.x64.stderr
+++ b/tests/ui/abi/unsupported.x64.stderr
@@ -1,351 +1,202 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:55:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:47:8
    |
-LL | extern "aapcs" {}
-   | ^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" fn aapcs() {}
+   |        ^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:49:24
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
+   |                        ^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:53:8
    |
-LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "aapcs" {}
+   |        ^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "msp430-interrupt" {}
+   |        ^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
 LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:62:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "riscv-interrupt-m" {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:86:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:68:8
    |
-LL | extern "riscv-interrupt-m" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" fn thiscall() {}
+   |        ^^^^^^^^^^
 
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:70:27
    |
 LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                           ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:107:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:74:8
    |
 LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^
 
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:77:8
+   |
+LL | extern "stdcall" fn stdcall() {}
+   |        ^^^^^^^^^
+   |
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:81:26
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+   |                          ^^^^^^^^^
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+error[E0570]: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:87:8
    |
 LL | extern "stdcall" {}
-   | ^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    |
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:125:1
+error[E0570]: "stdcall-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:91:8
    |
 LL | extern "stdcall-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:133:17
-   |
-LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:138:1
-   |
-LL | extern "cdecl" {}
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C"` instead
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:141:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
-   = help: use `extern "C-unwind"` instead
-
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
 LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:141:17
    |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: extern "thiscall" fn(),
+   |                 ^^^^^^^^^^
 
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:146:16
    |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     pub extern "thiscall" fn inherent_fn(self) {
+   |                ^^^^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:153:12
    |
-LL | extern "aapcs" fn aapcs() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self);
+   |            ^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:158:12
    |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "thiscall" fn trait_fn(self) {
+   |            ^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:99:17
    |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:78:1
-   |
-LL | extern "riscv-interrupt-m" fn riscv() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: functions with the "x86-interrupt" ABI cannot be called
-  --> $DIR/unsupported.rs:94:5
-   |
-LL |     f()
-   |     ^^^
-   |
-note: an `extern "x86-interrupt"` function can only be called using inline assembly
-  --> $DIR/unsupported.rs:94:5
-   |
-LL |     f()
-   |     ^^^
-
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:100:1
-   |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:110:1
-   |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:130:1
-   |
-LL | extern "cdecl" fn cdecl() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
+   |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 19 previous errors; 13 warnings emitted
-
-For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
-   |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:104:1
    |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" {}
+   | ^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "stdcall" is not supported on this target
-  --> $DIR/unsupported.rs:114:19
+warning: "cdecl-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:107:1
    |
-LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl-unwind" {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C-unwind"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:96:1
    |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "cdecl" fn cdecl() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+error: aborting due to 25 previous errors; 4 warnings emitted
 
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr
index f201a089d3f..4ce5b3340d1 100644
--- a/tests/ui/abi/unsupported.x64_win.stderr
+++ b/tests/ui/abi/unsupported.x64_win.stderr
@@ -1,96 +1,131 @@
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:8
    |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "ptx-kernel" fn ptx() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:22
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
+   |                      ^^^^^^^^^^^^
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+error[E0570]: "ptx-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:8
    |
 LL | extern "ptx-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^
 
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:8
    |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
+LL | extern "gpu-kernel" fn gpu() {}
+   |        ^^^^^^^^^^^^
+
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:47:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "aapcs" fn aapcs() {}
+   |        ^^^^^^^
+
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:49:24
+   |
+LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
+   |                        ^^^^^^^
 
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:55:1
+error[E0570]: "aapcs" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:53:8
    |
 LL | extern "aapcs" {}
-   | ^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^
 
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
+error[E0570]: "msp430-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:8
    |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "msp430-interrupt" {}
+   |        ^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "avr-interrupt" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:59:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "avr-interrupt" {}
+   |        ^^^^^^^^^^^^^^^
 
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:65:1
+error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:62:8
    |
-LL | extern "msp430-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "riscv-interrupt-m" {}
+   |        ^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:68:8
    |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" fn thiscall() {}
+   |        ^^^^^^^^^^
+
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:70:27
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
+   |                           ^^^^^^^^^^
 
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:75:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:74:8
    |
-LL | extern "avr-interrupt" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "thiscall" {}
+   |        ^^^^^^^^^^
 
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:120:28
    |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:125:8
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:86:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:127:29
    |
-LL | extern "riscv-interrupt-m" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:131:8
    |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "C-cmse-nonsecure-entry" {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:141:17
    |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+LL |     ptr: extern "thiscall" fn(),
+   |                 ^^^^^^^^^^
 
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:107:1
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:146:16
    |
-LL | extern "thiscall" {}
-   | ^^^^^^^^^^^^^^^^^^^^
+LL |     pub extern "thiscall" fn inherent_fn(self) {
+   |                ^^^^^^^^^^
+
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:153:12
+   |
+LL |     extern "thiscall" fn trait_fn(self);
+   |            ^^^^^^^^^^
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:114:19
+error[E0570]: "thiscall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:158:12
+   |
+LL |     extern "thiscall" fn trait_fn(self) {
+   |            ^^^^^^^^^^
+
+warning: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:81:19
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    |                   ^^^^^^^^^^^^^^^^^^^^^
@@ -100,8 +135,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:121:1
+warning: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:87:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -110,8 +145,8 @@ LL | extern "stdcall" {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:125:1
+warning: "stdcall-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:91:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,8 +155,8 @@ LL | extern "stdcall-unwind" {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:133:17
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:99:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
@@ -130,8 +165,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:138:1
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:104:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -140,8 +175,8 @@ LL | extern "cdecl" {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:141:1
+warning: "cdecl-unwind" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:107:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -150,32 +185,8 @@ LL | extern "cdecl-unwind" {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C-unwind"` instead
 
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
-   |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:168:1
-   |
-LL | extern "C-cmse-nonsecure-entry" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:173:1
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -184,62 +195,8 @@ LL | extern "cdecl" {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
 
-error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
-   |
-LL | extern "ptx-kernel" fn ptx() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:45:1
-   |
-LL | extern "gpu-kernel" fn gpu() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:48:1
-   |
-LL | extern "aapcs" fn aapcs() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:58:1
-   |
-LL | extern "msp430-interrupt" fn msp430() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:68:1
-   |
-LL | extern "avr-interrupt" fn avr() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:78:1
-   |
-LL | extern "riscv-interrupt-m" fn riscv() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: functions with the "x86-interrupt" ABI cannot be called
-  --> $DIR/unsupported.rs:94:5
-   |
-LL |     f()
-   |     ^^^
-   |
-note: an `extern "x86-interrupt"` function can only be called using inline assembly
-  --> $DIR/unsupported.rs:94:5
-   |
-LL |     f()
-   |     ^^^
-
-error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:100:1
-   |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:110:1
+warning: "stdcall" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:77:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -248,8 +205,8 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:130:1
+warning: "cdecl" is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:96:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -258,100 +215,6 @@ LL | extern "cdecl" fn cdecl() {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:161:1
-   |
-LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 16 previous errors; 17 warnings emitted
+error: aborting due to 21 previous errors; 9 warnings emitted
 
 For more information about this error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "ptx-kernel" is not supported on this target
-  --> $DIR/unsupported.rs:38:15
-   |
-LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "aapcs" is not supported on this target
-  --> $DIR/unsupported.rs:50:17
-   |
-LL | fn aapcs_ptr(f: extern "aapcs" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "msp430-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:60:18
-   |
-LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) {
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "avr-interrupt" is not supported on this target
-  --> $DIR/unsupported.rs:70:15
-   |
-LL | fn avr_ptr(f: extern "avr-interrupt" fn()) {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "riscv-interrupt-m" is not supported on this target
-  --> $DIR/unsupported.rs:80:17
-   |
-LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "thiscall" is not supported on this target
-  --> $DIR/unsupported.rs:102:20
-   |
-LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:155:21
-   |
-LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:163:22
-   |
-LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/argument-suggestions/issue-100478.rs b/tests/ui/argument-suggestions/issue-100478.rs
index b0a9703112e..219870f3b23 100644
--- a/tests/ui/argument-suggestions/issue-100478.rs
+++ b/tests/ui/argument-suggestions/issue-100478.rs
@@ -32,8 +32,8 @@ fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {}
 
 fn main() {
     three_diff(T2::new(0)); //~ ERROR function takes
-    four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308]
-    four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308]
+    four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR arguments to this function are incorrect [E0308]
+    four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR arguments to this function are incorrect [E0308]
 
     let p1 = T1::new(0);
     let p2 = Arc::new(T2::new(0));
diff --git a/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed b/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed
index c74a32e442f..9e5e889506c 100644
--- a/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed
+++ b/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed
@@ -4,5 +4,5 @@
 // Regression test for issue 79694
 
 fn main() {
-    let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
+    let _ = async move { }; //~ ERROR the order of `move` and `async` is incorrect
 }
diff --git a/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs b/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs
index 81ffbacc327..9c36a6c96da 100644
--- a/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs
+++ b/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs
@@ -4,5 +4,5 @@
 // Regression test for issue 79694
 
 fn main() {
-    let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
+    let _ = move async { }; //~ ERROR the order of `move` and `async` is incorrect
 }
diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.rs b/tests/ui/attributes/rustc_skip_during_method_dispatch.rs
new file mode 100644
index 00000000000..25b473d5a58
--- /dev/null
+++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.rs
@@ -0,0 +1,38 @@
+#![feature(rustc_attrs)]
+
+#[rustc_skip_during_method_dispatch]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input [E0539]
+trait NotAList {}
+
+#[rustc_skip_during_method_dispatch = "array"]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input [E0539]
+trait AlsoNotAList {}
+
+#[rustc_skip_during_method_dispatch()]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
+trait Argless {}
+
+#[rustc_skip_during_method_dispatch(array, boxed_slice, array)]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
+trait Duplicate {}
+
+#[rustc_skip_during_method_dispatch(slice)]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
+trait Unexpected {}
+
+#[rustc_skip_during_method_dispatch(array = true)]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
+trait KeyValue {}
+
+#[rustc_skip_during_method_dispatch("array")]
+//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
+trait String {}
+
+#[rustc_skip_during_method_dispatch(array, boxed_slice)]
+trait OK {}
+
+#[rustc_skip_during_method_dispatch(array)]
+//~^ ERROR: attribute should be applied to a trait
+impl OK for () {}
+
+fn main() {}
diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr
new file mode 100644
index 00000000000..2f5d7968489
--- /dev/null
+++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr
@@ -0,0 +1,76 @@
+error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:3:1
+   |
+LL | #[rustc_skip_during_method_dispatch]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:7:1
+   |
+LL | #[rustc_skip_during_method_dispatch = "array"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:11:1
+   |
+LL | #[rustc_skip_during_method_dispatch()]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--^
+   | |                                  |
+   | |                                  expected at least 1 argument here
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error[E0538]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:15:1
+   |
+LL | #[rustc_skip_during_method_dispatch(array, boxed_slice, array)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
+   | |                                                       |
+   | |                                                       found `array` used as a key more than once
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:19:1
+   |
+LL | #[rustc_skip_during_method_dispatch(slice)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
+   | |                                   |
+   | |                                   valid arguments are `array` or `boxed_slice`
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error[E0565]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:23:1
+   |
+LL | #[rustc_skip_during_method_dispatch(array = true)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^
+   | |                                         |
+   | |                                         didn't expect any arguments here
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error[E0565]: malformed `rustc_skip_during_method_dispatch` attribute input
+  --> $DIR/rustc_skip_during_method_dispatch.rs:27:1
+   |
+LL | #[rustc_skip_during_method_dispatch("array")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
+   | |                                   |
+   | |                                   didn't expect a literal here
+   | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
+
+error: attribute should be applied to a trait
+  --> $DIR/rustc_skip_during_method_dispatch.rs:34:1
+   |
+LL | #[rustc_skip_during_method_dispatch(array)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | impl OK for () {}
+   | ----------------- not a trait
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0538, E0539, E0565.
+For more information about an error, try `rustc --explain E0538`.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs
index 2d0ed5d2a30..40e2da8d1cd 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs
@@ -1,9 +1,9 @@
 // gate-test-abi_c_cmse_nonsecure_call
-#[allow(unsupported_fn_ptr_calling_conventions)]
 fn main() {
     let non_secure_function = unsafe {
         core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>(
-            //~^ ERROR [E0658]
+            //~^ ERROR: is not a supported ABI for the current target [E0570]
+            //~| ERROR: ABI is experimental and subject to change [E0658]
             0x10000004,
         )
     };
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr
index beb0ab70cc7..dcbe09d8b36 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr
@@ -1,5 +1,11 @@
+error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target
+  --> $DIR/gate_test.rs:4:46
+   |
+LL |         core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>(
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0658]: the extern "C-cmse-nonsecure-call" ABI is experimental and subject to change
-  --> $DIR/gate_test.rs:5:46
+  --> $DIR/gate_test.rs:4:46
    |
 LL |         core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>(
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,16 +14,7 @@ LL |         core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32
    = help: add `#![feature(abi_c_cmse_nonsecure_call)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/gate_test.rs:5:39
-   |
-LL |         core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn(i32, i32, i32, i32) -> i32>(
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+error: aborting due to 2 previous errors
 
+Some errors have detailed explanations: E0570, E0658.
+For more information about an error, try `rustc --explain E0570`.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs
index 6061451b2e9..de68097e139 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs
@@ -2,8 +2,8 @@
 
 #[no_mangle]
 pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
-    //~^ ERROR [E0570]
-    //~| ERROR [E0658]
+    //~^ ERROR: is not a supported ABI for the current target [E0570]
+    //~| ERROR: ABI is experimental and subject to change [E0658]
     input + 6
 }
 
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr
index 0afbbe647af..312f57591f9 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr
@@ -1,3 +1,9 @@
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/gate_test.rs:4:12
+   |
+LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0658]: the extern "C-cmse-nonsecure-entry" ABI is experimental and subject to change
   --> $DIR/gate_test.rs:4:12
    |
@@ -8,12 +14,6 @@ LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
    = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/gate_test.rs:4:1
-   |
-LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0570, E0658.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr
index 6a90dc8d635..3072d3a3abf 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr
@@ -1,8 +1,8 @@
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/trustzone-only.rs:17:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/trustzone-only.rs:17:12
    |
 LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr
index 6a90dc8d635..3072d3a3abf 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr
@@ -1,8 +1,8 @@
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/trustzone-only.rs:17:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/trustzone-only.rs:17:12
    |
 LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr
index 6a90dc8d635..3072d3a3abf 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr
@@ -1,8 +1,8 @@
-error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/trustzone-only.rs:17:1
+error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target
+  --> $DIR/trustzone-only.rs:17:12
    |
 LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/compiletest-self-test/line-annotation-mismatches.rs b/tests/ui/compiletest-self-test/line-annotation-mismatches.rs
new file mode 100644
index 00000000000..d2a14374ed4
--- /dev/null
+++ b/tests/ui/compiletest-self-test/line-annotation-mismatches.rs
@@ -0,0 +1,42 @@
+//@ should-fail
+
+// The warning is reported with unknown line
+//@ compile-flags: -D raw_pointer_derive
+//~? WARN kind and unknown line match the reported warning, but we do not suggest it
+
+// The error is expected but not reported at all.
+//~ ERROR this error does not exist
+
+// The error is reported but not expected at all.
+// "`main` function not found in crate" (the main function is intentionally not added)
+
+// An "unimportant" diagnostic is expected on a wrong line.
+//~ ERROR aborting due to
+
+// An "unimportant" diagnostic is expected with a wrong kind.
+//~? ERROR For more information about an error
+
+fn wrong_line_or_kind() {
+    // A diagnostic expected on a wrong line.
+    unresolved1;
+    //~ ERROR cannot find value `unresolved1` in this scope
+
+    // A diagnostic expected with a wrong kind.
+    unresolved2; //~ WARN cannot find value `unresolved2` in this scope
+
+    // A diagnostic expected with a missing kind (treated as a wrong kind).
+    unresolved3; //~ cannot find value `unresolved3` in this scope
+
+    // A diagnostic expected with a wrong line and kind.
+    unresolved4;
+    //~ WARN cannot find value `unresolved4` in this scope
+}
+
+fn wrong_message() {
+    // A diagnostic expected with a wrong message, but the line is known and right.
+    unresolvedA; //~ ERROR stub message 1
+
+    // A diagnostic expected with a wrong message, but the line is known and right,
+    // even if the kind doesn't match.
+    unresolvedB; //~ WARN stub message 2
+}
diff --git a/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr b/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr
new file mode 100644
index 00000000000..7ca3bfaf396
--- /dev/null
+++ b/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr
@@ -0,0 +1,61 @@
+warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+error[E0425]: cannot find value `unresolved1` in this scope
+  --> $DIR/line-annotation-mismatches.rs:21:5
+   |
+LL |     unresolved1;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `unresolved2` in this scope
+  --> $DIR/line-annotation-mismatches.rs:25:5
+   |
+LL |     unresolved2;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `unresolved3` in this scope
+  --> $DIR/line-annotation-mismatches.rs:28:5
+   |
+LL |     unresolved3;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `unresolved4` in this scope
+  --> $DIR/line-annotation-mismatches.rs:31:5
+   |
+LL |     unresolved4;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `unresolvedA` in this scope
+  --> $DIR/line-annotation-mismatches.rs:37:5
+   |
+LL |     unresolvedA;
+   |     ^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `unresolvedB` in this scope
+  --> $DIR/line-annotation-mismatches.rs:41:5
+   |
+LL |     unresolvedB;
+   |     ^^^^^^^^^^^ not found in this scope
+
+warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0601]: `main` function not found in crate `line_annotation_mismatches`
+  --> $DIR/line-annotation-mismatches.rs:42:2
+   |
+LL | }
+   |  ^ consider adding a `main` function to `$DIR/line-annotation-mismatches.rs`
+
+warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 7 previous errors; 3 warnings emitted
+
+Some errors have detailed explanations: E0425, E0601.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/deprecation/deprecated_no_stack_check.rs b/tests/ui/deprecation/deprecated_no_stack_check.rs
index ef482098634..8e1f5bbf045 100644
--- a/tests/ui/deprecation/deprecated_no_stack_check.rs
+++ b/tests/ui/deprecation/deprecated_no_stack_check.rs
@@ -1,5 +1,3 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
-
 #![deny(warnings)]
 #![feature(no_stack_check)]
 //~^ ERROR: feature has been removed [E0557]
diff --git a/tests/ui/deprecation/deprecated_no_stack_check.stderr b/tests/ui/deprecation/deprecated_no_stack_check.stderr
index 2d08b1b8db5..33788661d73 100644
--- a/tests/ui/deprecation/deprecated_no_stack_check.stderr
+++ b/tests/ui/deprecation/deprecated_no_stack_check.stderr
@@ -1,10 +1,10 @@
 error[E0557]: feature has been removed
-  --> $DIR/deprecated_no_stack_check.rs:4:12
+  --> $DIR/deprecated_no_stack_check.rs:2:12
    |
 LL | #![feature(no_stack_check)]
    |            ^^^^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.0.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/40110> for more information
+   = note: removed in 1.0.0; see <https://github.com/rust-lang/rust/pull/40110> for more information
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/derives/nonsense-input-to-debug.rs b/tests/ui/derives/nonsense-input-to-debug.rs
new file mode 100644
index 00000000000..7dfa3cd616a
--- /dev/null
+++ b/tests/ui/derives/nonsense-input-to-debug.rs
@@ -0,0 +1,12 @@
+// Issue: #32950
+// Ensure that using macros rather than a type doesn't break `derive`.
+
+#[derive(Debug)]
+struct Nonsense<T> {
+    //~^ ERROR type parameter `T` is never used
+    should_be_vec_t: vec![T],
+    //~^ ERROR `derive` cannot be used on items with type macros
+    //~| ERROR expected type, found `expr` metavariable
+}
+
+fn main() {}
diff --git a/tests/ui/derives/nonsense-input-to-debug.stderr b/tests/ui/derives/nonsense-input-to-debug.stderr
new file mode 100644
index 00000000000..7c97ca93cfc
--- /dev/null
+++ b/tests/ui/derives/nonsense-input-to-debug.stderr
@@ -0,0 +1,30 @@
+error: `derive` cannot be used on items with type macros
+  --> $DIR/nonsense-input-to-debug.rs:7:22
+   |
+LL |     should_be_vec_t: vec![T],
+   |                      ^^^^^^^
+
+error: expected type, found `expr` metavariable
+  --> $DIR/nonsense-input-to-debug.rs:7:22
+   |
+LL |     should_be_vec_t: vec![T],
+   |                      ^^^^^^^
+   |                      |
+   |                      expected type
+   |                      in this macro invocation
+   |                      this macro call doesn't expand to a type
+   |
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/nonsense-input-to-debug.rs:5:17
+   |
+LL | struct Nonsense<T> {
+   |                 ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr
index fca32c5c1e6..4fa3fee942e 100644
--- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr
@@ -19,7 +19,7 @@ LL |     extern "gpu-kernel" fn m1(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12
    |
 LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12
    |
 LL |     extern "gpu-kernel" fn m1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     extern "gpu-kernel" fn m1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12
    |
 LL |     extern "gpu-kernel" fn im1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     extern "gpu-kernel" fn im1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18
    |
 LL | type A1 = extern "gpu-kernel" fn(_: ());
    |                  ^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr
index cc81289f6b7..88734bc9d22 100644
--- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr
@@ -1,3 +1,9 @@
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8
+   |
+LL | extern "gpu-kernel" fn f1(_: ()) {}
+   |        ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
   --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8
    |
@@ -8,6 +14,12 @@ LL | extern "gpu-kernel" fn f1(_: ()) {}
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12
+   |
+LL |     extern "gpu-kernel" fn m1(_: ());
+   |            ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
   --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12
    |
@@ -18,8 +30,14 @@ LL |     extern "gpu-kernel" fn m1(_: ());
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12
+   |
+LL |     extern "gpu-kernel" fn dm1(_: ()) {}
+   |            ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12
    |
 LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -28,8 +46,14 @@ LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12
+   |
+LL |     extern "gpu-kernel" fn m1(_: ()) {}
+   |            ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12
    |
 LL |     extern "gpu-kernel" fn m1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -38,8 +62,14 @@ LL |     extern "gpu-kernel" fn m1(_: ()) {}
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12
+   |
+LL |     extern "gpu-kernel" fn im1(_: ()) {}
+   |            ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12
    |
 LL |     extern "gpu-kernel" fn im1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -48,8 +78,14 @@ LL |     extern "gpu-kernel" fn im1(_: ()) {}
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18
+   |
+LL | type A1 = extern "gpu-kernel" fn(_: ());
+   |                  ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18
    |
 LL | type A1 = extern "gpu-kernel" fn(_: ());
    |                  ^^^^^^^^^^^^
@@ -58,6 +94,12 @@ LL | type A1 = extern "gpu-kernel" fn(_: ());
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0570]: "gpu-kernel" is not a supported ABI for the current target
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8
+   |
+LL | extern "gpu-kernel" {}
+   |        ^^^^^^^^^^^^
+
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
   --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8
    |
@@ -68,58 +110,7 @@ LL | extern "gpu-kernel" {}
    = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-warning: the calling convention "gpu-kernel" is not supported on this target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11
-   |
-LL | type A1 = extern "gpu-kernel" fn(_: ());
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:47:1
-   |
-LL | extern "gpu-kernel" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:16:1
-   |
-LL | extern "gpu-kernel" fn f1(_: ()) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:5
-   |
-LL |     extern "gpu-kernel" fn dm1(_: ()) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:5
-   |
-LL |     extern "gpu-kernel" fn m1(_: ()) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:5
-   |
-LL |     extern "gpu-kernel" fn im1(_: ()) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors; 1 warning emitted
+error: aborting due to 14 previous errors
 
 Some errors have detailed explanations: E0570, E0658.
 For more information about an error, try `rustc --explain E0570`.
-Future incompatibility report: Future breakage diagnostic:
-warning: the calling convention "gpu-kernel" is not supported on this target
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11
-   |
-LL | type A1 = extern "gpu-kernel" fn(_: ());
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
-
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr
index fca32c5c1e6..4fa3fee942e 100644
--- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr
@@ -19,7 +19,7 @@ LL |     extern "gpu-kernel" fn m1(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12
    |
 LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL |     extern "gpu-kernel" fn dm1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12
    |
 LL |     extern "gpu-kernel" fn m1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     extern "gpu-kernel" fn m1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12
    |
 LL |     extern "gpu-kernel" fn im1(_: ()) {}
    |            ^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     extern "gpu-kernel" fn im1(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18
+  --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18
    |
 LL | type A1 = extern "gpu-kernel" fn(_: ());
    |                  ^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
index 7b1ee681dd7..988fbd83afc 100644
--- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
+++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs
@@ -19,6 +19,7 @@ extern "gpu-kernel" fn f1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental a
 // Methods in trait definition
 trait Tr {
     extern "gpu-kernel" fn m1(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change
+    //[HOST]~^ ERROR is not a supported ABI
 
     extern "gpu-kernel" fn dm1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
     //[HOST]~^ ERROR is not a supported ABI
@@ -40,8 +41,7 @@ impl S {
 
 // Function pointer types
 type A1 = extern "gpu-kernel" fn(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change
-//[HOST]~^ WARNING the calling convention "gpu-kernel" is not supported on this target [unsupported_fn_ptr_calling_conventions]
-//[HOST]~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+//[HOST]~^ ERROR is not a supported ABI
 
 // Foreign modules
 extern "gpu-kernel" {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change
diff --git a/tests/ui/feature-gates/feature-gate-cfi_encoding.rs b/tests/ui/feature-gates/feature-gate-cfi_encoding.rs
index 3cef8156014..b6312dd7817 100644
--- a/tests/ui/feature-gates/feature-gate-cfi_encoding.rs
+++ b/tests/ui/feature-gates/feature-gate-cfi_encoding.rs
@@ -1,4 +1,4 @@
 #![crate_type = "lib"]
 
-#[cfi_encoding = "3Bar"] //~ERROR 3:1: 3:25: the `#[cfi_encoding]` attribute is an experimental feature [E0658]
+#[cfi_encoding = "3Bar"] //~ ERROR the `#[cfi_encoding]` attribute is an experimental feature [E0658]
 pub struct Foo(i32);
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.rs b/tests/ui/feature-gates/feature-gate-concat_idents.rs
deleted file mode 100644
index 4fc3b691597..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![expect(deprecated)] // concat_idents is deprecated
-
-const XY_1: i32 = 10;
-
-fn main() {
-    const XY_2: i32 = 20;
-    let a = concat_idents!(X, Y_1); //~ ERROR `concat_idents` is not stable
-    let b = concat_idents!(X, Y_2); //~ ERROR `concat_idents` is not stable
-    assert_eq!(a, 10);
-    assert_eq!(b, 20);
-}
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.stderr b/tests/ui/feature-gates/feature-gate-concat_idents.stderr
deleted file mode 100644
index 6399424eecd..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents.rs:7:13
-   |
-LL |     let a = concat_idents!(X, Y_1);
-   |             ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents.rs:8:13
-   |
-LL |     let b = concat_idents!(X, Y_2);
-   |             ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.rs b/tests/ui/feature-gates/feature-gate-concat_idents2.rs
deleted file mode 100644
index bc2b4f7cddf..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents2.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![expect(deprecated)] // concat_idents is deprecated
-
-fn main() {
-    concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough
-                          //~| ERROR cannot find value `ab` in this scope
-}
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr b/tests/ui/feature-gates/feature-gate-concat_idents2.stderr
deleted file mode 100644
index a770c1a348b..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents2.rs:4:5
-   |
-LL |     concat_idents!(a, b);
-   |     ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0425]: cannot find value `ab` in this scope
-  --> $DIR/feature-gate-concat_idents2.rs:4:5
-   |
-LL |     concat_idents!(a, b);
-   |     ^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0425, E0658.
-For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.rs b/tests/ui/feature-gates/feature-gate-concat_idents3.rs
deleted file mode 100644
index d4a0d2e6bb0..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents3.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![expect(deprecated)] // concat_idents is deprecated
-
-const XY_1: i32 = 10;
-
-fn main() {
-    const XY_2: i32 = 20;
-    assert_eq!(10, concat_idents!(X, Y_1)); //~ ERROR `concat_idents` is not stable
-    assert_eq!(20, concat_idents!(X, Y_2)); //~ ERROR `concat_idents` is not stable
-}
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr b/tests/ui/feature-gates/feature-gate-concat_idents3.stderr
deleted file mode 100644
index 7d929322bc0..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents3.rs:7:20
-   |
-LL |     assert_eq!(10, concat_idents!(X, Y_1));
-   |                    ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents3.rs:8:20
-   |
-LL |     assert_eq!(20, concat_idents!(X, Y_2));
-   |                    ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
index 2cf4b76180e..0a463755f13 100644
--- a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
+++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
@@ -1,5 +1,3 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
-
 #![crate_type = "lib"]
 #![feature(no_coverage)] //~ ERROR feature has been removed [E0557]
 
diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
index 8c23544698d..68d0d9bc3c3 100644
--- a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
+++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
@@ -1,14 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/feature-gate-coverage-attribute.rs:4:12
+  --> $DIR/feature-gate-coverage-attribute.rs:2:12
    |
 LL | #![feature(no_coverage)]
    |            ^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.74.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/114656> for more information
+   = note: removed in 1.74.0; see <https://github.com/rust-lang/rust/pull/114656> for more information
    = note: renamed to `coverage_attribute`
 
 error[E0658]: the `#[coverage]` attribute is an experimental feature
-  --> $DIR/feature-gate-coverage-attribute.rs:12:1
+  --> $DIR/feature-gate-coverage-attribute.rs:10:1
    |
 LL | #[coverage(off)]
    | ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
index 663a83a665c..7746654555d 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
@@ -17,6 +17,10 @@ fn foo(mut x: Pin<&mut Foo>) {
     let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental
 }
 
+fn foo_const(x: Pin<&Foo>) {
+    let _y: &pin const Foo = x; //~ ERROR pinned reference syntax is experimental
+}
+
 fn foo_sugar(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental
 
 fn bar(x: Pin<&mut Foo>) {
@@ -31,6 +35,18 @@ fn baz(mut x: Pin<&mut Foo>) {
 
 fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
 
+fn borrows() {
+    let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x.as_ref());
+
+    let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
+
+    foo_const(x);
+    foo_const(x);
+}
+
 #[cfg(any())]
 mod not_compiled {
     use std::pin::Pin;
@@ -63,6 +79,18 @@ mod not_compiled {
     }
 
     fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
+
+    fn borrows() {
+        let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
+        foo(x.as_mut());
+        foo(x.as_mut());
+        foo_const(x.as_ref());
+
+        let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
+
+        foo_const(x);
+        foo_const(x);
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
index 8ed7543d86e..a8890254fac 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
@@ -29,7 +29,17 @@ LL |     let _y: &pin mut Foo = x;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:20:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:21:14
+   |
+LL |     let _y: &pin const Foo = x;
+   |              ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:24:18
    |
 LL | fn foo_sugar(_: &pin mut Foo) {}
    |                  ^^^
@@ -39,7 +49,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:32:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:36:18
    |
 LL | fn baz_sugar(_: &pin const Foo) {}
    |                  ^^^
@@ -49,7 +59,27 @@ LL | fn baz_sugar(_: &pin const Foo) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:43:23
+  --> $DIR/feature-gate-pin_ergonomics.rs:39:31
+   |
+LL |     let mut x: Pin<&mut _> = &pin mut Foo;
+   |                               ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:44:23
+   |
+LL |     let x: Pin<&_> = &pin const Foo;
+   |                       ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:59:23
    |
 LL |         fn foo_sugar(&pin mut self) {}
    |                       ^^^
@@ -59,7 +89,7 @@ LL |         fn foo_sugar(&pin mut self) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:44:29
+  --> $DIR/feature-gate-pin_ergonomics.rs:60:29
    |
 LL |         fn foo_sugar_const(&pin const self) {}
    |                             ^^^
@@ -69,7 +99,7 @@ LL |         fn foo_sugar_const(&pin const self) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:50:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:66:18
    |
 LL |         let _y: &pin mut Foo = x;
    |                  ^^^
@@ -79,7 +109,7 @@ LL |         let _y: &pin mut Foo = x;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:53:22
+  --> $DIR/feature-gate-pin_ergonomics.rs:69:22
    |
 LL |     fn foo_sugar(_: &pin mut Foo) {}
    |                      ^^^
@@ -89,7 +119,7 @@ LL |     fn foo_sugar(_: &pin mut Foo) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:65:22
+  --> $DIR/feature-gate-pin_ergonomics.rs:81:22
    |
 LL |     fn baz_sugar(_: &pin const Foo) {}
    |                      ^^^
@@ -98,8 +128,28 @@ LL |     fn baz_sugar(_: &pin const Foo) {}
    = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:84:35
+   |
+LL |         let mut x: Pin<&mut _> = &pin mut Foo;
+   |                                   ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:89:27
+   |
+LL |         let x: Pin<&_> = &pin const Foo;
+   |                           ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
 error[E0382]: use of moved value: `x`
-  --> $DIR/feature-gate-pin_ergonomics.rs:24:9
+  --> $DIR/feature-gate-pin_ergonomics.rs:28:9
    |
 LL | fn bar(x: Pin<&mut Foo>) {
    |        - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -117,7 +167,7 @@ LL | fn foo(mut x: Pin<&mut Foo>) {
    |    in this function
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/feature-gate-pin_ergonomics.rs:29:5
+  --> $DIR/feature-gate-pin_ergonomics.rs:33:5
    |
 LL | fn baz(mut x: Pin<&mut Foo>) {
    |        ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -136,7 +186,7 @@ help: consider reborrowing the `Pin` instead of moving it
 LL |     x.as_mut().foo();
    |      +++++++++
 
-error: aborting due to 12 previous errors
+error: aborting due to 17 previous errors
 
 Some errors have detailed explanations: E0382, E0658.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs b/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs
index b5fbcc9ccf8..c1469863792 100644
--- a/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs
+++ b/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs
@@ -1,4 +1,4 @@
 fn main() {
     let _ : &(dyn Send,) = &((),);
-    //~^ ERROR 2:28: 2:34: mismatched types [E0308]
+    //~^ ERROR mismatched types [E0308]
 }
diff --git a/tests/ui/feature-gates/gated-bad-feature.rs b/tests/ui/feature-gates/gated-bad-feature.rs
index 3114f661dc5..51f2db5556e 100644
--- a/tests/ui/feature-gates/gated-bad-feature.rs
+++ b/tests/ui/feature-gates/gated-bad-feature.rs
@@ -1,4 +1,3 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
 //~^ ERROR malformed `feature`
 //~| ERROR malformed `feature`
diff --git a/tests/ui/feature-gates/gated-bad-feature.stderr b/tests/ui/feature-gates/gated-bad-feature.stderr
index 0e75dff14f8..e0e84d84235 100644
--- a/tests/ui/feature-gates/gated-bad-feature.stderr
+++ b/tests/ui/feature-gates/gated-bad-feature.stderr
@@ -1,43 +1,43 @@
 error[E0556]: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:2:25
+  --> $DIR/gated-bad-feature.rs:1:25
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |                         ^^^^^^^^ help: expected just one word: `foo`
 
 error[E0556]: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:2:35
+  --> $DIR/gated-bad-feature.rs:1:35
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |                                   ^^^^^^^^^^^ help: expected just one word: `foo`
 
 error[E0557]: feature has been removed
-  --> $DIR/gated-bad-feature.rs:9:12
+  --> $DIR/gated-bad-feature.rs:8:12
    |
 LL | #![feature(test_removed_feature)]
    |            ^^^^^^^^^^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.0.0 (you are using $RUSTC_VERSION)
+   = note: removed in 1.0.0
 
 error: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:7:1
+  --> $DIR/gated-bad-feature.rs:6:1
    |
 LL | #![feature]
    | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
 
 error: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:8:1
+  --> $DIR/gated-bad-feature.rs:7:1
    |
 LL | #![feature = "foo"]
    | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
 
 error[E0635]: unknown feature `foo_bar_baz`
-  --> $DIR/gated-bad-feature.rs:2:12
+  --> $DIR/gated-bad-feature.rs:1:12
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |            ^^^^^^^^^^^
 
 error[E0635]: unknown feature `foo`
-  --> $DIR/gated-bad-feature.rs:2:48
+  --> $DIR/gated-bad-feature.rs:1:48
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |                                                ^^^
diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs
index ec6adb471ba..d8c5f48f9fd 100644
--- a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs
+++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs
@@ -1,5 +1,3 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
-
 #![feature(external_doc)] //~ ERROR feature has been removed
 #![doc(include("README.md"))] //~ ERROR unknown `doc` attribute `include`
 
diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr
index 43205c7360b..bd8c56c61c3 100644
--- a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr
+++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr
@@ -1,14 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:3:12
+  --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:1:12
    |
 LL | #![feature(external_doc)]
    |            ^^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.54.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/85457> for more information
+   = note: removed in 1.54.0; see <https://github.com/rust-lang/rust/pull/85457> for more information
    = note: use #[doc = include_str!("filename")] instead, which handles macro invocations
 
 error: unknown `doc` attribute `include`
-  --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:4:8
+  --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:2:8
    |
 LL | #![doc(include("README.md"))]
    |        ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr
index 5de6e3db327..42049da23eb 100644
--- a/tests/ui/hygiene/no_implicit_prelude.stderr
+++ b/tests/ui/hygiene/no_implicit_prelude.stderr
@@ -23,8 +23,6 @@ LL |         ().clone()
    |            ^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: there is a method `clone_from` with a similar name, but with different arguments
-  --> $SRC_DIR/core/src/clone.rs:LL:COL
    = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: trait `Clone` which provides `clone` is implemented but not in scope; perhaps you want to import it
    |
diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.rs b/tests/ui/impl-header-lifetime-elision/assoc-type.rs
index db3c416540f..14b2ea647f1 100644
--- a/tests/ui/impl-header-lifetime-elision/assoc-type.rs
+++ b/tests/ui/impl-header-lifetime-elision/assoc-type.rs
@@ -9,7 +9,7 @@ trait MyTrait {
 
 impl MyTrait for &i32 {
     type Output = &i32;
-    //~^ ERROR 11:19: 11:20: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
+    //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
 }
 
 impl MyTrait for &u32 {
diff --git a/tests/ui/impl-trait/in-bindings/lifetime-equality.rs b/tests/ui/impl-trait/in-bindings/lifetime-equality.rs
new file mode 100644
index 00000000000..6cf48dccc7d
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/lifetime-equality.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+#![feature(impl_trait_in_bindings)]
+
+// A test for #61773 which would have been difficult to support if we
+// were to represent `impl_trait_in_bindings` using opaque types.
+
+trait Trait<'a, 'b> { }
+impl<T> Trait<'_, '_> for T { }
+
+
+fn bar<'a, 'b>(data0: &'a u32, data1: &'b u32) {
+  let x: impl Trait<'_, '_> = (data0, data1);
+  force_equal(x);
+}
+
+fn force_equal<'a>(t: impl Trait<'a, 'a>) { }
+
+fn main() { }
diff --git a/tests/ui/impl-trait/in-bindings/region-lifetimes.rs b/tests/ui/impl-trait/in-bindings/region-lifetimes.rs
new file mode 100644
index 00000000000..189ab85a276
--- /dev/null
+++ b/tests/ui/impl-trait/in-bindings/region-lifetimes.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+
+#![feature(impl_trait_in_bindings)]
+
+// A test for #61773 which would have been difficult to support if we
+// were to represent `impl_trait_in_bindings` using opaque types.
+
+trait Foo<'a> { }
+impl Foo<'_> for &u32 { }
+
+fn bar<'a>(data: &'a u32) {
+  let x: impl Foo<'_> = data;
+}
+
+fn main() {
+  let _: impl Foo<'_> = &44;
+}
diff --git a/tests/ui/imports/issue-28134.rs b/tests/ui/imports/issue-28134.rs
index 70d3a327c1a..aef2fe8facd 100644
--- a/tests/ui/imports/issue-28134.rs
+++ b/tests/ui/imports/issue-28134.rs
@@ -2,4 +2,4 @@
 
 #![allow(soft_unstable)]
 #![test]
-//~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level
+//~^ ERROR `test` attribute cannot be used at crate level
diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr
index 1da5aa87070..985cd654c39 100644
--- a/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr
+++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr
@@ -1,5 +1,5 @@
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/multiple-extern-by-macro-for-underscore.rs:16:11
+  --> $DIR/multiple-extern-by-macro-for-underscore.rs:18:11
    |
 LL |     use ::_;
    |           ^ expected identifier, found reserved identifier
diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr
new file mode 100644
index 00000000000..985cd654c39
--- /dev/null
+++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-extern-by-macro-for-underscore.rs:18:11
+   |
+LL |     use ::_;
+   |           ^ expected identifier, found reserved identifier
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs b/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs
index ddf735d8947..ab877e06246 100644
--- a/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs
+++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs
@@ -1,4 +1,6 @@
-//@ edition: 2021
+//@ revisions: ed2015 ed2021
+//@[ed2015] edition: 2015
+//@[ed2021] edition: 2021
 
 // issue#128813
 
diff --git a/tests/ui/inference/hint-closure-signature-119266.rs b/tests/ui/inference/hint-closure-signature-119266.rs
index 35be600fd6a..6e136c57cca 100644
--- a/tests/ui/inference/hint-closure-signature-119266.rs
+++ b/tests/ui/inference/hint-closure-signature-119266.rs
@@ -3,7 +3,7 @@ fn main() {
     //~^ NOTE: the found closure
 
     let x: fn(i32) = x;
-    //~^ ERROR: 5:22: 5:23: mismatched types [E0308]
+    //~^ ERROR: mismatched types [E0308]
     //~| NOTE: incorrect number of function parameters
     //~| NOTE: expected due to this
     //~| NOTE: expected fn pointer `fn(i32)`
diff --git a/tests/ui/integral-indexing.rs b/tests/ui/integral-indexing.rs
index f076dfcb0a4..e20553af8a2 100644
--- a/tests/ui/integral-indexing.rs
+++ b/tests/ui/integral-indexing.rs
@@ -3,14 +3,14 @@ pub fn main() {
     let s: String = "abcdef".to_string();
     v[3_usize];
     v[3];
-    v[3u8];  //~ERROR : the type `[isize]` cannot be indexed by `u8`
-    v[3i8];  //~ERROR : the type `[isize]` cannot be indexed by `i8`
-    v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32`
-    v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32`
+    v[3u8];  //~ ERROR the type `[isize]` cannot be indexed by `u8`
+    v[3i8];  //~ ERROR the type `[isize]` cannot be indexed by `i8`
+    v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32`
+    v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32`
     s.as_bytes()[3_usize];
     s.as_bytes()[3];
-    s.as_bytes()[3u8];  //~ERROR : the type `[u8]` cannot be indexed by `u8`
-    s.as_bytes()[3i8];  //~ERROR : the type `[u8]` cannot be indexed by `i8`
-    s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u32`
-    s.as_bytes()[3i32]; //~ERROR : the type `[u8]` cannot be indexed by `i32`
+    s.as_bytes()[3u8];  //~ ERROR the type `[u8]` cannot be indexed by `u8`
+    s.as_bytes()[3i8];  //~ ERROR the type `[u8]` cannot be indexed by `i8`
+    s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32`
+    s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32`
 }
diff --git a/tests/ui/issues/issue-32950.rs b/tests/ui/issues/issue-32950.rs
deleted file mode 100644
index b51ac296776..00000000000
--- a/tests/ui/issues/issue-32950.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(concat_idents)]
-#![expect(deprecated)] // concat_idents is deprecated
-
-#[derive(Debug)]
-struct Baz<T>(
-    concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros
-                             //~^ ERROR cannot find type `FooBar` in this scope
-);
-
-fn main() {}
diff --git a/tests/ui/issues/issue-32950.stderr b/tests/ui/issues/issue-32950.stderr
deleted file mode 100644
index 38a82542f89..00000000000
--- a/tests/ui/issues/issue-32950.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: `derive` cannot be used on items with type macros
-  --> $DIR/issue-32950.rs:6:5
-   |
-LL |     concat_idents!(Foo, Bar)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0412]: cannot find type `FooBar` in this scope
-  --> $DIR/issue-32950.rs:6:5
-   |
-LL |     concat_idents!(Foo, Bar)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/issues/issue-50403.rs b/tests/ui/issues/issue-50403.rs
deleted file mode 100644
index f14958afc34..00000000000
--- a/tests/ui/issues/issue-50403.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(concat_idents)]
-#![expect(deprecated)] // concat_idents is deprecated
-
-fn main() {
-    let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments
-}
diff --git a/tests/ui/issues/issue-50403.stderr b/tests/ui/issues/issue-50403.stderr
deleted file mode 100644
index e7dd05bb018..00000000000
--- a/tests/ui/issues/issue-50403.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `concat_idents!()` takes 1 or more arguments
-  --> $DIR/issue-50403.rs:5:13
-   |
-LL |     let x = concat_idents!();
-   |             ^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/issues/issue-92741.rs b/tests/ui/issues/issue-92741.rs
index f2e5fdafd9c..1c5d5810a57 100644
--- a/tests/ui/issues/issue-92741.rs
+++ b/tests/ui/issues/issue-92741.rs
@@ -1,17 +1,17 @@
 //@ run-rustfix
 fn main() {}
 fn _foo() -> bool {
-    &  //~ ERROR 4:5: 6:36: mismatched types [E0308]
+    &  //~ ERROR mismatched types [E0308]
     mut
     if true { true } else { false }
 }
 
 fn _bar() -> bool {
-    &  //~ ERROR 10:5: 11:40: mismatched types [E0308]
+    &  //~ ERROR mismatched types [E0308]
     mut if true { true } else { false }
 }
 
 fn _baz() -> bool {
-    & mut //~ ERROR 15:5: 16:36: mismatched types [E0308]
+    & mut //~ ERROR mismatched types [E0308]
     if true { true } else { false }
 }
diff --git a/tests/ui/lifetimes/no_lending_iterators.rs b/tests/ui/lifetimes/no_lending_iterators.rs
index b3e8ad08ba1..88b8cda0898 100644
--- a/tests/ui/lifetimes/no_lending_iterators.rs
+++ b/tests/ui/lifetimes/no_lending_iterators.rs
@@ -2,7 +2,7 @@ struct Data(String);
 
 impl Iterator for Data {
     type Item = &str;
-    //~^ ERROR 4:17: 4:18: associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
+    //~^ ERROR associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
 
     fn next(&mut self) -> Option<Self::Item> {
         Some(&self.0)
@@ -16,7 +16,7 @@ trait Bar {
 
 impl Bar for usize {
     type Item = &usize;
-    //~^ ERROR 18:17: 18:18: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
+    //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
 
     fn poke(&mut self, item: Self::Item) {
         self += *item;
@@ -25,7 +25,7 @@ impl Bar for usize {
 
 impl Bar for isize {
     type Item<'a> = &'a isize;
-    //~^ ERROR 27:14: 27:18: lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195]
+    //~^ ERROR lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195]
 
     fn poke(&mut self, item: Self::Item) {
         self += *item;
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
index 9babc20d1a1..9ccc9ce4fdb 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
@@ -11,7 +11,7 @@ extern crate minicore;
 
 #[link(name = "foo", kind = "raw-dylib")]
 extern "stdcall" {
-//~^ WARN: calling convention not supported on this target
+//~^ WARN: unsupported_calling_conventions
 //~| WARN: previously accepted
     fn f(x: i32);
     //~^ ERROR ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
index 95ea9080486..91e42f2909e 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
@@ -1,4 +1,4 @@
-warning: use of calling convention not supported on this target
+warning: "stdcall" is not a supported ABI for the current target
   --> $DIR/unsupported-abi.rs:13:1
    |
 LL | / extern "stdcall" {
diff --git a/tests/ui/lint/lint-non-uppercase-usages.fixed b/tests/ui/lint/lint-non-uppercase-usages.fixed
new file mode 100644
index 00000000000..231991dcae0
--- /dev/null
+++ b/tests/ui/lint/lint-non-uppercase-usages.fixed
@@ -0,0 +1,44 @@
+// Checks that the `non_upper_case_globals` emits suggestions for usages as well
+// <https://github.com/rust-lang/rust/issues/124061>
+
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)]
+
+use std::cell::Cell;
+
+const MY_STATIC: u32 = 0;
+//~^ WARN constant `my_static` should have an upper case name
+//~| SUGGESTION MY_STATIC
+
+const LOL: u32 = MY_STATIC + 0;
+//~^ SUGGESTION MY_STATIC
+
+mod my_mod {
+    const INSIDE_MOD: u32 = super::MY_STATIC + 0;
+    //~^ SUGGESTION MY_STATIC
+}
+
+thread_local! {
+    static FOO_FOO: Cell<usize> = unreachable!();
+    //~^ WARN constant `fooFOO` should have an upper case name
+    //~| SUGGESTION FOO_FOO
+}
+
+fn foo<const FOO: u32>() {
+    //~^ WARN const parameter `foo` should have an upper case name
+    //~| SUGGESTION FOO
+    let _a = FOO + 1;
+    //~^ SUGGESTION FOO
+}
+
+fn main() {
+    let _a = crate::MY_STATIC;
+    //~^ SUGGESTION MY_STATIC
+
+    FOO_FOO.set(9);
+    //~^ SUGGESTION FOO_FOO
+    println!("{}", FOO_FOO.get());
+    //~^ SUGGESTION FOO_FOO
+}
diff --git a/tests/ui/lint/lint-non-uppercase-usages.rs b/tests/ui/lint/lint-non-uppercase-usages.rs
new file mode 100644
index 00000000000..9cdf5e47003
--- /dev/null
+++ b/tests/ui/lint/lint-non-uppercase-usages.rs
@@ -0,0 +1,44 @@
+// Checks that the `non_upper_case_globals` emits suggestions for usages as well
+// <https://github.com/rust-lang/rust/issues/124061>
+
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)]
+
+use std::cell::Cell;
+
+const my_static: u32 = 0;
+//~^ WARN constant `my_static` should have an upper case name
+//~| SUGGESTION MY_STATIC
+
+const LOL: u32 = my_static + 0;
+//~^ SUGGESTION MY_STATIC
+
+mod my_mod {
+    const INSIDE_MOD: u32 = super::my_static + 0;
+    //~^ SUGGESTION MY_STATIC
+}
+
+thread_local! {
+    static fooFOO: Cell<usize> = unreachable!();
+    //~^ WARN constant `fooFOO` should have an upper case name
+    //~| SUGGESTION FOO_FOO
+}
+
+fn foo<const foo: u32>() {
+    //~^ WARN const parameter `foo` should have an upper case name
+    //~| SUGGESTION FOO
+    let _a = foo + 1;
+    //~^ SUGGESTION FOO
+}
+
+fn main() {
+    let _a = crate::my_static;
+    //~^ SUGGESTION MY_STATIC
+
+    fooFOO.set(9);
+    //~^ SUGGESTION FOO_FOO
+    println!("{}", fooFOO.get());
+    //~^ SUGGESTION FOO_FOO
+}
diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr
new file mode 100644
index 00000000000..7c7e573a88e
--- /dev/null
+++ b/tests/ui/lint/lint-non-uppercase-usages.stderr
@@ -0,0 +1,39 @@
+warning: constant `my_static` should have an upper case name
+  --> $DIR/lint-non-uppercase-usages.rs:11:7
+   |
+LL | const my_static: u32 = 0;
+   |       ^^^^^^^^^
+   |
+   = note: `#[warn(non_upper_case_globals)]` on by default
+help: convert the identifier to upper case
+   |
+LL - const my_static: u32 = 0;
+LL + const MY_STATIC: u32 = 0;
+   |
+
+warning: constant `fooFOO` should have an upper case name
+  --> $DIR/lint-non-uppercase-usages.rs:24:12
+   |
+LL |     static fooFOO: Cell<usize> = unreachable!();
+   |            ^^^^^^
+   |
+help: convert the identifier to upper case
+   |
+LL -     static fooFOO: Cell<usize> = unreachable!();
+LL +     static FOO_FOO: Cell<usize> = unreachable!();
+   |
+
+warning: const parameter `foo` should have an upper case name
+  --> $DIR/lint-non-uppercase-usages.rs:29:14
+   |
+LL | fn foo<const foo: u32>() {
+   |              ^^^
+   |
+help: convert the identifier to upper case (notice the capitalization difference)
+   |
+LL - fn foo<const foo: u32>() {
+LL + fn foo<const FOO: u32>() {
+   |
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/macros/macro-comma-support-rpass.rs b/tests/ui/macros/macro-comma-support-rpass.rs
index 5a4bac70b1c..ef6c1ff6fd0 100644
--- a/tests/ui/macros/macro-comma-support-rpass.rs
+++ b/tests/ui/macros/macro-comma-support-rpass.rs
@@ -15,7 +15,6 @@
 #![cfg_attr(core, no_std)]
 
 #![allow(deprecated)] // for deprecated `try!()` macro
-#![feature(concat_idents)]
 
 #[cfg(std)] use std::fmt;
 #[cfg(core)] use core::fmt;
@@ -80,17 +79,6 @@ fn concat() {
 }
 
 #[test]
-fn concat_idents() {
-    fn foo() {}
-    fn foobar() {}
-
-    concat_idents!(foo)();
-    concat_idents!(foo,)();
-    concat_idents!(foo, bar)();
-    concat_idents!(foo, bar,)();
-}
-
-#[test]
 fn debug_assert() {
     debug_assert!(true);
     debug_assert!(true, );
diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs
index fa2af945a1f..1643cddb192 100644
--- a/tests/ui/macros/macro-match-nonterminal.rs
+++ b/tests/ui/macros/macro-match-nonterminal.rs
@@ -2,11 +2,10 @@ macro_rules! test {
     ($a, $b) => {
         //~^ ERROR missing fragment
         //~| ERROR missing fragment
-        //~| ERROR missing fragment
         ()
     };
 }
 
 fn main() {
-    test!()
+    test!() //~ ERROR unexpected end of macro invocation
 }
diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr
index 8196d795c4c..a92d099ca00 100644
--- a/tests/ui/macros/macro-match-nonterminal.stderr
+++ b/tests/ui/macros/macro-match-nonterminal.stderr
@@ -24,7 +24,16 @@ help: try adding a specifier here
 LL |     ($a, $b:spec) => {
    |            +++++
 
-error: missing fragment specifier
+error: unexpected end of macro invocation
+  --> $DIR/macro-match-nonterminal.rs:10:5
+   |
+LL | macro_rules! test {
+   | ----------------- when calling this macro
+...
+LL |     test!()
+   |     ^^^^^^^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$a:tt`
   --> $DIR/macro-match-nonterminal.rs:2:6
    |
 LL |     ($a, $b) => {
diff --git a/tests/ui/macros/macro-metavar-expr-concat/empty-input.rs b/tests/ui/macros/macro-metavar-expr-concat/empty-input.rs
new file mode 100644
index 00000000000..caad63c5f6b
--- /dev/null
+++ b/tests/ui/macros/macro-metavar-expr-concat/empty-input.rs
@@ -0,0 +1,12 @@
+// Issue 50403
+// Ensure that `concat` can't create empty identifiers
+// FIXME(macro_metavar_expr_concat): this error message could be improved
+
+macro_rules! empty {
+    () => { ${concat()} } //~ ERROR expected identifier or string literal
+                          //~^ERROR expected expression
+}
+
+fn main() {
+    let x = empty!();
+}
diff --git a/tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr b/tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr
new file mode 100644
index 00000000000..e95032dd247
--- /dev/null
+++ b/tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr
@@ -0,0 +1,19 @@
+error: expected identifier or string literal
+  --> $DIR/empty-input.rs:6:14
+   |
+LL |     () => { ${concat()} }
+   |              ^^^^^^^^^^
+
+error: expected expression, found `$`
+  --> $DIR/empty-input.rs:6:13
+   |
+LL |     () => { ${concat()} }
+   |             ^ expected expression
+...
+LL |     let x = empty!();
+   |             -------- in this macro invocation
+   |
+   = note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs
index 481f08fa111..fc81c713b4d 100644
--- a/tests/ui/macros/macro-missing-fragment-deduplication.rs
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs
@@ -2,12 +2,11 @@
 
 macro_rules! m {
     ($name) => {}; //~ ERROR missing fragment
-                   //~| ERROR missing fragment
 }
 
 fn main() {
-    m!();
-    m!();
-    m!();
-    m!();
+    m!(); //~ ERROR unexpected end
+    m!(); //~ ERROR unexpected end
+    m!(); //~ ERROR unexpected end
+    m!(); //~ ERROR unexpected end
 }
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
index 820f7eb3cf7..29d2ae0e16e 100644
--- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
@@ -11,11 +11,65 @@ help: try adding a specifier here
 LL |     ($name:spec) => {};
    |           +++++
 
-error: missing fragment specifier
+error: unexpected end of macro invocation
+  --> $DIR/macro-missing-fragment-deduplication.rs:8:5
+   |
+LL | macro_rules! m {
+   | -------------- when calling this macro
+...
+LL |     m!();
+   |     ^^^^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$name:tt`
+  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
+   |
+LL |     ($name) => {};
+   |      ^^^^^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-missing-fragment-deduplication.rs:9:5
+   |
+LL | macro_rules! m {
+   | -------------- when calling this macro
+...
+LL |     m!();
+   |     ^^^^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$name:tt`
+  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
+   |
+LL |     ($name) => {};
+   |      ^^^^^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-missing-fragment-deduplication.rs:10:5
+   |
+LL | macro_rules! m {
+   | -------------- when calling this macro
+...
+LL |     m!();
+   |     ^^^^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$name:tt`
+  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
+   |
+LL |     ($name) => {};
+   |      ^^^^^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-missing-fragment-deduplication.rs:11:5
+   |
+LL | macro_rules! m {
+   | -------------- when calling this macro
+...
+LL |     m!();
+   |     ^^^^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$name:tt`
   --> $DIR/macro-missing-fragment-deduplication.rs:4:6
    |
 LL |     ($name) => {};
    |      ^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs
index 533aa147bcb..7ed9074020e 100644
--- a/tests/ui/macros/macro-missing-fragment.rs
+++ b/tests/ui/macros/macro-missing-fragment.rs
@@ -2,7 +2,6 @@
 
 macro_rules! used_arm {
     ( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment
-                                                //~| ERROR missing fragment
 }
 
 macro_rules! used_macro_unused_arm {
diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.stderr
index 4a99d7d949c..886292378d1 100644
--- a/tests/ui/macros/macro-missing-fragment.stderr
+++ b/tests/ui/macros/macro-missing-fragment.stderr
@@ -12,7 +12,7 @@ LL |     ( $( any_token $field_rust_type:spec )* ) => {};
    |                                    +++++
 
 error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:10:7
+  --> $DIR/macro-missing-fragment.rs:9:7
    |
 LL |     ( $name ) => {};
    |       ^^^^^
@@ -25,7 +25,7 @@ LL |     ( $name:spec ) => {};
    |            +++++
 
 error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:14:7
+  --> $DIR/macro-missing-fragment.rs:13:7
    |
 LL |     ( $name ) => {};
    |       ^^^^^
@@ -37,11 +37,5 @@ help: try adding a specifier here
 LL |     ( $name:spec ) => {};
    |            +++++
 
-error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:4:20
-   |
-LL |     ( $( any_token $field_rust_type )* ) => {};
-   |                    ^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/macros/macro-reexport-removed.rs b/tests/ui/macros/macro-reexport-removed.rs
index c1267f14cd8..4a054686d77 100644
--- a/tests/ui/macros/macro-reexport-removed.rs
+++ b/tests/ui/macros/macro-reexport-removed.rs
@@ -1,5 +1,4 @@
 //@ aux-build:two_macros.rs
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 
 #![feature(macro_reexport)] //~ ERROR feature has been removed
 
diff --git a/tests/ui/macros/macro-reexport-removed.stderr b/tests/ui/macros/macro-reexport-removed.stderr
index d4940eeb775..8130fe0c4bd 100644
--- a/tests/ui/macros/macro-reexport-removed.stderr
+++ b/tests/ui/macros/macro-reexport-removed.stderr
@@ -1,14 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/macro-reexport-removed.rs:4:12
+  --> $DIR/macro-reexport-removed.rs:3:12
    |
 LL | #![feature(macro_reexport)]
    |            ^^^^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.0.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/49982> for more information
+   = note: removed in 1.0.0; see <https://github.com/rust-lang/rust/pull/49982> for more information
    = note: subsumed by `pub use`
 
 error: cannot find attribute `macro_reexport` in this scope
-  --> $DIR/macro-reexport-removed.rs:6:3
+  --> $DIR/macro-reexport-removed.rs:5:3
    |
 LL | #[macro_reexport(macro_one)]
    |   ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export`
diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs
index 091d64ea5d9..1349d741510 100644
--- a/tests/ui/macros/macros-nonfatal-errors.rs
+++ b/tests/ui/macros/macros-nonfatal-errors.rs
@@ -3,9 +3,8 @@
 // test that errors in a (selection) of macros don't kill compilation
 // immediately, so that we get more errors listed at a time.
 
-#![feature(trace_macros, concat_idents)]
+#![feature(trace_macros)]
 #![feature(stmt_expr_attributes)]
-#![expect(deprecated)] // concat_idents is deprecated
 
 use std::arch::asm;
 
@@ -105,8 +104,6 @@ fn main() {
     asm!(invalid); //~ ERROR
     llvm_asm!(invalid); //~ ERROR
 
-    concat_idents!("not", "idents"); //~ ERROR
-
     option_env!(invalid); //~ ERROR
     env!(invalid); //~ ERROR
     env!(foo, abr, baz); //~ ERROR
diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr
index 2f990cb24e2..bc34bd1c8ec 100644
--- a/tests/ui/macros/macros-nonfatal-errors.stderr
+++ b/tests/ui/macros/macros-nonfatal-errors.stderr
@@ -1,5 +1,5 @@
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:14:5
+  --> $DIR/macros-nonfatal-errors.rs:13:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[default]
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:19:36
+  --> $DIR/macros-nonfatal-errors.rs:18:36
    |
 LL | struct DefaultInnerAttrTupleStruct(#[default] ());
    |                                    ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | struct DefaultInnerAttrTupleStruct(#[default] ());
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:23:1
+  --> $DIR/macros-nonfatal-errors.rs:22:1
    |
 LL | #[default]
    | ^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[default]
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:27:1
+  --> $DIR/macros-nonfatal-errors.rs:26:1
    |
 LL | #[default]
    | ^^^^^^^^^^
@@ -31,7 +31,7 @@ LL | #[default]
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:37:11
+  --> $DIR/macros-nonfatal-errors.rs:36:11
    |
 LL |     Foo = #[default] 0,
    |           ^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     Foo = #[default] 0,
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:38:14
+  --> $DIR/macros-nonfatal-errors.rs:37:14
    |
 LL |     Bar([u8; #[default] 1]),
    |              ^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |     Bar([u8; #[default] 1]),
    = help: consider a manual implementation of `Default`
 
 error[E0665]: `#[derive(Default)]` on enum with no `#[default]`
-  --> $DIR/macros-nonfatal-errors.rs:43:10
+  --> $DIR/macros-nonfatal-errors.rs:42:10
    |
 LL |   #[derive(Default)]
    |            ^^^^^^^
@@ -67,7 +67,7 @@ LL |     #[default] Bar,
    |     ++++++++++
 
 error[E0665]: `#[derive(Default)]` on enum with no `#[default]`
-  --> $DIR/macros-nonfatal-errors.rs:49:10
+  --> $DIR/macros-nonfatal-errors.rs:48:10
    |
 LL |   #[derive(Default)]
    |            ^^^^^^^
@@ -78,7 +78,7 @@ LL | | }
    | |_- this enum needs a unit variant marked with `#[default]`
 
 error: multiple declared defaults
-  --> $DIR/macros-nonfatal-errors.rs:55:10
+  --> $DIR/macros-nonfatal-errors.rs:54:10
    |
 LL | #[derive(Default)]
    |          ^^^^^^^
@@ -95,7 +95,7 @@ LL |     Baz,
    = note: only one variant can be default
 
 error: `#[default]` attribute does not accept a value
-  --> $DIR/macros-nonfatal-errors.rs:67:5
+  --> $DIR/macros-nonfatal-errors.rs:66:5
    |
 LL |     #[default = 1]
    |     ^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL |     #[default = 1]
    = help: try using `#[default]`
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:75:5
+  --> $DIR/macros-nonfatal-errors.rs:74:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -114,13 +114,13 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing this
-  --> $DIR/macros-nonfatal-errors.rs:74:5
+  --> $DIR/macros-nonfatal-errors.rs:73:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:85:5
+  --> $DIR/macros-nonfatal-errors.rs:84:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -132,7 +132,7 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing these
-  --> $DIR/macros-nonfatal-errors.rs:82:5
+  --> $DIR/macros-nonfatal-errors.rs:81:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
@@ -142,7 +142,7 @@ LL |     #[default]
    |     ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:92:5
+  --> $DIR/macros-nonfatal-errors.rs:91:5
    |
 LL |     Foo {},
    |     ^^^
@@ -150,7 +150,7 @@ LL |     Foo {},
    = help: consider a manual implementation of `Default`
 
 error: default variant must be exhaustive
-  --> $DIR/macros-nonfatal-errors.rs:100:5
+  --> $DIR/macros-nonfatal-errors.rs:99:5
    |
 LL |     #[non_exhaustive]
    |     ----------------- declared `#[non_exhaustive]` here
@@ -160,37 +160,31 @@ LL |     Foo,
    = help: consider a manual implementation of `Default`
 
 error: asm template must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:105:10
+  --> $DIR/macros-nonfatal-errors.rs:104:10
    |
 LL |     asm!(invalid);
    |          ^^^^^^^
 
-error: `concat_idents!()` requires ident args
-  --> $DIR/macros-nonfatal-errors.rs:108:5
-   |
-LL |     concat_idents!("not", "idents");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:110:17
+  --> $DIR/macros-nonfatal-errors.rs:107:17
    |
 LL |     option_env!(invalid);
    |                 ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:111:10
+  --> $DIR/macros-nonfatal-errors.rs:108:10
    |
 LL |     env!(invalid);
    |          ^^^^^^^
 
 error: `env!()` takes 1 or 2 arguments
-  --> $DIR/macros-nonfatal-errors.rs:112:5
+  --> $DIR/macros-nonfatal-errors.rs:109:5
    |
 LL |     env!(foo, abr, baz);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time
-  --> $DIR/macros-nonfatal-errors.rs:113:5
+  --> $DIR/macros-nonfatal-errors.rs:110:5
    |
 LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +192,7 @@ LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    = help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time
 
 error: format argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:115:13
+  --> $DIR/macros-nonfatal-errors.rs:112:13
    |
 LL |     format!(invalid);
    |             ^^^^^^^
@@ -209,43 +203,43 @@ LL |     format!("{}", invalid);
    |             +++++
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:117:14
+  --> $DIR/macros-nonfatal-errors.rs:114:14
    |
 LL |     include!(invalid);
    |              ^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:119:18
+  --> $DIR/macros-nonfatal-errors.rs:116:18
    |
 LL |     include_str!(invalid);
    |                  ^^^^^^^
 
 error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG
-  --> $DIR/macros-nonfatal-errors.rs:120:5
+  --> $DIR/macros-nonfatal-errors.rs:117:5
    |
 LL |     include_str!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:121:20
+  --> $DIR/macros-nonfatal-errors.rs:118:20
    |
 LL |     include_bytes!(invalid);
    |                    ^^^^^^^
 
 error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG
-  --> $DIR/macros-nonfatal-errors.rs:122:5
+  --> $DIR/macros-nonfatal-errors.rs:119:5
    |
 LL |     include_bytes!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: trace_macros! accepts only `true` or `false`
-  --> $DIR/macros-nonfatal-errors.rs:124:5
+  --> $DIR/macros-nonfatal-errors.rs:121:5
    |
 LL |     trace_macros!(invalid);
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: default variant must be exhaustive
-  --> $DIR/macros-nonfatal-errors.rs:134:9
+  --> $DIR/macros-nonfatal-errors.rs:131:9
    |
 LL |         #[non_exhaustive]
    |         ----------------- declared `#[non_exhaustive]` here
@@ -255,11 +249,11 @@ LL |         Foo,
    = help: consider a manual implementation of `Default`
 
 error: cannot find macro `llvm_asm` in this scope
-  --> $DIR/macros-nonfatal-errors.rs:106:5
+  --> $DIR/macros-nonfatal-errors.rs:105:5
    |
 LL |     llvm_asm!(invalid);
    |     ^^^^^^^^
 
-error: aborting due to 29 previous errors
+error: aborting due to 28 previous errors
 
 For more information about this error, try `rustc --explain E0665`.
diff --git a/tests/ui/macros/missing-writer-issue-139830.rs b/tests/ui/macros/missing-writer-issue-139830.rs
new file mode 100644
index 00000000000..da4608776c3
--- /dev/null
+++ b/tests/ui/macros/missing-writer-issue-139830.rs
@@ -0,0 +1,9 @@
+// Make sure we don't suggest a method change inside the `write!` macro.
+//
+// See <https://github.com/rust-lang/rust/issues/139830>
+
+fn main() {
+    let mut buf = String::new();
+    let _ = write!(buf, "foo");
+    //~^ ERROR cannot write into `String`
+}
diff --git a/tests/ui/macros/missing-writer-issue-139830.stderr b/tests/ui/macros/missing-writer-issue-139830.stderr
new file mode 100644
index 00000000000..34dd61328e0
--- /dev/null
+++ b/tests/ui/macros/missing-writer-issue-139830.stderr
@@ -0,0 +1,23 @@
+error[E0599]: cannot write into `String`
+  --> $DIR/missing-writer-issue-139830.rs:7:20
+   |
+LL |     let _ = write!(buf, "foo");
+   |                    ^^^
+  --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+   |
+   = note: the method is available for `String` here
+   |
+note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
+  --> $DIR/missing-writer-issue-139830.rs:7:20
+   |
+LL |     let _ = write!(buf, "foo");
+   |                    ^^^
+   = help: items from traits can only be used if the trait is in scope
+help: trait `Write` which provides `write_fmt` is implemented but not in scope; perhaps you want to import it
+   |
+LL + use std::fmt::Write;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs
index f589e88f68e..0632b822c55 100644
--- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs
+++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs
@@ -2,17 +2,17 @@
 #![crate_type = "lib"]
 
 pub fn foo(arg: Option<&Vec<i32>>) -> Option<&[i32]> {
-    arg //~ ERROR 5:5: 5:8: mismatched types [E0308]
+    arg //~ ERROR mismatched types [E0308]
 }
 
 pub fn bar(arg: Option<&Vec<i32>>) -> &[i32] {
-    arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308]
+    arg.unwrap_or(&[]) //~ ERROR mismatched types [E0308]
 }
 
 pub fn barzz<'a>(arg: Option<&'a Vec<i32>>, v: &'a [i32]) -> &'a [i32] {
-    arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308]
+    arg.unwrap_or(v) //~ ERROR mismatched types [E0308]
 }
 
 pub fn convert_result(arg: Result<&Vec<i32>, ()>) -> &[i32] {
-    arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308]
+    arg.unwrap_or(&[]) //~ ERROR mismatched types [E0308]
 }
diff --git a/tests/ui/parser/macro/issue-33569.rs b/tests/ui/parser/macro/issue-33569.rs
index e0a5352ab06..7288fa858db 100644
--- a/tests/ui/parser/macro/issue-33569.rs
+++ b/tests/ui/parser/macro/issue-33569.rs
@@ -1,11 +1,10 @@
 macro_rules! foo {
     { $+ } => { //~ ERROR expected identifier, found `+`
                 //~^ ERROR missing fragment specifier
-                //~| ERROR missing fragment specifier
         $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
     }
 }
 
-foo!();
+foo!(); //~ ERROR unexpected end
 
 fn main() {}
diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr
index 0d53c04c1c9..dd8e38f0d6e 100644
--- a/tests/ui/parser/macro/issue-33569.stderr
+++ b/tests/ui/parser/macro/issue-33569.stderr
@@ -4,12 +4,6 @@ error: expected identifier, found `+`
 LL |     { $+ } => {
    |        ^
 
-error: expected one of: `*`, `+`, or `?`
-  --> $DIR/issue-33569.rs:5:13
-   |
-LL |         $(x)(y)
-   |             ^^^
-
 error: missing fragment specifier
   --> $DIR/issue-33569.rs:2:8
    |
@@ -23,7 +17,22 @@ help: try adding a specifier here
 LL |     { $+:spec } => {
    |         +++++
 
-error: missing fragment specifier
+error: expected one of: `*`, `+`, or `?`
+  --> $DIR/issue-33569.rs:4:13
+   |
+LL |         $(x)(y)
+   |             ^^^
+
+error: unexpected end of macro invocation
+  --> $DIR/issue-33569.rs:8:1
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL | foo!();
+   | ^^^^^^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$<!dummy!>:tt`
   --> $DIR/issue-33569.rs:2:8
    |
 LL |     { $+ } => {
diff --git a/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr
new file mode 100644
index 00000000000..cc438461a5d
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr
@@ -0,0 +1,238 @@
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:39:14
+   |
+LL |     let foo = Foo::default();
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo);
+   |                          --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo);
+   |                          --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:43:14
+   |
+LL |     let foo = Foo::default();
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo;
+   |                      --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo;
+   |                      --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:52:14
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:56:14
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:68:14
+   |
+LL |     let foo = Foo::default();
+   |         --- binding `foo` declared here
+LL |     let x = &pin const foo; // ok
+   |             -------------- borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin const foo; // ok
+   |                        --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:76:13
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_ref(&foo);
+   |             ^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:80:13
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_ref(&foo);
+   |             ^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:99:26
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_pin_mut(&pin mut foo);
+   |                          ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:103:26
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_pin_mut(&pin mut foo);
+   |                          ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:115:26
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- binding `foo` declared here
+LL |     let x = &pin const foo; // ok
+   |             -------------- borrow of `foo` occurs here
+LL |     foo_pin_mut(&pin mut foo);
+   |                          ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin const foo; // ok
+   |                        --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:123:17
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:127:17
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0382, E0505.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pin-ergonomics/borrow-unpin.rs b/tests/ui/pin-ergonomics/borrow-unpin.rs
new file mode 100644
index 00000000000..61e69bab12b
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow-unpin.rs
@@ -0,0 +1,143 @@
+//@ revisions: unpin pinned
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+// For now, in order to ensure soundness, we move the place in `&pin mut place`
+// if `place` is not `Unpin`.
+// In the next step, we borrow the place instead of moving it, after that we
+// have to makes sure `&pin mut place` and `&pin const place` cannot violate
+// the mut-xor-share rules.
+
+use std::pin::Pin;
+use std::marker::PhantomPinned;
+
+#[cfg(pinned)]
+#[derive(Default)]
+struct Foo(PhantomPinned);
+
+#[cfg(unpin)]
+#[derive(Default)]
+struct Foo;
+
+fn foo_mut(_: &mut Foo) {
+}
+
+fn foo_ref(_: &Foo) {
+}
+
+fn foo_pin_mut(_: Pin<&mut Foo>) {
+}
+
+fn foo_pin_ref(_: Pin<&Foo>) {
+}
+
+fn foo_move(_: Foo) {}
+
+fn immutable_pin_mut_then_move() {
+    let foo = Foo::default();
+    foo_pin_mut(&pin mut foo); //[unpin]~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+
+    let foo = Foo::default();
+    let x = &pin mut foo; //[unpin]~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+    //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed
+    foo_pin_mut(x); //
+}
+
+
+fn pin_mut_then_move() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+    //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed
+    foo_pin_mut(x); //
+}
+
+fn pin_ref_then_move() {
+    let foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_move(foo); // ok
+
+    let foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_move(foo); //[pinned]~ ERROR cannot move out of `foo` because it is borrowed
+    //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed
+    foo_pin_ref(x);
+}
+
+fn pin_mut_then_ref() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_ref(&foo); //[pinned]~ ERROR borrow of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_ref(&foo); //[pinned]~ ERROR borrow of moved value: `foo`
+    //[unpin]~^ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_pin_mut(x);
+}
+
+fn pin_ref_then_ref() {
+    let mut foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_ref(&foo); // ok
+
+    let mut foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_ref(&foo); // ok
+    foo_pin_ref(x);
+}
+
+fn pin_mut_then_pin_mut() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_pin_mut(&pin mut foo); //[pinned]~ ERROR use of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_pin_mut(&pin mut foo); //[pinned]~ ERROR use of moved value: `foo`
+    //[unpin]~^ ERROR cannot borrow `foo` as mutable more than once at a time
+    foo_pin_mut(x);
+}
+
+fn pin_ref_then_pin_mut() {
+    let mut foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_mut(&pin mut foo); // ok
+
+    let mut foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_pin_mut(&pin mut foo); //[pinned]~ ERROR cannot move out of `foo` because it is borrowed
+    //[unpin]~^ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
+    foo_pin_ref(x);
+}
+
+fn pin_mut_then_pin_ref() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_pin_ref(&pin const foo); //[pinned]~ ERROR borrow of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_pin_ref(&pin const foo); //[pinned]~ ERROR borrow of moved value: `foo`
+    //[unpin]~^ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_pin_mut(x);
+}
+
+fn pin_ref_then_pin_ref() {
+    let mut foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_ref(&pin const foo); // ok
+
+    let mut foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_ref(x);
+}
+
+fn main() {}
diff --git a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr
new file mode 100644
index 00000000000..bf9921343ee
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr
@@ -0,0 +1,136 @@
+error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-unpin.rs:38:17
+   |
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = Foo::default();
+   |         +++
+
+error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-unpin.rs:42:13
+   |
+LL |     let x = &pin mut foo;
+   |             ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = Foo::default();
+   |         +++
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:43:14
+   |
+LL |     let foo = Foo::default();
+   |         --- binding `foo` declared here
+LL |     let x = &pin mut foo;
+   |             ------------ borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_mut(x); //
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:20:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo;
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:56:14
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- binding `foo` declared here
+LL |     let x = &pin mut foo; // ok
+   |             ------------ borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_mut(x); //
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:20:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:68:14
+   |
+LL |     let foo = Foo::default();
+   |         --- binding `foo` declared here
+LL |     let x = &pin const foo; // ok
+   |             -------------- borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:20:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin const foo; // ok
+   |                        --- you could clone this value
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-unpin.rs:80:13
+   |
+LL |     let x = &pin mut foo; // ok
+   |             ------------ mutable borrow occurs here
+LL |     foo_ref(&foo);
+   |             ^^^^ immutable borrow occurs here
+LL |
+LL |     foo_pin_mut(x);
+   |                 - mutable borrow later used here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/borrow-unpin.rs:103:17
+   |
+LL |     let x = &pin mut foo; // ok
+   |             ------------ first mutable borrow occurs here
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL |     foo_pin_mut(x);
+   |                 - first borrow later used here
+
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-unpin.rs:115:17
+   |
+LL |     let x = &pin const foo; // ok
+   |             -------------- immutable borrow occurs here
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - immutable borrow later used here
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-unpin.rs:127:17
+   |
+LL |     let x = &pin mut foo; // ok
+   |             ------------ mutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ immutable borrow occurs here
+LL |
+LL |     foo_pin_mut(x);
+   |                 - mutable borrow later used here
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0505, E0596.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/pin-ergonomics/borrow.rs b/tests/ui/pin-ergonomics/borrow.rs
new file mode 100644
index 00000000000..f221165848b
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow.rs
@@ -0,0 +1,38 @@
+//@ check-pass
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+// Makes sure we can handle `&pin mut place` and `&pin const place` as sugar for
+// `std::pin::pin!(place)` and `Pin::new(&place)`.
+
+use std::pin::Pin;
+
+struct Foo;
+
+fn foo_pin_mut(_: Pin<&mut Foo>) {
+}
+
+fn foo_pin_ref(_: Pin<&Foo>) {
+}
+
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo_pin_mut(x.as_mut());
+    foo_pin_mut(x.as_mut());
+    foo_pin_ref(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_pin_ref(x);
+    foo_pin_ref(x);
+}
+
+fn baz(mut x: Foo, y: Foo) {
+    let _x = &pin mut x;
+    let _x = x; // ok because `Foo: Unpin` and thus `&pin mut x` doesn't move `x`
+
+    let _y = &pin const y;
+    let _y = y; // ok because `&pin const y` dosn't move `y`
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.rs b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs
index a95665f126d..a95665f126d 100644
--- a/tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.rs
+++ b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs
diff --git a/tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.stderr b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr
index 2deb5b09884..2deb5b09884 100644
--- a/tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.stderr
+++ b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-arg.rs b/tests/ui/pin-ergonomics/reborrow-arg.rs
index 2008bd1f52d..2008bd1f52d 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-arg.rs
+++ b/tests/ui/pin-ergonomics/reborrow-arg.rs
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.rs b/tests/ui/pin-ergonomics/reborrow-const-as-mut.rs
index 27c70a7b4df..27c70a7b4df 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.rs
+++ b/tests/ui/pin-ergonomics/reborrow-const-as-mut.rs
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.stderr b/tests/ui/pin-ergonomics/reborrow-const-as-mut.stderr
index 36bbf1c493a..36bbf1c493a 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.stderr
+++ b/tests/ui/pin-ergonomics/reborrow-const-as-mut.stderr
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-once.rs b/tests/ui/pin-ergonomics/reborrow-once.rs
index 241efadef7d..241efadef7d 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-once.rs
+++ b/tests/ui/pin-ergonomics/reborrow-once.rs
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr b/tests/ui/pin-ergonomics/reborrow-once.stderr
index dc8e424ad2a..dc8e424ad2a 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr
+++ b/tests/ui/pin-ergonomics/reborrow-once.stderr
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-self.rs b/tests/ui/pin-ergonomics/reborrow-self.rs
index ee617617da0..ee617617da0 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-self.rs
+++ b/tests/ui/pin-ergonomics/reborrow-self.rs
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-shorter.rs b/tests/ui/pin-ergonomics/reborrow-shorter.rs
index 06c266e0035..06c266e0035 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-shorter.rs
+++ b/tests/ui/pin-ergonomics/reborrow-shorter.rs
diff --git a/tests/ui/async-await/pin-ergonomics/sugar-ambiguity.rs b/tests/ui/pin-ergonomics/sugar-ambiguity.rs
index d183000931e..d183000931e 100644
--- a/tests/ui/async-await/pin-ergonomics/sugar-ambiguity.rs
+++ b/tests/ui/pin-ergonomics/sugar-ambiguity.rs
diff --git a/tests/ui/async-await/pin-ergonomics/sugar-no-const.rs b/tests/ui/pin-ergonomics/sugar-no-const.rs
index dd6456b6034..dd6456b6034 100644
--- a/tests/ui/async-await/pin-ergonomics/sugar-no-const.rs
+++ b/tests/ui/pin-ergonomics/sugar-no-const.rs
diff --git a/tests/ui/async-await/pin-ergonomics/sugar-no-const.stderr b/tests/ui/pin-ergonomics/sugar-no-const.stderr
index 062b6d3f487..062b6d3f487 100644
--- a/tests/ui/async-await/pin-ergonomics/sugar-no-const.stderr
+++ b/tests/ui/pin-ergonomics/sugar-no-const.stderr
diff --git a/tests/ui/async-await/pin-ergonomics/sugar-self.rs b/tests/ui/pin-ergonomics/sugar-self.rs
index 3d71b54b1ae..3d71b54b1ae 100644
--- a/tests/ui/async-await/pin-ergonomics/sugar-self.rs
+++ b/tests/ui/pin-ergonomics/sugar-self.rs
diff --git a/tests/ui/async-await/pin-ergonomics/sugar.rs b/tests/ui/pin-ergonomics/sugar.rs
index 8dbdec418b1..8dbdec418b1 100644
--- a/tests/ui/async-await/pin-ergonomics/sugar.rs
+++ b/tests/ui/pin-ergonomics/sugar.rs
diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs
index 2257130280d..739c624d0c6 100644
--- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs
+++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs
@@ -1,5 +1,3 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
-
 #![feature(doc_keyword)] //~ ERROR
 #![feature(doc_primitive)] //~ ERROR
 #![crate_type = "lib"]
diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr b/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr
index 9c664da8ee6..0608a8b58a2 100644
--- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr
+++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr
@@ -1,19 +1,19 @@
 error[E0557]: feature has been removed
-  --> $DIR/renamed-features-rustdoc_internals.rs:3:12
+  --> $DIR/renamed-features-rustdoc_internals.rs:1:12
    |
 LL | #![feature(doc_keyword)]
    |            ^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.58.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/90420> for more information
+   = note: removed in 1.58.0; see <https://github.com/rust-lang/rust/pull/90420> for more information
    = note: merged into `#![feature(rustdoc_internals)]`
 
 error[E0557]: feature has been removed
-  --> $DIR/renamed-features-rustdoc_internals.rs:4:12
+  --> $DIR/renamed-features-rustdoc_internals.rs:2:12
    |
 LL | #![feature(doc_primitive)]
    |            ^^^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in 1.58.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/90420> for more information
+   = note: removed in 1.58.0; see <https://github.com/rust-lang/rust/pull/90420> for more information
    = note: merged into `#![feature(rustdoc_internals)]`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs
index 7ef6bd2f0ac..23ffabad62f 100644
--- a/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs
+++ b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs
@@ -7,5 +7,5 @@
 #![no_core]
 #![no_main]
 
-#[cfi_encoding] //~ERROR 10:1: 10:16: malformed `cfi_encoding` attribute input
+#[cfi_encoding] //~ ERROR malformed `cfi_encoding` attribute input
 pub struct Type1(i32);
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index 88f91bef30b..b3b8784fa27 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -1,52 +1,7 @@
-ast-stats POST EXPANSION AST STATS
+ast-stats ================================================================
+ast-stats POST EXPANSION AST STATS: input_stats
 ast-stats Name                Accumulated Size         Count     Item Size
 ast-stats ----------------------------------------------------------------
-ast-stats Crate                     40 (NN.N%)             1            40
-ast-stats GenericArgs               40 (NN.N%)             1            40
-ast-stats - AngleBracketed            40 (NN.N%)             1
-ast-stats ExprField                 48 (NN.N%)             1            48
-ast-stats WherePredicate            72 (NN.N%)             1            72
-ast-stats - BoundPredicate            72 (NN.N%)             1
-ast-stats ForeignItem               80 (NN.N%)             1            80
-ast-stats - Fn                        80 (NN.N%)             1
-ast-stats Arm                       96 (NN.N%)             2            48
-ast-stats Local                     96 (NN.N%)             1            96
-ast-stats FnDecl                   120 (NN.N%)             5            24
-ast-stats InlineAsm                120 (NN.N%)             1           120
-ast-stats Attribute                128 (NN.N%)             4            32
-ast-stats - DocComment                32 (NN.N%)             1
-ast-stats - Normal                    96 (NN.N%)             3
-ast-stats Param                    160 (NN.N%)             4            40
-ast-stats Stmt                     160 (NN.N%)             5            32
-ast-stats - Let                       32 (NN.N%)             1
-ast-stats - Semi                      32 (NN.N%)             1
-ast-stats - Expr                      96 (NN.N%)             3
-ast-stats Block                    192 (NN.N%)             6            32
-ast-stats FieldDef                 208 (NN.N%)             2           104
-ast-stats Variant                  208 (NN.N%)             2           104
-ast-stats AssocItem                320 (NN.N%)             4            80
-ast-stats - Fn                       160 (NN.N%)             2
-ast-stats - Type                     160 (NN.N%)             2
-ast-stats GenericBound             352 (NN.N%)             4            88
-ast-stats - Trait                    352 (NN.N%)             4
-ast-stats GenericParam             480 (NN.N%)             5            96
-ast-stats Pat                      504 (NN.N%)             7            72
-ast-stats - Struct                    72 (NN.N%)             1
-ast-stats - Wild                      72 (NN.N%)             1
-ast-stats - Ident                    360 (NN.N%)             5
-ast-stats Expr                     648 (NN.N%)             9            72
-ast-stats - InlineAsm                 72 (NN.N%)             1
-ast-stats - Match                     72 (NN.N%)             1
-ast-stats - Path                      72 (NN.N%)             1
-ast-stats - Struct                    72 (NN.N%)             1
-ast-stats - Lit                      144 (NN.N%)             2
-ast-stats - Block                    216 (NN.N%)             3
-ast-stats PathSegment              864 (NN.N%)            36            24
-ast-stats Ty                       896 (NN.N%)            14            64
-ast-stats - Ptr                       64 (NN.N%)             1
-ast-stats - Ref                       64 (NN.N%)             1
-ast-stats - ImplicitSelf             128 (NN.N%)             2
-ast-stats - Path                     640 (NN.N%)            10
 ast-stats Item                   1_584 (NN.N%)            11           144
 ast-stats - Enum                     144 (NN.N%)             1
 ast-stats - ExternCrate              144 (NN.N%)             1
@@ -55,57 +10,61 @@ ast-stats - Impl                     144 (NN.N%)             1
 ast-stats - Trait                    144 (NN.N%)             1
 ast-stats - Fn                       288 (NN.N%)             2
 ast-stats - Use                      576 (NN.N%)             4
+ast-stats Ty                       896 (NN.N%)            14            64
+ast-stats - Ptr                       64 (NN.N%)             1
+ast-stats - Ref                       64 (NN.N%)             1
+ast-stats - ImplicitSelf             128 (NN.N%)             2
+ast-stats - Path                     640 (NN.N%)            10
+ast-stats PathSegment              864 (NN.N%)            36            24
+ast-stats Expr                     648 (NN.N%)             9            72
+ast-stats - InlineAsm                 72 (NN.N%)             1
+ast-stats - Match                     72 (NN.N%)             1
+ast-stats - Path                      72 (NN.N%)             1
+ast-stats - Struct                    72 (NN.N%)             1
+ast-stats - Lit                      144 (NN.N%)             2
+ast-stats - Block                    216 (NN.N%)             3
+ast-stats Pat                      504 (NN.N%)             7            72
+ast-stats - Struct                    72 (NN.N%)             1
+ast-stats - Wild                      72 (NN.N%)             1
+ast-stats - Ident                    360 (NN.N%)             5
+ast-stats GenericParam             480 (NN.N%)             5            96
+ast-stats GenericBound             352 (NN.N%)             4            88
+ast-stats - Trait                    352 (NN.N%)             4
+ast-stats AssocItem                320 (NN.N%)             4            80
+ast-stats - Fn                       160 (NN.N%)             2
+ast-stats - Type                     160 (NN.N%)             2
+ast-stats Variant                  208 (NN.N%)             2           104
+ast-stats FieldDef                 208 (NN.N%)             2           104
+ast-stats Block                    192 (NN.N%)             6            32
+ast-stats Stmt                     160 (NN.N%)             5            32
+ast-stats - Let                       32 (NN.N%)             1
+ast-stats - Semi                      32 (NN.N%)             1
+ast-stats - Expr                      96 (NN.N%)             3
+ast-stats Param                    160 (NN.N%)             4            40
+ast-stats Attribute                128 (NN.N%)             4            32
+ast-stats - DocComment                32 (NN.N%)             1
+ast-stats - Normal                    96 (NN.N%)             3
+ast-stats InlineAsm                120 (NN.N%)             1           120
+ast-stats FnDecl                   120 (NN.N%)             5            24
+ast-stats Local                     96 (NN.N%)             1            96
+ast-stats Arm                       96 (NN.N%)             2            48
+ast-stats ForeignItem               80 (NN.N%)             1            80
+ast-stats - Fn                        80 (NN.N%)             1
+ast-stats WherePredicate            72 (NN.N%)             1            72
+ast-stats - BoundPredicate            72 (NN.N%)             1
+ast-stats ExprField                 48 (NN.N%)             1            48
+ast-stats GenericArgs               40 (NN.N%)             1            40
+ast-stats - AngleBracketed            40 (NN.N%)             1
+ast-stats Crate                     40 (NN.N%)             1            40
 ast-stats ----------------------------------------------------------------
 ast-stats Total                  7_416                   127
-ast-stats
-hir-stats HIR STATS
+ast-stats ================================================================
+hir-stats ================================================================
+hir-stats HIR STATS: input_stats
 hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
-hir-stats ForeignItemRef            24 (NN.N%)             1            24
-hir-stats Lifetime                  28 (NN.N%)             1            28
-hir-stats Mod                       32 (NN.N%)             1            32
-hir-stats ExprField                 40 (NN.N%)             1            40
-hir-stats TraitItemRef              56 (NN.N%)             2            28
-hir-stats GenericArg                64 (NN.N%)             4            16
-hir-stats - Type                      16 (NN.N%)             1
-hir-stats - Lifetime                  48 (NN.N%)             3
-hir-stats Param                     64 (NN.N%)             2            32
-hir-stats Body                      72 (NN.N%)             3            24
-hir-stats ImplItemRef               72 (NN.N%)             2            36
-hir-stats InlineAsm                 72 (NN.N%)             1            72
-hir-stats Local                     72 (NN.N%)             1            72
-hir-stats WherePredicate            72 (NN.N%)             3            24
-hir-stats - BoundPredicate            72 (NN.N%)             3
-hir-stats Arm                       80 (NN.N%)             2            40
-hir-stats Stmt                      96 (NN.N%)             3            32
-hir-stats - Expr                      32 (NN.N%)             1
-hir-stats - Let                       32 (NN.N%)             1
-hir-stats - Semi                      32 (NN.N%)             1
-hir-stats FnDecl                   120 (NN.N%)             3            40
-hir-stats FieldDef                 128 (NN.N%)             2            64
-hir-stats GenericArgs              144 (NN.N%)             3            48
-hir-stats Variant                  144 (NN.N%)             2            72
-hir-stats Attribute                160 (NN.N%)             4            40
-hir-stats GenericBound             256 (NN.N%)             4            64
-hir-stats - Trait                    256 (NN.N%)             4
-hir-stats Block                    288 (NN.N%)             6            48
-hir-stats Pat                      360 (NN.N%)             5            72
-hir-stats - Struct                    72 (NN.N%)             1
-hir-stats - Wild                      72 (NN.N%)             1
-hir-stats - Binding                  216 (NN.N%)             3
-hir-stats GenericParam             400 (NN.N%)             5            80
-hir-stats Generics                 560 (NN.N%)            10            56
-hir-stats Ty                       720 (NN.N%)            15            48
-hir-stats - Ptr                       48 (NN.N%)             1
-hir-stats - Ref                       48 (NN.N%)             1
-hir-stats - Path                     624 (NN.N%)            13
-hir-stats Expr                     768 (NN.N%)            12            64
-hir-stats - InlineAsm                 64 (NN.N%)             1
-hir-stats - Match                     64 (NN.N%)             1
-hir-stats - Path                      64 (NN.N%)             1
-hir-stats - Struct                    64 (NN.N%)             1
-hir-stats - Lit                      128 (NN.N%)             2
-hir-stats - Block                    384 (NN.N%)             6
+hir-stats PathSegment            1_776 (NN.N%)            37            48
+hir-stats Path                   1_040 (NN.N%)            26            40
 hir-stats Item                     968 (NN.N%)            11            88
 hir-stats - Enum                      88 (NN.N%)             1
 hir-stats - ExternCrate               88 (NN.N%)             1
@@ -114,8 +73,51 @@ hir-stats - Impl                      88 (NN.N%)             1
 hir-stats - Trait                     88 (NN.N%)             1
 hir-stats - Fn                       176 (NN.N%)             2
 hir-stats - Use                      352 (NN.N%)             4
-hir-stats Path                   1_040 (NN.N%)            26            40
-hir-stats PathSegment            1_776 (NN.N%)            37            48
+hir-stats Expr                     768 (NN.N%)            12            64
+hir-stats - InlineAsm                 64 (NN.N%)             1
+hir-stats - Match                     64 (NN.N%)             1
+hir-stats - Path                      64 (NN.N%)             1
+hir-stats - Struct                    64 (NN.N%)             1
+hir-stats - Lit                      128 (NN.N%)             2
+hir-stats - Block                    384 (NN.N%)             6
+hir-stats Ty                       720 (NN.N%)            15            48
+hir-stats - Ptr                       48 (NN.N%)             1
+hir-stats - Ref                       48 (NN.N%)             1
+hir-stats - Path                     624 (NN.N%)            13
+hir-stats Generics                 560 (NN.N%)            10            56
+hir-stats GenericParam             400 (NN.N%)             5            80
+hir-stats Pat                      360 (NN.N%)             5            72
+hir-stats - Struct                    72 (NN.N%)             1
+hir-stats - Wild                      72 (NN.N%)             1
+hir-stats - Binding                  216 (NN.N%)             3
+hir-stats Block                    288 (NN.N%)             6            48
+hir-stats GenericBound             256 (NN.N%)             4            64
+hir-stats - Trait                    256 (NN.N%)             4
+hir-stats Attribute                160 (NN.N%)             4            40
+hir-stats Variant                  144 (NN.N%)             2            72
+hir-stats GenericArgs              144 (NN.N%)             3            48
+hir-stats FieldDef                 128 (NN.N%)             2            64
+hir-stats FnDecl                   120 (NN.N%)             3            40
+hir-stats Stmt                      96 (NN.N%)             3            32
+hir-stats - Expr                      32 (NN.N%)             1
+hir-stats - Let                       32 (NN.N%)             1
+hir-stats - Semi                      32 (NN.N%)             1
+hir-stats Arm                       80 (NN.N%)             2            40
+hir-stats WherePredicate            72 (NN.N%)             3            24
+hir-stats - BoundPredicate            72 (NN.N%)             3
+hir-stats Local                     72 (NN.N%)             1            72
+hir-stats InlineAsm                 72 (NN.N%)             1            72
+hir-stats ImplItemRef               72 (NN.N%)             2            36
+hir-stats Body                      72 (NN.N%)             3            24
+hir-stats Param                     64 (NN.N%)             2            32
+hir-stats GenericArg                64 (NN.N%)             4            16
+hir-stats - Type                      16 (NN.N%)             1
+hir-stats - Lifetime                  48 (NN.N%)             3
+hir-stats TraitItemRef              56 (NN.N%)             2            28
+hir-stats ExprField                 40 (NN.N%)             1            40
+hir-stats Mod                       32 (NN.N%)             1            32
+hir-stats Lifetime                  28 (NN.N%)             1            28
+hir-stats ForeignItemRef            24 (NN.N%)             1            24
 hir-stats ----------------------------------------------------------------
 hir-stats Total                  8_676                   172
-hir-stats
+hir-stats ================================================================
diff --git a/tests/ui/suggestions/issue-105645.rs b/tests/ui/suggestions/issue-105645.rs
index 681ce1c6e37..f3ca8ccbb3c 100644
--- a/tests/ui/suggestions/issue-105645.rs
+++ b/tests/ui/suggestions/issue-105645.rs
@@ -2,7 +2,7 @@ fn main() {
     let mut buf = [0u8; 50];
     let mut bref = buf.as_slice();
     foo(&mut bref);
-    //~^ ERROR 4:9: 4:18: the trait bound `&[u8]: std::io::Write` is not satisfied [E0277]
+    //~^ ERROR the trait bound `&[u8]: std::io::Write` is not satisfied [E0277]
 }
 
 fn foo(_: &mut impl std::io::Write) {}
diff --git a/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs b/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs
index 1dfc0786668..807fba0ab7e 100644
--- a/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs
+++ b/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs
@@ -6,5 +6,5 @@ mod option {
 }
 
 fn main() {
-    let _: option::O<()> = (); //~ ERROR 9:28: 9:30: mismatched types [E0308]
+    let _: option::O<()> = (); //~ ERROR mismatched types [E0308]
 }
diff --git a/tests/ui/syntax-extension-minor.rs b/tests/ui/syntax-extension-minor.rs
deleted file mode 100644
index 826990a89a5..00000000000
--- a/tests/ui/syntax-extension-minor.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ run-pass
-
-#![feature(concat_idents)]
-#![expect(deprecated)] // concat_idents is deprecated
-
-pub fn main() {
-    struct Foo;
-    let _: concat_idents!(F, oo) = Foo; // Test that `concat_idents!` can be used in type positions
-
-    let asdf_fdsa = "<.<".to_string();
-    // concat_idents should have call-site hygiene.
-    assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-
-    assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
-}
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
index b563b78f78a..f90ff91aff4 100644
--- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
@@ -6,7 +6,6 @@
 // Regression test for issue #125877.
 
 //@ compile-flags: -Znext-solver
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 
 #![feature(const_trait_impl, effects)]
 //~^ ERROR feature has been removed
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
index a04f98e68a6..566961b27f3 100644
--- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
@@ -1,14 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/const-trait-impl-parameter-mismatch.rs:11:30
+  --> $DIR/const-trait-impl-parameter-mismatch.rs:10:30
    |
 LL | #![feature(const_trait_impl, effects)]
    |                              ^^^^^^^ feature has been removed
    |
-   = note: removed in 1.84.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/132479> for more information
+   = note: removed in 1.84.0; see <https://github.com/rust-lang/rust/pull/132479> for more information
    = note: removed, redundant with `#![feature(const_trait_impl)]`
 
 error[E0049]: associated function `compute` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/const-trait-impl-parameter-mismatch.rs:20:16
+  --> $DIR/const-trait-impl-parameter-mismatch.rs:19:16
    |
 LL |     fn compute<T: ~const Aux>() -> u32;
    |                - expected 1 type parameter
diff --git a/tests/ui/type/option-ref-advice.rs b/tests/ui/type/option-ref-advice.rs
index 2dcee5a2eb9..435b15d01e3 100644
--- a/tests/ui/type/option-ref-advice.rs
+++ b/tests/ui/type/option-ref-advice.rs
@@ -3,9 +3,9 @@
 fn takes_option(_arg: Option<&String>) {}
 
 fn main() {
-    takes_option(&None); //~ ERROR 6:18: 6:23: mismatched types [E0308]
+    takes_option(&None); //~ ERROR mismatched types [E0308]
 
     let x = String::from("x");
     let res = Some(x);
-    takes_option(&res); //~ ERROR 10:18: 10:22: mismatched types [E0308]
+    takes_option(&res); //~ ERROR mismatched types [E0308]
 }
diff --git a/tests/ui/typeck/issue-100246.rs b/tests/ui/typeck/issue-100246.rs
index 8f0b34bab0c..e05bb2a1362 100644
--- a/tests/ui/typeck/issue-100246.rs
+++ b/tests/ui/typeck/issue-100246.rs
@@ -25,6 +25,6 @@ fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> {
 struct Other;
 
 fn main() -> std::io::Result<()> {
-    let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types
+    let other: Other = downcast()?; //~ ERROR `?` operator has incompatible types
     Ok(())
 }
diff --git a/tests/ui/typeck/issue-89275.rs b/tests/ui/typeck/issue-89275.rs
index b91c0017548..6e4211de185 100644
--- a/tests/ui/typeck/issue-89275.rs
+++ b/tests/ui/typeck/issue-89275.rs
@@ -25,5 +25,5 @@ fn downcast<'a, W: ?Sized>() -> &'a W {
 struct Other;
 
 fn main() {
-    let other: &mut Other = downcast();//~ERROR 28:29: 28:39: mismatched types [E0308]
+    let other: &mut Other = downcast();//~ ERROR mismatched types [E0308]
 }
diff --git a/tests/ui/underscore-imports/issue-110164.stderr b/tests/ui/underscore-imports/issue-110164.ed2015.stderr
index d8a4b6bbb75..f34b5ab5dde 100644
--- a/tests/ui/underscore-imports/issue-110164.stderr
+++ b/tests/ui/underscore-imports/issue-110164.ed2015.stderr
@@ -1,17 +1,17 @@
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-110164.rs:5:5
+  --> $DIR/issue-110164.rs:8:5
    |
 LL | use _::a;
    |     ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-110164.rs:8:5
+  --> $DIR/issue-110164.rs:10:5
    |
 LL | use _::*;
    |     ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-110164.rs:13:9
+  --> $DIR/issue-110164.rs:14:9
    |
 LL |     use _::a;
    |         ^ expected identifier, found reserved identifier
@@ -23,41 +23,17 @@ LL |     use _::*;
    |         ^ expected identifier, found reserved identifier
 
 error[E0432]: unresolved import `self::*`
-  --> $DIR/issue-110164.rs:1:5
+  --> $DIR/issue-110164.rs:4:5
    |
 LL | use self::*;
    |     ^^^^^^^ cannot glob-import a module into itself
 
 error[E0432]: unresolved import `crate::*`
-  --> $DIR/issue-110164.rs:3:5
+  --> $DIR/issue-110164.rs:6:5
    |
 LL | use crate::*;
    |     ^^^^^^^^ cannot glob-import a module into itself
 
-error[E0432]: unresolved import `_`
-  --> $DIR/issue-110164.rs:8:5
-   |
-LL | use _::*;
-   |     ^ `_` is not a valid crate or module name
-
-error[E0432]: unresolved import `_`
-  --> $DIR/issue-110164.rs:5:5
-   |
-LL | use _::a;
-   |     ^ `_` is not a valid crate or module name
-
-error[E0432]: unresolved import `_`
-  --> $DIR/issue-110164.rs:13:9
-   |
-LL |     use _::a;
-   |         ^ `_` is not a valid crate or module name
-
-error[E0432]: unresolved import `_`
-  --> $DIR/issue-110164.rs:16:9
-   |
-LL |     use _::*;
-   |         ^ `_` is not a valid crate or module name
-
-error: aborting due to 10 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/underscore-imports/issue-110164.ed2021.stderr b/tests/ui/underscore-imports/issue-110164.ed2021.stderr
new file mode 100644
index 00000000000..f34b5ab5dde
--- /dev/null
+++ b/tests/ui/underscore-imports/issue-110164.ed2021.stderr
@@ -0,0 +1,39 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-110164.rs:8:5
+   |
+LL | use _::a;
+   |     ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-110164.rs:10:5
+   |
+LL | use _::*;
+   |     ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-110164.rs:14:9
+   |
+LL |     use _::a;
+   |         ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-110164.rs:16:9
+   |
+LL |     use _::*;
+   |         ^ expected identifier, found reserved identifier
+
+error[E0432]: unresolved import `self::*`
+  --> $DIR/issue-110164.rs:4:5
+   |
+LL | use self::*;
+   |     ^^^^^^^ cannot glob-import a module into itself
+
+error[E0432]: unresolved import `crate::*`
+  --> $DIR/issue-110164.rs:6:5
+   |
+LL | use crate::*;
+   |     ^^^^^^^^ cannot glob-import a module into itself
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/underscore-imports/issue-110164.rs b/tests/ui/underscore-imports/issue-110164.rs
index 6fd13414500..bb080c5e471 100644
--- a/tests/ui/underscore-imports/issue-110164.rs
+++ b/tests/ui/underscore-imports/issue-110164.rs
@@ -1,19 +1,18 @@
+//@ revisions: ed2015 ed2021
+//@[ed2015] edition: 2015
+//@[ed2021] edition: 2021
 use self::*;
 //~^ ERROR unresolved import `self::*`
 use crate::*;
 //~^ ERROR unresolved import `crate::*`
 use _::a;
 //~^ ERROR expected identifier, found reserved identifier `_`
-//~| ERROR unresolved import `_`
 use _::*;
 //~^ ERROR expected identifier, found reserved identifier `_`
-//~| ERROR unresolved import `_`
 
 fn main() {
     use _::a;
     //~^ ERROR expected identifier, found reserved identifier `_`
-    //~| ERROR unresolved import `_`
     use _::*;
     //~^ ERROR expected identifier, found reserved identifier `_`
-    //~| ERROR unresolved import `_`
 }
diff --git a/tests/ui/underscore-imports/multiple-uses.ed2015.stderr b/tests/ui/underscore-imports/multiple-uses.ed2015.stderr
new file mode 100644
index 00000000000..a295586fa16
--- /dev/null
+++ b/tests/ui/underscore-imports/multiple-uses.ed2015.stderr
@@ -0,0 +1,49 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:4:9
+   |
+LL | pub use _::{a, b};
+   |         ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:6:18
+   |
+LL | pub use std::{a, _};
+   |                  ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:9:18
+   |
+LL | pub use std::{b, _, c};
+   |                  ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:12:15
+   |
+LL | pub use std::{_, d};
+   |               ^ expected identifier, found reserved identifier
+
+error[E0432]: unresolved import `std::a`
+  --> $DIR/multiple-uses.rs:6:15
+   |
+LL | pub use std::{a, _};
+   |               ^ no `a` in the root
+
+error[E0432]: unresolved imports `std::b`, `std::c`
+  --> $DIR/multiple-uses.rs:9:15
+   |
+LL | pub use std::{b, _, c};
+   |               ^     ^
+   |               |     |
+   |               |     no `c` in the root
+   |               |     help: a similar name exists in the module: `rc`
+   |               no `b` in the root
+
+error[E0432]: unresolved import `std::d`
+  --> $DIR/multiple-uses.rs:12:18
+   |
+LL | pub use std::{_, d};
+   |                  ^ no `d` in the root
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/underscore-imports/multiple-uses.ed2021.stderr b/tests/ui/underscore-imports/multiple-uses.ed2021.stderr
new file mode 100644
index 00000000000..a295586fa16
--- /dev/null
+++ b/tests/ui/underscore-imports/multiple-uses.ed2021.stderr
@@ -0,0 +1,49 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:4:9
+   |
+LL | pub use _::{a, b};
+   |         ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:6:18
+   |
+LL | pub use std::{a, _};
+   |                  ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:9:18
+   |
+LL | pub use std::{b, _, c};
+   |                  ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/multiple-uses.rs:12:15
+   |
+LL | pub use std::{_, d};
+   |               ^ expected identifier, found reserved identifier
+
+error[E0432]: unresolved import `std::a`
+  --> $DIR/multiple-uses.rs:6:15
+   |
+LL | pub use std::{a, _};
+   |               ^ no `a` in the root
+
+error[E0432]: unresolved imports `std::b`, `std::c`
+  --> $DIR/multiple-uses.rs:9:15
+   |
+LL | pub use std::{b, _, c};
+   |               ^     ^
+   |               |     |
+   |               |     no `c` in the root
+   |               |     help: a similar name exists in the module: `rc`
+   |               no `b` in the root
+
+error[E0432]: unresolved import `std::d`
+  --> $DIR/multiple-uses.rs:12:18
+   |
+LL | pub use std::{_, d};
+   |                  ^ no `d` in the root
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/underscore-imports/multiple-uses.rs b/tests/ui/underscore-imports/multiple-uses.rs
new file mode 100644
index 00000000000..31dd1862429
--- /dev/null
+++ b/tests/ui/underscore-imports/multiple-uses.rs
@@ -0,0 +1,16 @@
+//@ revisions: ed2015 ed2021
+//@[ed2015] edition: 2015
+//@[ed2021] edition: 2021
+pub use _::{a, b};
+//~^ ERROR expected identifier, found reserved identifier `_`
+pub use std::{a, _};
+//~^ ERROR expected identifier, found reserved identifier `_`
+//~| ERROR unresolved import `std::a`
+pub use std::{b, _, c};
+//~^ ERROR expected identifier, found reserved identifier `_`
+//~| ERROR unresolved imports `std::b`, `std::c`
+pub use std::{_, d};
+//~^ ERROR expected identifier, found reserved identifier `_`
+//~| ERROR unresolved import `std::d`
+
+fn main() {}
diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout
index cd1a5d0af08..ae44d1206af 100644
--- a/tests/ui/unpretty/exhaustive.expanded.stdout
+++ b/tests/ui/unpretty/exhaustive.expanded.stdout
@@ -12,7 +12,6 @@
 #![feature(auto_traits)]
 #![feature(box_patterns)]
 #![feature(builtin_syntax)]
-#![feature(concat_idents)]
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
@@ -309,7 +308,6 @@ mod expressions {
 
 
 
-        // concat_idents is deprecated
 
 
 
@@ -622,8 +620,12 @@ mod types {
         /*! there is no syntax for this */
     }
     /// TyKind::MacCall
-    #[expect(deprecated)]
-    fn ty_mac_call() { let _: T; let _: T; let _: T; }
+    fn ty_mac_call() {
+        macro_rules! ty { ($ty:ty) => { $ty } }
+        let _: T;
+        let _: T;
+        let _: T;
+    }
     /// TyKind::CVarArgs
     fn ty_c_var_args() {
         /*! FIXME: todo */
diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr
index 58f7ff0f598..1c78cf98c59 100644
--- a/tests/ui/unpretty/exhaustive.hir.stderr
+++ b/tests/ui/unpretty/exhaustive.hir.stderr
@@ -1,17 +1,17 @@
 error[E0697]: closures cannot be static
-  --> $DIR/exhaustive.rs:211:9
+  --> $DIR/exhaustive.rs:210:9
    |
 LL |         static || value;
    |         ^^^^^^^^^
 
 error[E0697]: closures cannot be static
-  --> $DIR/exhaustive.rs:212:9
+  --> $DIR/exhaustive.rs:211:9
    |
 LL |         static move || value;
    |         ^^^^^^^^^^^^^^
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/exhaustive.rs:241:13
+  --> $DIR/exhaustive.rs:240:13
    |
 LL |     fn expr_await() {
    |     --------------- this is not `async`
@@ -20,19 +20,19 @@ LL |         fut.await;
    |             ^^^^^ only allowed inside `async` functions and blocks
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/exhaustive.rs:290:9
+  --> $DIR/exhaustive.rs:289:9
    |
 LL |         _;
    |         ^ `_` not allowed here
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:300:9
+  --> $DIR/exhaustive.rs:299:9
    |
 LL |         x::();
    |         ^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:301:9
+  --> $DIR/exhaustive.rs:300:9
    |
 LL |         x::(T, T) -> T;
    |         ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
@@ -44,31 +44,31 @@ LL +         x::<T, T> -> T;
    |
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:302:9
+  --> $DIR/exhaustive.rs:301:9
    |
 LL |         crate::() -> ()::expressions::() -> ()::expr_path;
    |         ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:302:26
+  --> $DIR/exhaustive.rs:301:26
    |
 LL |         crate::() -> ()::expressions::() -> ()::expr_path;
    |                          ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:305:9
+  --> $DIR/exhaustive.rs:304:9
    |
 LL |         core::()::marker::()::PhantomData;
    |         ^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:305:19
+  --> $DIR/exhaustive.rs:304:19
    |
 LL |         core::()::marker::()::PhantomData;
    |                   ^^^^^^^^^^ only `Fn` traits may use parentheses
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
-  --> $DIR/exhaustive.rs:392:9
+  --> $DIR/exhaustive.rs:391:9
    |
 LL |         yield;
    |         ^^^^^
@@ -79,7 +79,7 @@ LL |     #[coroutine] fn expr_yield() {
    |     ++++++++++++
 
 error[E0703]: invalid ABI: found `C++`
-  --> $DIR/exhaustive.rs:472:23
+  --> $DIR/exhaustive.rs:471:23
    |
 LL |         unsafe extern "C++" {}
    |                       ^^^^^ invalid ABI
@@ -87,7 +87,7 @@ LL |         unsafe extern "C++" {}
    = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
 
 error: `..` patterns are not allowed here
-  --> $DIR/exhaustive.rs:679:13
+  --> $DIR/exhaustive.rs:678:13
    |
 LL |         let ..;
    |             ^^
@@ -95,13 +95,13 @@ LL |         let ..;
    = note: only allowed in tuple, tuple struct, and slice patterns
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:794:16
+  --> $DIR/exhaustive.rs:793:16
    |
 LL |         let _: T() -> !;
    |                ^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:809:16
+  --> $DIR/exhaustive.rs:808:16
    |
 LL |         let _: impl Send;
    |                ^^^^^^^^^
@@ -112,7 +112,7 @@ LL |         let _: impl Send;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:810:16
+  --> $DIR/exhaustive.rs:809:16
    |
 LL |         let _: impl Send + 'static;
    |                ^^^^^^^^^^^^^^^^^^^
@@ -123,7 +123,7 @@ LL |         let _: impl Send + 'static;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:811:16
+  --> $DIR/exhaustive.rs:810:16
    |
 LL |         let _: impl 'static + Send;
    |                ^^^^^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL |         let _: impl 'static + Send;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:812:16
+  --> $DIR/exhaustive.rs:811:16
    |
 LL |         let _: impl ?Sized;
    |                ^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL |         let _: impl ?Sized;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:813:16
+  --> $DIR/exhaustive.rs:812:16
    |
 LL |         let _: impl ~const Clone;
    |                ^^^^^^^^^^^^^^^^^
@@ -156,7 +156,7 @@ LL |         let _: impl ~const Clone;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:814:16
+  --> $DIR/exhaustive.rs:813:16
    |
 LL |         let _: impl for<'a> Send;
    |                ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index b15c02003a6..2d347ec6e88 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -11,7 +11,6 @@
 #![feature(auto_traits)]
 #![feature(box_patterns)]
 #![feature(builtin_syntax)]
-#![feature(concat_idents)]
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
@@ -343,7 +342,6 @@ mod expressions {
 
 
 
-        // concat_idents is deprecated
 
 
 
@@ -685,8 +683,12 @@ mod types {
     /** there is no syntax for this */
     fn ty_implicit_self() { }
     /// TyKind::MacCall
-    #[expect(deprecated)]
-    fn ty_mac_call() { let _: T; let _: T; let _: T; }
+    fn ty_mac_call() {
+        macro_rules! ty { ($ty:ty) => { $ty } }
+        let _: T;
+        let _: T;
+        let _: T;
+    }
     /// TyKind::CVarArgs
     /** FIXME: todo */
     fn ty_c_var_args() { }
diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs
index 60ad3564689..ccf907a6165 100644
--- a/tests/ui/unpretty/exhaustive.rs
+++ b/tests/ui/unpretty/exhaustive.rs
@@ -11,7 +11,6 @@
 #![feature(auto_traits)]
 #![feature(box_patterns)]
 #![feature(builtin_syntax)]
-#![feature(concat_idents)]
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
@@ -835,11 +834,13 @@ mod types {
     }
 
     /// TyKind::MacCall
-    #[expect(deprecated)] // concat_idents is deprecated
     fn ty_mac_call() {
-        let _: concat_idents!(T);
-        let _: concat_idents![T];
-        let _: concat_idents! { T };
+        macro_rules! ty {
+            ($ty:ty) => { $ty }
+        }
+        let _: ty!(T);
+        let _: ty![T];
+        let _: ty! { T };
     }
 
     /// TyKind::CVarArgs
diff --git a/tests/ui/unsized-locals/yote.rs b/tests/ui/unsized-locals/yote.rs
index aa5b68a3078..1de75a6ce61 100644
--- a/tests/ui/unsized-locals/yote.rs
+++ b/tests/ui/unsized-locals/yote.rs
@@ -1,4 +1,2 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
-
 #![feature(unsized_locals)] //~ERROR feature has been removed
 #![crate_type = "lib"]
diff --git a/tests/ui/unsized-locals/yote.stderr b/tests/ui/unsized-locals/yote.stderr
index 655aad5360c..8e7da64038a 100644
--- a/tests/ui/unsized-locals/yote.stderr
+++ b/tests/ui/unsized-locals/yote.stderr
@@ -1,10 +1,10 @@
 error[E0557]: feature has been removed
-  --> $DIR/yote.rs:3:12
+  --> $DIR/yote.rs:1:12
    |
 LL | #![feature(unsized_locals)]
    |            ^^^^^^^^^^^^^^ feature has been removed
    |
-   = note: removed in CURRENT_RUSTC_VERSION (you are using $RUSTC_VERSION)
+   = note: removed in CURRENT_RUSTC_VERSION
    = note: removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942
 
 error: aborting due to 1 previous error