about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules2
-rw-r--r--Cargo.lock110
-rw-r--r--compiler/rustc_ast/src/expand/allocator.rs22
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs595
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs53
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs14
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs22
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs5
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0577.md2
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_feature/src/lib.rs2
-rw-r--r--compiler/rustc_hir/src/def.rs10
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/target.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs4
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs7
-rw-r--r--compiler/rustc_lint/src/builtin.rs486
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs402
-rw-r--r--compiler/rustc_lint/src/late.rs42
-rw-r--r--compiler/rustc_lint/src/levels.rs11
-rw-r--r--compiler/rustc_lint/src/lib.rs45
-rw-r--r--compiler/rustc_lint/src/lints.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs57
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp8
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs15
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs20
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs28
-rw-r--r--compiler/rustc_middle/src/query/mod.rs12
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_middle/src/values.rs2
-rw-r--r--compiler/rustc_mir_build/src/lib.rs2
-rw-r--r--compiler/rustc_mir_build/src/lints.rs115
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs2
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml1
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs2
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs42
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs2
-rw-r--r--compiler/rustc_passes/messages.ftl4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs14
-rw-r--r--compiler/rustc_passes/src/dead.rs4
-rw-r--r--compiler/rustc_passes/src/errors.rs4
-rw-r--r--compiler/rustc_passes/src/layout_test.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs6
-rw-r--r--compiler/rustc_query_system/src/query/job.rs5
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs9
-rw-r--r--compiler/rustc_resolve/src/late.rs68
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs83
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs98
-rw-r--r--compiler/rustc_smir/src/stable_mir/mod.rs7
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs59
-rw-r--r--compiler/rustc_span/src/source_map.rs15
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/abi.rs11
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs16
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs31
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs4
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs4
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs8
-rw-r--r--library/alloc/src/str.rs6
-rw-r--r--library/alloc/src/string.rs73
-rw-r--r--library/core/src/clone.rs40
-rw-r--r--library/core/src/intrinsics.rs34
-rw-r--r--library/core/src/iter/mod.rs6
-rw-r--r--library/core/src/iter/traits/double_ended.rs62
-rw-r--r--library/core/src/iter/traits/iterator.rs62
-rw-r--r--library/core/src/macros/mod.rs1
-rw-r--r--library/core/src/option.rs35
-rw-r--r--library/core/src/slice/cmp.rs21
-rw-r--r--library/panic_unwind/src/lib.rs2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/unix/fs.rs27
-rwxr-xr-xsrc/bootstrap/configure.py11
-rw-r--r--src/bootstrap/llvm.rs4
-rw-r--r--src/ci/docker/README.md3
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig2
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile4
-rwxr-xr-xsrc/ci/docker/run.sh1
-rwxr-xr-xsrc/ci/run.sh21
-rw-r--r--src/doc/unstable-book/src/language-features/abi-thiscall.md12
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/clean/utils.rs18
-rw-r--r--src/librustdoc/core.rs8
-rw-r--r--src/librustdoc/formats/item_type.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs9
m---------src/llvm-project0
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/linkchecker/main.rs1
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs2
-rw-r--r--src/tools/miri/tests/fail/uninit_buffer.stderr4
-rw-r--r--src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr4
-rw-r--r--src/tools/opt-dist/src/environment/linux.rs2
-rw-r--r--src/tools/opt-dist/src/environment/mod.rs4
-rw-r--r--src/tools/opt-dist/src/environment/windows.rs2
-rw-r--r--src/tools/opt-dist/src/training.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs39
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs55
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs65
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/eager.rs141
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs106
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs444
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs117
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs88
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs77
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/db.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/from_id.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/has_source.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs65
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs184
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs125
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs70
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs739
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs93
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs53
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/source_change.rs204
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/search.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs88
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs54
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs327
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/ssr.rs57
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs16
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander.rs10
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs10
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs42
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/token_map.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar.rs34
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/shortcuts.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs21
-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/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs38
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs617
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram6
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs36
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs30
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs1
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc23
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json10
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json13
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts10
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts10
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts14
-rw-r--r--src/tools/rust-analyzer/triagebot.toml4
-rw-r--r--src/tools/tidy/src/fluent_alphabetical.rs2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/codegen/box-maybe-uninit-llvm14.rs34
-rw-r--r--tests/codegen/cffi/c-variadic-copy.rs (renamed from tests/codegen/c-variadic-copy.rs)0
-rw-r--r--tests/codegen/cffi/c-variadic-opt.rs (renamed from tests/codegen/c-variadic-opt.rs)0
-rw-r--r--tests/codegen/cffi/c-variadic.rs (renamed from tests/codegen/c-variadic.rs)0
-rw-r--r--tests/codegen/cffi/ffi-const.rs (renamed from tests/codegen/ffi-const.rs)0
-rw-r--r--tests/codegen/cffi/ffi-out-of-bounds-loads.rs (renamed from tests/codegen/ffi-out-of-bounds-loads.rs)0
-rw-r--r--tests/codegen/cffi/ffi-pure.rs (renamed from tests/codegen/ffi-pure.rs)0
-rw-r--r--tests/codegen/cffi/ffi-returns-twice.rs (renamed from tests/codegen/ffi-returns-twice.rs)0
-rw-r--r--tests/codegen/enum/enum-bounds-check-derived-idx.rs (renamed from tests/codegen/enum-bounds-check-derived-idx.rs)0
-rw-r--r--tests/codegen/enum/enum-bounds-check-issue-13926.rs (renamed from tests/codegen/enum-bounds-check-issue-13926.rs)0
-rw-r--r--tests/codegen/enum/enum-bounds-check-issue-82871.rs (renamed from tests/codegen/enum-bounds-check-issue-82871.rs)0
-rw-r--r--tests/codegen/enum/enum-bounds-check.rs (renamed from tests/codegen/enum-bounds-check.rs)0
-rw-r--r--tests/codegen/enum/enum-debug-clike.rs (renamed from tests/codegen/enum-debug-clike.rs)0
-rw-r--r--tests/codegen/enum/enum-debug-niche-2.rs (renamed from tests/codegen/enum-debug-niche-2.rs)0
-rw-r--r--tests/codegen/enum/enum-debug-niche.rs (renamed from tests/codegen/enum-debug-niche.rs)0
-rw-r--r--tests/codegen/enum/enum-debug-tagged.rs (renamed from tests/codegen/enum-debug-tagged.rs)0
-rw-r--r--tests/codegen/enum/enum-discriminant-value.rs (renamed from tests/codegen/enum-discriminant-value.rs)0
-rw-r--r--tests/codegen/enum/enum-match.rs (renamed from tests/codegen/enum-match.rs)0
-rw-r--r--tests/codegen/enum/enum-u128.rs (renamed from tests/codegen/enum-u128.rs)0
-rw-r--r--tests/codegen/intrinsics/compare_bytes.rs34
-rw-r--r--tests/codegen/macos/i686-macosx-deployment-target.rs (renamed from tests/codegen/i686-macosx-deployment-target.rs)0
-rw-r--r--tests/codegen/macos/i686-no-macosx-deployment-target.rs (renamed from tests/codegen/i686-no-macosx-deployment-target.rs)0
-rw-r--r--tests/codegen/macos/x86_64-macosx-deployment-target.rs (renamed from tests/codegen/x86_64-macosx-deployment-target.rs)0
-rw-r--r--tests/codegen/macos/x86_64-no-macosx-deployment-target.rs (renamed from tests/codegen/x86_64-no-macosx-deployment-target.rs)0
-rw-r--r--tests/codegen/naked-fn/naked-functions.rs (renamed from tests/codegen/naked-functions.rs)0
-rw-r--r--tests/codegen/naked-fn/naked-nocoverage.rs (renamed from tests/codegen/naked-nocoverage.rs)0
-rw-r--r--tests/codegen/naked-fn/naked-noinline.rs (renamed from tests/codegen/naked-noinline.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-add-canonical-jump-tables-flag.rs (renamed from tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-add-enable-split-lto-unit-flag.rs (renamed from tests/codegen/sanitizer-cfi-add-enable-split-lto-unit-flag.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-checks-attr-no-sanitize.rs)2
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-checks.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-checks.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-attr-cfi-encoding.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs)96
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-emit-type-metadata-trait-objects.rs (renamed from tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-generalize-pointers.rs (renamed from tests/codegen/sanitizer-cfi-generalize-pointers.rs)0
-rw-r--r--tests/codegen/sanitizer/cfi-normalize-integers.rs (renamed from tests/codegen/sanitizer-cfi-normalize-integers.rs)0
-rw-r--r--tests/codegen/sanitizer/kasan-emits-instrumentation.rs (renamed from tests/codegen/sanitizer-kasan-emits-instrumentation.rs)4
-rw-r--r--tests/codegen/sanitizer/kcfi-add-kcfi-flag.rs (renamed from tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs)0
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs (renamed from tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs)2
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs (renamed from tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs)0
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs (renamed from tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs)0
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs (renamed from tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs)0
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs (renamed from tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs)0
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle.rs (renamed from tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs)0
-rw-r--r--tests/codegen/sanitizer/kcfi-emit-type-metadata-trait-objects.rs (renamed from tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs)0
-rw-r--r--tests/codegen/sanitizer/memory-track-origins.rs (renamed from tests/codegen/sanitizer-memory-track-orgins.rs)0
-rw-r--r--tests/codegen/sanitizer/memtag-attr-check.rs (renamed from tests/codegen/sanitizer_memtag_attr_check.rs)0
-rw-r--r--tests/codegen/sanitizer/no-sanitize-inlining.rs (renamed from tests/codegen/sanitizer-no-sanitize-inlining.rs)0
-rw-r--r--tests/codegen/sanitizer/no-sanitize.rs (renamed from tests/codegen/sanitizer-no-sanitize.rs)4
-rw-r--r--tests/codegen/sanitizer/safestack-attr-check.rs (renamed from tests/codegen/sanitizer-safestack-attr-check.rs)0
-rw-r--r--tests/codegen/sanitizer/sanitizer-recover.rs (renamed from tests/codegen/sanitizer-recover.rs)0
-rw-r--r--tests/codegen/sanitizer/scs-attr-check.rs (renamed from tests/codegen/sanitizer_scs_attr_check.rs)0
-rw-r--r--tests/codegen/simd/simd-wide-sum.rs (renamed from tests/codegen/simd-wide-sum.rs)0
-rw-r--r--tests/codegen/simd/simd_arith_offset.rs (renamed from tests/codegen/simd_arith_offset.rs)0
-rw-r--r--tests/codegen/simd/swap-simd-types.rs (renamed from tests/codegen/swap-simd-types.rs)0
-rw-r--r--tests/codegen/simd/unpadded-simd.rs (renamed from tests/codegen/unpadded-simd.rs)0
-rw-r--r--tests/codegen/unwind-abis/thiscall-unwind-abi.rs2
-rw-r--r--tests/codegen/vec-calloc-llvm14.rs144
-rw-r--r--tests/run-make/pretty-print-with-dep-file/Makefile9
-rw-r--r--tests/run-make/pretty-print-with-dep-file/with-dep.rs1
-rw-r--r--tests/run-make/unknown-mod-stdin/Makefile15
-rw-r--r--tests/run-make/unknown-mod-stdin/unknown-mod.stderr11
-rw-r--r--tests/run-make/unknown-mod-stdin/unknown-mod.stdout0
-rw-r--r--tests/rustdoc-gui/scrape-examples-toggle.goml12
-rw-r--r--tests/rustdoc-gui/search-error.goml6
-rw-r--r--tests/ui/abi/stack-protector.rs2
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr18
-rw-r--r--tests/ui/abi/unsupported.arm.stderr16
-rw-r--r--tests/ui/abi/unsupported.i686.stderr12
-rw-r--r--tests/ui/abi/unsupported.rs1
-rw-r--r--tests/ui/abi/unsupported.x64.stderr16
-rw-r--r--tests/ui/attributes/macro_export_on_decl_macro.rs9
-rw-r--r--tests/ui/attributes/macro_export_on_decl_macro.stderr16
-rw-r--r--tests/ui/const-generics/lifetime-in-const-param.rs9
-rw-r--r--tests/ui/const-generics/lifetime-in-const-param.stderr18
-rw-r--r--tests/ui/const_prop/ice-issue-111353.rs7
-rw-r--r--tests/ui/const_prop/ice-issue-96944.rs26
-rw-r--r--tests/ui/consts/const-compare-bytes-ub.rs41
-rw-r--r--tests/ui/consts/const-compare-bytes-ub.stderr54
-rw-r--r--tests/ui/consts/const-compare-bytes.rs27
-rw-r--r--tests/ui/extern/extern-thiscall.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-thiscall.rs38
-rw-r--r--tests/ui/feature-gates/feature-gate-thiscall.stderr115
-rw-r--r--tests/ui/for/issue-20605.next.stderr12
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.rs22
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.stderr13
-rw-r--r--tests/ui/issues/issue-100605.rs9
-rw-r--r--tests/ui/lazy-type-alias/auxiliary/eager.rs6
-rw-r--r--tests/ui/lazy-type-alias/auxiliary/lazy.rs4
-rw-r--r--tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr11
-rw-r--r--tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr11
-rw-r--r--tests/ui/lazy-type-alias/coerce-behind-lazy.rs16
-rw-r--r--tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs23
-rw-r--r--tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr15
-rw-r--r--tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr15
-rw-r--r--tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs16
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr5
-rw-r--r--tests/ui/lint/clashing-extern-fn.stderr124
-rw-r--r--tests/ui/lint/invalid-nan-comparison.stderr5
-rw-r--r--tests/ui/lint/issue-111359.stderr16
-rw-r--r--tests/ui/lint/issue-1866.stderr4
-rw-r--r--tests/ui/lint/lint-attr-everywhere-late.stderr104
-rw-r--r--tests/ui/lint/lint-missing-doc.stderr36
-rw-r--r--tests/ui/lint/lint-unconditional-drop-recursion.rs38
-rw-r--r--tests/ui/lint/lint-unconditional-drop-recursion.stderr17
-rw-r--r--tests/ui/lint/missing-copy-implementations-negative-copy.rs15
-rw-r--r--tests/ui/lint/missing-doc-private-macro.stderr12
-rw-r--r--tests/ui/missing_debug_impls.rs2
-rw-r--r--tests/ui/nll/guarantor-issue-46974.rs1
-rw-r--r--tests/ui/nll/guarantor-issue-46974.stderr3
-rw-r--r--tests/ui/panic-handler/weak-lang-item-2.rs12
-rw-r--r--tests/ui/proc-macro/meta-macro-hygiene.stdout2
-rw-r--r--tests/ui/proc-macro/nonterminal-token-hygiene.stdout2
-rw-r--r--tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs10
-rw-r--r--tests/ui/resolve/unresolved-segments-visibility.rs11
-rw-r--r--tests/ui/resolve/unresolved-segments-visibility.stderr9
-rw-r--r--tests/ui/span/visibility-ty-params.rs2
-rw-r--r--tests/ui/span/visibility-ty-params.stderr6
-rw-r--r--tests/ui/traits/new-solver/lazy-nested-obligations-2.rs2
-rw-r--r--tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr39
-rw-r--r--tests/ui/traits/new-solver/more-object-bound.stderr4
-rw-r--r--tests/ui/traits/new-solver/object-soundness-requires-generalization.rs20
-rw-r--r--tests/ui/type-alias-impl-trait/under-binder.rs9
-rw-r--r--tests/ui/type-alias-impl-trait/under-binder.stderr12
-rw-r--r--tests/ui/type/option-ref-advice.rs11
-rw-r--r--tests/ui/type/option-ref-advice.stderr (renamed from tests/ui/issues/issue-100605.stderr)8
-rw-r--r--tests/ui/use/use-self-type.stderr4
436 files changed, 6888 insertions, 3378 deletions
diff --git a/.gitmodules b/.gitmodules
index b48fddf963f..a13a2f5e01b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -33,7 +33,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/16.0-2023-06-05
+	branch = rustc/17.0-2023-07-29
 	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
diff --git a/Cargo.lock b/Cargo.lock
index 7cde7989bc0..3b270c14bb5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -154,7 +154,7 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -164,7 +164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
 dependencies = [
  "anstyle",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -797,7 +797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
 dependencies = [
  "nix",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1108,7 +1108,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
 dependencies = [
  "errno-dragonfly",
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1191,7 +1191,7 @@ dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall 0.2.16",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1910,7 +1910,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
 dependencies = [
  "hermit-abi 0.3.2",
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1927,7 +1927,7 @@ checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
 dependencies = [
  "hermit-abi 0.3.2",
  "rustix 0.38.2",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -2320,16 +2320,16 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
 dependencies = [
  "libc",
  "wasi",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "miow"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
+checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044"
 dependencies = [
- "windows-sys 0.42.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4046,6 +4046,7 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
+ "rustc_mir_build",
  "rustc_mir_dataflow",
  "rustc_serialize",
  "rustc_session",
@@ -4561,7 +4562,7 @@ dependencies = [
  "io-lifetimes",
  "libc",
  "linux-raw-sys 0.3.8",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4574,7 +4575,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys 0.4.3",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4611,11 +4612,11 @@ dependencies = [
 
 [[package]]
 name = "schannel"
-version = "0.1.21"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
 dependencies = [
- "windows-sys 0.42.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -5044,7 +5045,7 @@ dependencies = [
  "fastrand",
  "redox_syscall 0.3.5",
  "rustix 0.37.22",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -5085,7 +5086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
 dependencies = [
  "rustix 0.37.22",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -5264,7 +5265,7 @@ dependencies = [
  "num_cpus",
  "pin-project-lite",
  "socket2",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -5874,21 +5875,6 @@ checksum = "2f5bca94a32bf1e6a376522b6601275a3b611ee885ec0f1b6a05f17e8cfd3385"
 
 [[package]]
 name = "windows-sys"
-version = "0.42.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
@@ -5902,13 +5888,13 @@ version = "0.48.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
@@ -5919,84 +5905,42 @@ checksum = "b34c9a3b28cb41db7385546f7f9a8179348dffc89923dde66857b1ba5312f6b4"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
-[[package]]
-name = "windows_aarch64_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
-[[package]]
-name = "windows_x86_64_gnu"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
-[[package]]
-name = "windows_x86_64_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs
index e87f6e820a1..f825b10f489 100644
--- a/compiler/rustc_ast/src/expand/allocator.rs
+++ b/compiler/rustc_ast/src/expand/allocator.rs
@@ -33,29 +33,41 @@ pub enum AllocatorTy {
 
 pub struct AllocatorMethod {
     pub name: Symbol,
-    pub inputs: &'static [AllocatorTy],
+    pub inputs: &'static [AllocatorMethodInput],
     pub output: AllocatorTy,
 }
 
+pub struct AllocatorMethodInput {
+    pub name: &'static str,
+    pub ty: AllocatorTy,
+}
+
 pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
     AllocatorMethod {
         name: sym::alloc,
-        inputs: &[AllocatorTy::Layout],
+        inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }],
         output: AllocatorTy::ResultPtr,
     },
     AllocatorMethod {
         name: sym::dealloc,
-        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
+        inputs: &[
+            AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr },
+            AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout },
+        ],
         output: AllocatorTy::Unit,
     },
     AllocatorMethod {
         name: sym::realloc,
-        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
+        inputs: &[
+            AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr },
+            AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout },
+            AllocatorMethodInput { name: "new_size", ty: AllocatorTy::Usize },
+        ],
         output: AllocatorTy::ResultPtr,
     },
     AllocatorMethod {
         name: sym::alloc_zeroed,
-        inputs: &[AllocatorTy::Layout],
+        inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }],
         output: AllocatorTy::ResultPtr,
     },
 ];
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ac750690046..d29e9f9b3f6 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -512,11 +512,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
     }
 
-    fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
-        self.orig_opt_local_def_id(node)
-            .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
-    }
-
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
     ///
@@ -1521,209 +1516,86 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_id = self.create_def(
-            self.current_hir_id_owner.def_id,
-            opaque_ty_node_id,
-            DefPathData::ImplTrait,
-            opaque_ty_span,
-        );
-        debug!(?opaque_ty_def_id);
-
-        // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
-        // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
-        // exactly which ones those are.
-        let lifetimes_to_remap = match origin {
+        let captured_lifetimes_to_duplicate = match origin {
             hir::OpaqueTyOrigin::TyAlias { .. } => {
-                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
+                // lifetimes, since we don't have the issue that any are late-bound.
                 Vec::new()
             }
-            hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
-                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-                // we only keep the lifetimes that appear in the `impl Debug` itself:
+            hir::OpaqueTyOrigin::FnReturn(..) => {
+                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+                // example, we only need to duplicate lifetimes that appear in the
+                // bounds, since those are the only ones that are captured by the opaque.
                 lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
             }
+            hir::OpaqueTyOrigin::AsyncFn(..) => {
+                unreachable!("should be using `lower_async_fn_ret_ty`")
+            }
         };
-        debug!(?lifetimes_to_remap);
-
-        let mut new_remapping = FxHashMap::default();
-
-        // Contains the new lifetime definitions created for the TAIT (if any).
-        // If this opaque type is only capturing a subset of the lifetimes (those that appear in
-        // bounds), then create the new lifetime parameters required and create a mapping from the
-        // old `'a` (on the function) to the new `'a` (on the opaque type).
-        let collected_lifetimes =
-            self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
-        debug!(?collected_lifetimes);
-        debug!(?new_remapping);
-
-        // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
-        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
-        let collected_lifetime_mapping: Vec<_> = collected_lifetimes
-            .iter()
-            .map(|(node_id, lifetime)| {
-                let id = self.next_node_id();
-                let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
-                let def_id = self.local_def_id(*node_id);
-                (lifetime, def_id)
-            })
-            .collect();
-        debug!(?collected_lifetime_mapping);
-
-        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            // Install the remapping from old to new (if any):
-            lctx.with_remapping(new_remapping, |lctx| {
-                // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
-                // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
-                // containing `&['x]`.
-                let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                    |&(new_node_id, lifetime)| {
-                        let hir_id = lctx.lower_node_id(new_node_id);
-                        debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
-
-                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
-                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                        } else {
-                            (
-                                hir::ParamName::Plain(lifetime.ident),
-                                hir::LifetimeParamKind::Explicit,
-                            )
-                        };
+        debug!(?captured_lifetimes_to_duplicate);
 
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: lctx.local_def_id(new_node_id),
-                            name,
-                            span: lifetime.ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-                debug!(?lifetime_defs);
-
-                // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
-                // get back Debug + 'a1, which is suitable for use on the TAIT.
-                let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
-                debug!(?hir_bounds);
-
-                let lifetime_mapping = if in_trait {
-                    Some(
-                        &*self.arena.alloc_from_iter(
-                            collected_lifetime_mapping
-                                .iter()
-                                .map(|(lifetime, def_id)| (**lifetime, *def_id)),
-                        ),
-                    )
-                } else {
-                    None
-                };
-
-                let opaque_ty_item = hir::OpaqueTy {
-                    generics: self.arena.alloc(hir::Generics {
-                        params: lifetime_defs,
-                        predicates: &[],
-                        has_where_clause_predicates: false,
-                        where_clause_span: lctx.lower_span(span),
-                        span: lctx.lower_span(span),
-                    }),
-                    bounds: hir_bounds,
-                    origin,
-                    lifetime_mapping,
-                    in_trait,
-                };
-                debug!(?opaque_ty_item);
-
-                lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
-            })
-        });
-
-        // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-        hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            self.arena.alloc_from_iter(
-                collected_lifetime_mapping
-                    .iter()
-                    .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
-            ),
+        self.lower_opaque_inner(
+            opaque_ty_node_id,
+            origin,
             in_trait,
+            captured_lifetimes_to_duplicate,
+            span,
+            opaque_ty_span,
+            |this| this.lower_param_bounds(bounds, itctx),
         )
     }
 
-    /// Registers a new opaque type with the proper `NodeId`s and
-    /// returns the lowered node-ID for the opaque type.
-    fn generate_opaque_type(
+    fn lower_opaque_inner(
         &mut self,
-        opaque_ty_id: LocalDefId,
-        opaque_ty_item: hir::OpaqueTy<'hir>,
+        opaque_ty_node_id: NodeId,
+        origin: hir::OpaqueTyOrigin,
+        in_trait: bool,
+        captured_lifetimes_to_duplicate: Vec<Lifetime>,
         span: Span,
         opaque_ty_span: Span,
-    ) -> hir::OwnerNode<'hir> {
-        let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
-        // Generate an `type Foo = impl Trait;` declaration.
-        trace!("registering opaque type with id {:#?}", opaque_ty_id);
-        let opaque_ty_item = hir::Item {
-            owner_id: hir::OwnerId { def_id: opaque_ty_id },
-            ident: Ident::empty(),
-            kind: opaque_ty_item_kind,
-            vis_span: self.lower_span(span.shrink_to_lo()),
-            span: self.lower_span(opaque_ty_span),
-        };
-        hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
-    }
-
-    /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be
-    /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
-    /// new definition, adds it to the remapping with the definition of the given lifetime and
-    /// returns a list of lifetimes to be lowered afterwards.
-    fn create_lifetime_defs(
-        &mut self,
-        parent_def_id: LocalDefId,
-        lifetimes_in_bounds: &[Lifetime],
-        remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
-    ) -> Vec<(NodeId, Lifetime)> {
-        let mut result = Vec::new();
+        lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
+    ) -> hir::TyKind<'hir> {
+        let opaque_ty_def_id = self.create_def(
+            self.current_hir_id_owner.def_id,
+            opaque_ty_node_id,
+            DefPathData::ImplTrait,
+            opaque_ty_span,
+        );
+        debug!(?opaque_ty_def_id);
 
-        for lifetime in lifetimes_in_bounds {
+        // Map from captured (old) lifetime to synthetic (new) lifetime.
+        // Used to resolve lifetimes in the bounds of the opaque.
+        let mut captured_to_synthesized_mapping = FxHashMap::default();
+        // List of (early-bound) synthetic lifetimes that are owned by the opaque.
+        // This is used to create the `hir::Generics` owned by the opaque.
+        let mut synthesized_lifetime_definitions = vec![];
+        // Pairs of lifetime arg (that resolves to the captured lifetime)
+        // and the def-id of the (early-bound) synthetic lifetime definition.
+        // This is used both to create generics for the `TyKind::OpaqueDef` that
+        // we return, and also as a captured lifetime mapping for RPITITs.
+        let mut synthesized_lifetime_args = vec![];
+
+        for lifetime in captured_lifetimes_to_duplicate {
             let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
-            debug!(?res);
-
-            match res {
-                LifetimeRes::Param { param: old_def_id, binder: _ } => {
-                    if remapping.get(&old_def_id).is_none() {
-                        let node_id = self.next_node_id();
-
-                        let new_def_id = self.create_def(
-                            parent_def_id,
-                            node_id,
-                            DefPathData::LifetimeNs(lifetime.ident.name),
-                            lifetime.ident.span,
-                        );
-                        remapping.insert(old_def_id, new_def_id);
-
-                        result.push((node_id, *lifetime));
-                    }
-                }
+            let old_def_id = match res {
+                LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
-                        let node_id = self.next_node_id();
-
-                        let new_def_id = self.create_def(
-                            parent_def_id,
-                            node_id,
-                            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                            lifetime.ident.span,
-                        );
-                        remapping.insert(old_def_id, new_def_id);
-
-                        result.push((node_id, *lifetime));
+                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
+                        old_def_id
+                    } else {
+                        self.tcx
+                            .sess
+                            .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime");
+                        continue;
                     }
                 }
 
-                LifetimeRes::Static | LifetimeRes::Error => {}
+                // Opaques do not capture `'static`
+                LifetimeRes::Static | LifetimeRes::Error => {
+                    continue;
+                }
 
                 res => {
                     let bug_msg = format!(
@@ -1732,10 +1604,113 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     );
                     span_bug!(lifetime.ident.span, "{}", bug_msg);
                 }
+            };
+
+            if captured_to_synthesized_mapping.get(&old_def_id).is_none() {
+                // Create a new lifetime parameter local to the opaque.
+                let duplicated_lifetime_node_id = self.next_node_id();
+                let duplicated_lifetime_def_id = self.create_def(
+                    opaque_ty_def_id,
+                    duplicated_lifetime_node_id,
+                    DefPathData::LifetimeNs(lifetime.ident.name),
+                    lifetime.ident.span,
+                );
+                captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
+                // FIXME: Instead of doing this, we could move this whole loop
+                // into the `with_hir_id_owner`, then just directly construct
+                // the `hir::GenericParam` here.
+                synthesized_lifetime_definitions.push((
+                    duplicated_lifetime_node_id,
+                    duplicated_lifetime_def_id,
+                    lifetime.ident,
+                ));
+
+                // Now make an arg that we can use for the substs of the opaque tykind.
+                let id = self.next_node_id();
+                let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
+                let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);
+                synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id))
             }
         }
 
-        result
+        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+            // Install the remapping from old to new (if any). This makes sure that
+            // any lifetimes that would have resolved to the def-id of captured
+            // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
+            let bounds = this
+                .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
+
+            let generic_params = this.arena.alloc_from_iter(
+                synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| {
+                    let hir_id = this.lower_node_id(new_node_id);
+                    let (name, kind) = if ident.name == kw::UnderscoreLifetime {
+                        (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                    } else {
+                        (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
+                    };
+
+                    hir::GenericParam {
+                        hir_id,
+                        def_id: new_def_id,
+                        name,
+                        span: ident.span,
+                        pure_wrt_drop: false,
+                        kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
+                        source: hir::GenericParamSource::Generics,
+                    }
+                }),
+            );
+            debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+            let lifetime_mapping = if in_trait {
+                Some(&*self.arena.alloc_slice(&synthesized_lifetime_args))
+            } else {
+                None
+            };
+
+            let opaque_ty_item = hir::OpaqueTy {
+                generics: this.arena.alloc(hir::Generics {
+                    params: generic_params,
+                    predicates: &[],
+                    has_where_clause_predicates: false,
+                    where_clause_span: this.lower_span(span),
+                    span: this.lower_span(span),
+                }),
+                bounds,
+                origin,
+                lifetime_mapping,
+                in_trait,
+            };
+
+            // Generate an `type Foo = impl Trait;` declaration.
+            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+            let opaque_ty_item = hir::Item {
+                owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
+                ident: Ident::empty(),
+                kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
+                vis_span: this.lower_span(span.shrink_to_lo()),
+                span: this.lower_span(opaque_ty_span),
+            };
+
+            hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
+        });
+
+        let generic_args = self.arena.alloc_from_iter(
+            synthesized_lifetime_args
+                .iter()
+                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+        );
+
+        // Create the `Foo<...>` reference itself. Note that the `type
+        // Foo = impl Trait` is, internally, created as a child of the
+        // async fn, so the *type parameters* are inherited. It's
+        // only the lifetime parameters that we must supply.
+        hir::TyKind::OpaqueDef(
+            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+            generic_args,
+            in_trait,
+        )
     }
 
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
@@ -1813,9 +1788,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
             }
 
+            let fn_def_id = self.local_def_id(fn_node_id);
             self.lower_async_fn_ret_ty(
                 &decl.output,
-                fn_node_id,
+                fn_def_id,
                 ret_id,
                 matches!(kind, FnDeclKind::Trait),
             )
@@ -1892,151 +1868,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FnRetTy,
-        fn_node_id: NodeId,
+        fn_def_id: LocalDefId,
         opaque_ty_node_id: NodeId,
         in_trait: bool,
     ) -> hir::FnRetTy<'hir> {
-        let span = output.span();
-
+        let span = self.lower_span(output.span());
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let fn_def_id = self.local_def_id(fn_node_id);
-
-        let opaque_ty_def_id =
-            self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span);
-
-        // When we create the opaque type for this async fn, it is going to have
-        // to capture all the lifetimes involved in the signature (including in the
-        // return type). This is done by introducing lifetime parameters for:
-        //
-        // - all the explicitly declared lifetimes from the impl and function itself;
-        // - all the elided lifetimes in the fn arguments;
-        // - all the elided lifetimes in the return type.
-        //
-        // So for example in this snippet:
-        //
-        // ```rust
-        // impl<'a> Foo<'a> {
-        //   async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
-        //   //               ^ '0                       ^ '1     ^ '2
-        //   // elided lifetimes used below
-        //   }
-        // }
-        // ```
-        //
-        // we would create an opaque type like:
-        //
-        // ```
-        // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
-        // ```
-        //
-        // and we would then desugar `bar` to the equivalent of:
-        //
-        // ```rust
-        // impl<'a> Foo<'a> {
-        //   fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
-        // }
-        // ```
-        //
-        // Note that the final parameter to `Bar` is `'_`, not `'2` --
-        // this is because the elided lifetimes from the return type
-        // should be figured out using the ordinary elision rules, and
-        // this desugaring achieves that.
-
-        // Calculate all the lifetimes that should be captured
-        // by the opaque type. This should include all in-scope
-        // lifetime parameters, including those defined in-band.
-
-        // Contains the new lifetime definitions created for the TAIT (if any) generated for the
-        // return type.
-        let mut collected_lifetimes = Vec::new();
-        let mut new_remapping = FxHashMap::default();
-
-        let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
-        debug!(?extra_lifetime_params);
-        for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let outer_def_id = self.orig_local_def_id(outer_node_id);
-            let inner_node_id = self.next_node_id();
-
-            // Add a definition for the in scope lifetime def.
-            let inner_def_id = self.create_def(
-                opaque_ty_def_id,
-                inner_node_id,
-                DefPathData::LifetimeNs(ident.name),
-                ident.span,
-            );
-            new_remapping.insert(outer_def_id, inner_def_id);
-
-            let inner_res = match outer_res {
-                // Input lifetime like `'a`:
-                LifetimeRes::Param { param, .. } => {
-                    LifetimeRes::Param { param, binder: fn_node_id }
-                }
-                // Input lifetime like `'1`:
-                LifetimeRes::Fresh { param, .. } => {
-                    LifetimeRes::Fresh { param, binder: fn_node_id }
-                }
-                LifetimeRes::Static | LifetimeRes::Error => continue,
-                res => {
-                    panic!(
-                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
-                        res, ident, ident.span
-                    )
-                }
-            };
-
-            let lifetime = Lifetime { id: outer_node_id, ident };
-            collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
-        }
-        debug!(?collected_lifetimes);
-
-        // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
-        // find out exactly which ones those are.
-        // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-        // we only keep the lifetimes that appear in the `impl Debug` itself:
-        let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
-        debug!(?lifetimes_to_remap);
-
-        // If this opaque type is only capturing a subset of the lifetimes (those that appear in
-        // bounds), then create the new lifetime parameters required and create a mapping from the
-        // old `'a` (on the function) to the new `'a` (on the opaque type).
-        collected_lifetimes.extend(
-            self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
-                .into_iter()
-                .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
-        );
-        debug!(?collected_lifetimes);
-        debug!(?new_remapping);
-
-        // This creates pairs of HIR lifetimes and def_ids. In the given example `type
-        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
-        // new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
-        // `TestReturn`.
-        let collected_lifetime_mapping: Vec<_> = collected_lifetimes
-            .iter()
-            .map(|(node_id, lifetime, res)| {
-                let id = self.next_node_id();
-                let res = res.unwrap_or(
-                    self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
-                );
-                let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
-                let def_id = self.local_def_id(*node_id);
-                (lifetime, def_id)
-            })
+        let captured_lifetimes: Vec<_> = self
+            .resolver
+            .take_extra_lifetime_params(opaque_ty_node_id)
+            .into_iter()
+            .map(|(ident, id, _)| Lifetime { id, ident })
             .collect();
-        debug!(?collected_lifetime_mapping);
 
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
-            // Install the remapping from old to new (if any):
-            this.with_remapping(new_remapping, |this| {
-                // We have to be careful to get elision right here. The
-                // idea is that we create a lifetime parameter for each
-                // lifetime in the return type. So, given a return type
-                // like `async fn foo(..) -> &[&u32]`, we lower to `impl
-                // Future<Output = &'1 [ &'2 u32 ]>`.
-                //
-                // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
-                // hence the elision takes place at the fn site.
+        let opaque_ty_ref = self.lower_opaque_inner(
+            opaque_ty_node_id,
+            hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+            in_trait,
+            captured_lifetimes,
+            span,
+            opaque_ty_span,
+            |this| {
                 let future_bound = this.lower_async_fn_output_type_to_future_bound(
                     output,
                     span,
@@ -2052,96 +1905,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     },
                 );
-
-                let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                    |&(new_node_id, lifetime, _)| {
-                        let hir_id = this.lower_node_id(new_node_id);
-                        debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
-
-                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
-                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                        } else {
-                            (
-                                hir::ParamName::Plain(lifetime.ident),
-                                hir::LifetimeParamKind::Explicit,
-                            )
-                        };
-
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: this.local_def_id(new_node_id),
-                            name,
-                            span: lifetime.ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-                debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
-                let lifetime_mapping = if in_trait {
-                    Some(
-                        &*self.arena.alloc_from_iter(
-                            collected_lifetime_mapping
-                                .iter()
-                                .map(|(lifetime, def_id)| (**lifetime, *def_id)),
-                        ),
-                    )
-                } else {
-                    None
-                };
-
-                let opaque_ty_item = hir::OpaqueTy {
-                    generics: this.arena.alloc(hir::Generics {
-                        params: generic_params,
-                        predicates: &[],
-                        has_where_clause_predicates: false,
-                        where_clause_span: this.lower_span(span),
-                        span: this.lower_span(span),
-                    }),
-                    bounds: arena_vec![this; future_bound],
-                    origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                    lifetime_mapping,
-                    in_trait,
-                };
-
-                trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-                this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
-            })
-        });
-
-        // As documented above, we need to create the lifetime
-        // arguments to our opaque type. Continuing with our example,
-        // we're creating the type arguments for the return type:
-        //
-        // ```
-        // Bar<'a, 'b, '0, '1, '_>
-        // ```
-        //
-        // For the "input" lifetime parameters, we wish to create
-        // references to the parameters themselves, including the
-        // "implicit" ones created from parameter types (`'a`, `'b`,
-        // '`0`, `'1`).
-        //
-        // For the "output" lifetime parameters, we just want to
-        // generate `'_`.
-        let generic_args = self.arena.alloc_from_iter(
-            collected_lifetime_mapping
-                .iter()
-                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+                arena_vec![this; future_bound]
+            },
         );
 
-        // Create the `Foo<...>` reference itself. Note that the `type
-        // Foo = impl Trait` is, internally, created as a child of the
-        // async fn, so the *type parameters* are inherited. It's
-        // only the lifetime parameters that we must supply.
-        let opaque_ty_ref = hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            generic_args,
-            in_trait,
-        );
         let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 3989fc48619..0e0bdf17389 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -1,6 +1,6 @@
 use super::ResolverAstLoweringExt;
 use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
-use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
+use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
 use rustc_hir::def::LifetimeRes;
 use rustc_middle::span_bug;
 use rustc_middle::ty::ResolverAstLowering;
@@ -94,12 +94,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
     }
 }
 
-pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
-    let mut visitor = LifetimeCollectVisitor::new(resolver);
-    visitor.visit_fn_ret_ty(ret_ty);
-    visitor.collected_lifetimes
-}
-
 pub fn lifetimes_in_bounds(
     resolver: &ResolverAstLowering,
     bounds: &GenericBounds,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index be6eb2d1d12..337af89b21f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -516,7 +516,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         // be the same as those of the ADT.
                         // FIXME: We should be able to do something similar to
                         // match_adt_and_segment in this case.
-                        Res::Def(DefKind::TyAlias, _) => (),
+                        Res::Def(DefKind::TyAlias { .. }, _) => (),
                         _ => {
                             if let Some(last_segment) = path.segments.last() {
                                 if let Some(highlight) = self.match_adt_and_segment(
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 053f5730f6e..1bec00add55 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -2,7 +2,7 @@ use crate::util::check_builtin_macro_attribute;
 
 use crate::errors;
 use rustc_ast::expand::allocator::{
-    global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
+    global_fn_name, AllocatorMethod, AllocatorMethodInput, AllocatorTy, ALLOCATOR_METHODS,
 };
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
@@ -70,19 +70,13 @@ struct AllocFnFactory<'a, 'b> {
 impl AllocFnFactory<'_, '_> {
     fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
         let mut abi_args = ThinVec::new();
-        let mut i = 0;
-        let mut mk = || {
-            let name = Ident::from_str_and_span(&format!("arg{i}"), self.span);
-            i += 1;
-            name
-        };
-        let args = method.inputs.iter().map(|ty| self.arg_ty(ty, &mut abi_args, &mut mk)).collect();
+        let args = method.inputs.iter().map(|input| self.arg_ty(input, &mut abi_args)).collect();
         let result = self.call_allocator(method.name, args);
-        let (output_ty, output_expr) = self.ret_ty(&method.output, result);
+        let output_ty = self.ret_ty(&method.output);
         let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
         let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
         let sig = FnSig { decl, header, span: self.span };
-        let body = Some(self.cx.block_expr(output_expr));
+        let body = Some(self.cx.block_expr(result));
         let kind = ItemKind::Fn(Box::new(Fn {
             defaultness: ast::Defaultness::Final,
             sig,
@@ -113,18 +107,19 @@ impl AllocFnFactory<'_, '_> {
         thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)]
     }
 
-    fn arg_ty(
-        &self,
-        ty: &AllocatorTy,
-        args: &mut ThinVec<Param>,
-        ident: &mut dyn FnMut() -> Ident,
-    ) -> P<Expr> {
-        match *ty {
+    fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> P<Expr> {
+        match input.ty {
             AllocatorTy::Layout => {
+                // If an allocator method is ever introduced having multiple
+                // Layout arguments, these argument names need to be
+                // disambiguated somehow. Currently the generated code would
+                // fail to compile with "identifier is bound more than once in
+                // this parameter list".
+                let size = Ident::from_str_and_span("size", self.span);
+                let align = Ident::from_str_and_span("align", self.span);
+
                 let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
                 let ty_usize = self.cx.ty_path(usize);
-                let size = ident();
-                let align = ident();
                 args.push(self.cx.param(self.span, size, ty_usize.clone()));
                 args.push(self.cx.param(self.span, align, ty_usize));
 
@@ -138,14 +133,13 @@ impl AllocFnFactory<'_, '_> {
             }
 
             AllocatorTy::Ptr => {
-                let ident = ident();
+                let ident = Ident::from_str_and_span(input.name, self.span);
                 args.push(self.cx.param(self.span, ident, self.ptr_u8()));
-                let arg = self.cx.expr_ident(self.span, ident);
-                self.cx.expr_cast(self.span, arg, self.ptr_u8())
+                self.cx.expr_ident(self.span, ident)
             }
 
             AllocatorTy::Usize => {
-                let ident = ident();
+                let ident = Ident::from_str_and_span(input.name, self.span);
                 args.push(self.cx.param(self.span, ident, self.usize()));
                 self.cx.expr_ident(self.span, ident)
             }
@@ -156,18 +150,11 @@ impl AllocFnFactory<'_, '_> {
         }
     }
 
-    fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) {
+    fn ret_ty(&self, ty: &AllocatorTy) -> P<Ty> {
         match *ty {
-            AllocatorTy::ResultPtr => {
-                // We're creating:
-                //
-                //      #expr as *mut u8
-
-                let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8());
-                (self.ptr_u8(), expr)
-            }
+            AllocatorTy::ResultPtr => self.ptr_u8(),
 
-            AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), expr),
+            AllocatorTy::Unit => self.cx.ty(self.span, TyKind::Tup(ThinVec::new())),
 
             AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
                 panic!("can't convert `AllocatorTy` to an output")
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index e92280b26b0..4e4c595de82 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -39,8 +39,8 @@ fn codegen_inner(
     if kind == AllocatorKind::Default {
         for method in ALLOCATOR_METHODS {
             let mut arg_tys = Vec::with_capacity(method.inputs.len());
-            for ty in method.inputs.iter() {
-                match *ty {
+            for input in method.inputs.iter() {
+                match input.ty {
                     AllocatorTy::Layout => {
                         arg_tys.push(usize_ty); // size
                         arg_tys.push(usize_ty); // align
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index e3006b253b7..36e9ba9c7f8 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1155,6 +1155,20 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
         }
 
+        sym::compare_bytes => {
+            intrinsic_args!(fx, args => (lhs_ptr, rhs_ptr, bytes_val); intrinsic);
+            let lhs_ptr = lhs_ptr.load_scalar(fx);
+            let rhs_ptr = rhs_ptr.load_scalar(fx);
+            let bytes_val = bytes_val.load_scalar(fx);
+
+            let params = vec![AbiParam::new(fx.pointer_type); 3];
+            let returns = vec![AbiParam::new(types::I32)];
+            let args = &[lhs_ptr, rhs_ptr, bytes_val];
+            // Here we assume that the `memcmp` provided by the target is a NOP for size 0.
+            let cmp = fx.lib_call("memcmp", params, returns, args)[0];
+            ret.write_cvalue(fx, CValue::by_val(cmp, ret.layout()));
+        }
+
         sym::const_allocate => {
             intrinsic_args!(fx, args => (_size, _align); intrinsic);
 
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index 13f88192bbc..edd7ab722f6 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -27,8 +27,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
     if kind == AllocatorKind::Default {
         for method in ALLOCATOR_METHODS {
             let mut types = Vec::with_capacity(method.inputs.len());
-            for ty in method.inputs.iter() {
-                match *ty {
+            for input in method.inputs.iter() {
+                match input.ty {
                     AllocatorTy::Layout => {
                         types.push(usize);
                         types.push(usize);
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 68edde13829..f8c32c6dbbb 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -302,6 +302,21 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     }
                 }
 
+                sym::compare_bytes => {
+                    let a = args[0].immediate();
+                    let b = args[1].immediate();
+                    let n = args[2].immediate();
+
+                    let void_ptr_type = self.context.new_type::<*const ()>();
+                    let a_ptr = self.bitcast(a, void_ptr_type);
+                    let b_ptr = self.bitcast(b, void_ptr_type);
+
+                    // Here we assume that the `memcmp` provided by the target is a NOP for size 0.
+                    let builtin = self.context.get_builtin_function("memcmp");
+                    let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
+                    self.sext(cmp, self.type_ix(32))
+                }
+
                 sym::black_box => {
                     args[0].val.store(self, result);
 
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index ca123334fca..8bb93025c45 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -34,8 +34,8 @@ pub(crate) unsafe fn codegen(
     if kind == AllocatorKind::Default {
         for method in ALLOCATOR_METHODS {
             let mut args = Vec::with_capacity(method.inputs.len());
-            for ty in method.inputs.iter() {
-                match *ty {
+            for input in method.inputs.iter() {
+                match input.ty {
                     AllocatorTy::Layout => {
                         args.push(usize); // size
                         args.push(usize); // align
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 3577fb2d951..b4f7e20e05d 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -145,6 +145,17 @@ pub unsafe fn create_module<'ll>(
             target_data_layout = target_data_layout.replace("-n32:64-", "-n64-");
         }
     }
+    if llvm_version < (17, 0, 0) {
+        if sess.target.arch.starts_with("powerpc") {
+            // LLVM 17 specifies function pointer alignment for ppc:
+            // https://reviews.llvm.org/D147016
+            target_data_layout = target_data_layout
+                .replace("-Fn32", "")
+                .replace("-Fi32", "")
+                .replace("-Fn64", "")
+                .replace("-Fi64", "");
+        }
+    }
 
     // Ensure the data-layout values hardcoded remain the defaults.
     if sess.target.is_builtin {
@@ -891,7 +902,8 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.prefetch", fn(ptr, t_i32, t_i32, t_i32) -> void);
 
         // This isn't an "LLVM intrinsic", but LLVM's optimization passes
-        // recognize it like one and we assume it exists in `core::slice::cmp`
+        // recognize it like one (including turning it into `bcmp` sometimes)
+        // and we use it to implement intrinsics like `raw_eq` and `compare_bytes`
         match self.sess().target.arch.as_ref() {
             "avr" | "msp430" => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i16),
             _ => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i32),
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 6f1e4c5178a..a9b06030e70 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -329,6 +329,16 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 }
             }
 
+            sym::compare_bytes => {
+                // Here we assume that the `memcmp` provided by the target is a NOP for size 0.
+                let cmp = self.call_intrinsic(
+                    "memcmp",
+                    &[args[0].immediate(), args[1].immediate(), args[2].immediate()],
+                );
+                // Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`.
+                self.sext(cmp, self.type_ix(32))
+            }
+
             sym::black_box => {
                 args[0].val.store(self, result);
                 let result_val_span = [result.llval];
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index cbe7e519079..326b28ad104 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -233,15 +233,6 @@ fn exported_symbols_provider_local(
             ));
         }
 
-        symbols.push((
-            ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)),
-            SymbolExportInfo {
-                level: SymbolExportLevel::Rust,
-                kind: SymbolExportKind::Text,
-                used: false,
-            },
-        ));
-
         let exported_symbol =
             ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE));
         symbols.push((
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 64c6d17469b..e7c3906d977 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -441,7 +441,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             LocalRef::Place(place) => place,
             LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
             LocalRef::Operand(..) => {
-                if place_ref.has_deref() {
+                if place_ref.is_indirect_first_projection() {
                     base = 1;
                     let cg_base = self.codegen_consume(
                         bx,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 98e561b0aef..c370ba9be56 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -29,7 +29,6 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("aclass", Some(sym::arm_target_feature)),
     ("aes", Some(sym::arm_target_feature)),
     ("crc", Some(sym::arm_target_feature)),
-    ("crypto", Some(sym::arm_target_feature)),
     ("d32", Some(sym::arm_target_feature)),
     ("dotprod", Some(sym::arm_target_feature)),
     ("dsp", Some(sym::arm_target_feature)),
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 123eb3125f0..f22cd919c36 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -261,6 +261,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::write_bytes => {
                 self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?;
             }
+            sym::compare_bytes => {
+                let result = self.compare_bytes_intrinsic(&args[0], &args[1], &args[2])?;
+                self.write_scalar(result, dest)?;
+            }
             sym::arith_offset => {
                 let ptr = self.read_pointer(&args[0])?;
                 let offset_count = self.read_target_isize(&args[1])?;
@@ -643,6 +647,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.write_bytes_ptr(dst, bytes)
     }
 
+    pub(crate) fn compare_bytes_intrinsic(
+        &mut self,
+        left: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        right: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        byte_count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+    ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
+        let left = self.read_pointer(left)?;
+        let right = self.read_pointer(right)?;
+        let n = Size::from_bytes(self.read_target_usize(byte_count)?);
+
+        let left_bytes = self.read_bytes_ptr_strip_provenance(left, n)?;
+        let right_bytes = self.read_bytes_ptr_strip_provenance(right, n)?;
+
+        // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing.
+        let result = Ord::cmp(left_bytes, right_bytes) as i32;
+        Ok(Scalar::from_i32(result))
+    }
+
     pub(crate) fn raw_eq_intrinsic(
         &mut self,
         lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 2dc856528f5..ec226808f1b 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -826,10 +826,10 @@ where
                 // predicate like `where Self: Sized` with `Self = dyn Trait`.
                 // See #102553 for an example of such a predicate.
                 if src.layout().is_unsized() {
-                    throw_inval!(SizeOfUnsizedType(src.layout().ty));
+                    throw_inval!(ConstPropNonsense);
                 }
                 if dest.layout().is_unsized() {
-                    throw_inval!(SizeOfUnsizedType(dest.layout().ty));
+                    throw_inval!(ConstPropNonsense);
                 }
                 assert_eq!(src.layout().size, dest.layout().size);
                 // Yay, we got a value that we can write directly.
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 539b58b7e9b..882097ad2c3 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -101,7 +101,7 @@ where
         let (meta, offset) = if field_layout.is_unsized() {
             if base.layout().is_sized() {
                 // An unsized field of a sized type? Sure...
-                // But const-prop actually feeds us such nonsense MIR!
+                // But const-prop actually feeds us such nonsense MIR! (see test `const_prop/issue-86351.rs`)
                 throw_inval!(ConstPropNonsense);
             }
             let base_meta = base.meta(self)?;
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 0ef5522729a..f04c73105d2 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -247,7 +247,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             AddressOf(_, place) => {
                 // Figure out whether this is an addr_of of an already raw place.
-                let place_base_raw = if place.has_deref() {
+                let place_base_raw = if place.is_indirect_first_projection() {
                     let ty = self.frame().body.local_decls[place.local].ty;
                     ty.is_unsafe_ptr()
                 } else {
@@ -269,7 +269,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
                 let layout = self.layout_of(ty)?;
                 if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() {
-                    // FIXME: This should be a span_bug (#80742)
+                    // FIXME: This should be a span_bug, but const generics can run MIR
+                    // that is not properly type-checked yet (#97477).
                     self.tcx.sess.delay_span_bug(
                         self.frame().current_span(),
                         format!("{null_op:?} MIR operator called for unsized type {ty}"),
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index d4532873854..60dc9b20077 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -391,6 +391,10 @@ fn run_compiler(
                         pretty::print_after_hir_lowering(tcx, *ppm);
                         Ok(())
                     })?;
+
+                    // Make sure the `output_filenames` query is run for its side
+                    // effects of writing the dep-info and reporting errors.
+                    queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
                 } else {
                     let krate = queries.parse()?.steal();
                     pretty::print_after_parsing(sess, &krate, *ppm);
diff --git a/compiler/rustc_error_codes/src/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md
index eba2d3b1417..383ca61f6c4 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0577.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0577.md
@@ -3,7 +3,7 @@ Something other than a module was found in visibility scope.
 Erroneous code example:
 
 ```compile_fail,E0577,edition2018
-pub struct Sea;
+pub enum Sea {}
 
 pub (in crate::Sea) struct Shark; // error!
 
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 0170d52e82a..b1f74643b69 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -53,6 +53,8 @@ declare_features! (
     /// Allows the sysV64 ABI to be specified on all platforms
     /// instead of just the platforms on which it is the C ABI.
     (accepted, abi_sysv64, "1.24.0", Some(36167), None),
+    /// Allows using the `thiscall` ABI.
+    (accepted, abi_thiscall, "1.19.0", None, None),
     /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
     (accepted, adx_target_feature, "1.61.0", Some(44839), None),
     /// Allows explicit discriminants on non-unit enum variants.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 2a0dab64af5..ede3570510a 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -156,8 +156,6 @@ declare_features! (
     // -------------------------------------------------------------------------
     // no-tracking-issue-start
 
-    /// Allows using the `thiscall` ABI.
-    (active, abi_thiscall, "1.19.0", None, None),
     /// Allows using the `unadjusted` ABI; perma-unstable.
     (active, abi_unadjusted, "1.16.0", None, None),
     /// Allows using the `vectorcall` ABI.
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index beb6307846d..69e33115922 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -108,8 +108,6 @@ impl UnstableFeatures {
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
-        // FIXME (#28244): enforce that active features have issue numbers
-        // assert!(info.issue.is_some())
         info.issue
     } else {
         // search in Accepted, Removed, or Stable Removed features
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 3a4eb90f7f9..64271309664 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -61,7 +61,9 @@ pub enum DefKind {
     Variant,
     Trait,
     /// Type alias: `type Foo = Bar;`
-    TyAlias,
+    TyAlias {
+        lazy: bool,
+    },
     /// Type from an `extern` block.
     ForeignTy,
     /// Trait alias: `trait IntIterator = Iterator<Item = i32>;`
@@ -141,7 +143,7 @@ impl DefKind {
             DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
             DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
             DefKind::OpaqueTy => "opaque type",
-            DefKind::TyAlias => "type alias",
+            DefKind::TyAlias { .. } => "type alias",
             DefKind::TraitAlias => "trait alias",
             DefKind::AssocTy => "associated type",
             DefKind::Union => "union",
@@ -197,7 +199,7 @@ impl DefKind {
             | DefKind::Variant
             | DefKind::Trait
             | DefKind::OpaqueTy
-            | DefKind::TyAlias
+            | DefKind::TyAlias { .. }
             | DefKind::ForeignTy
             | DefKind::TraitAlias
             | DefKind::AssocTy
@@ -248,7 +250,7 @@ impl DefKind {
             | DefKind::Enum
             | DefKind::Variant
             | DefKind::Trait
-            | DefKind::TyAlias
+            | DefKind::TyAlias { .. }
             | DefKind::ForeignTy
             | DefKind::TraitAlias
             | DefKind::AssocTy
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index bc05565fed4..c6f8d1e211d 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2675,7 +2675,7 @@ pub struct OpaqueTy<'hir> {
     ///
     /// This mapping associated a captured lifetime (first parameter) with the new
     /// early-bound lifetime that was generated for the opaque.
-    pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>,
+    pub lifetime_mapping: Option<&'hir [(&'hir Lifetime, LocalDefId)]>,
     /// Whether the opaque is a return-position impl trait (or async future)
     /// originating from a trait method. This makes it so that the opaque is
     /// lowered as an associated type.
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 0d65ddb5642..644c4d8265d 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -101,7 +101,7 @@ impl Target {
             DefKind::Mod => Target::Mod,
             DefKind::ForeignMod => Target::ForeignMod,
             DefKind::GlobalAsm => Target::GlobalAsm,
-            DefKind::TyAlias => Target::TyAlias,
+            DefKind::TyAlias { .. } => Target::TyAlias,
             DefKind::OpaqueTy => Target::OpaqueTy,
             DefKind::Enum => Target::Enum,
             DefKind::Struct => Target::Struct,
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index b40e3123522..319573c85b4 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -907,19 +907,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         did: DefId,
         item_segment: &hir::PathSegment<'_>,
     ) -> Ty<'tcx> {
+        let tcx = self.tcx();
         let args = self.ast_path_args_for_ty(span, did, item_segment);
-        let ty = self.tcx().at(span).type_of(did);
+        let ty = tcx.at(span).type_of(did);
 
-        if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
-            && (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias)
+        if let DefKind::TyAlias { lazy } = tcx.def_kind(did)
+            && (lazy || ty.skip_binder().has_opaque_types())
         {
             // Type aliases referring to types that contain opaque types (but aren't just directly
-            // referencing a single opaque type) get encoded as a type alias that normalization will
+            // referencing a single opaque type) as well as those defined in crates that have the
+            // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
             // then actually instantiate the where bounds of.
-            let alias_ty = self.tcx().mk_alias_ty(did, args);
-            Ty::new_alias(self.tcx(), ty::Weak, alias_ty)
+            let alias_ty = tcx.mk_alias_ty(did, args);
+            Ty::new_alias(tcx, ty::Weak, alias_ty)
         } else {
-            ty.instantiate(self.tcx(), args)
+            ty.instantiate(tcx, args)
         }
     }
 
@@ -2158,7 +2160,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             Res::Def(
                 DefKind::Enum
-                | DefKind::TyAlias
+                | DefKind::TyAlias { .. }
                 | DefKind::Struct
                 | DefKind::Union
                 | DefKind::ForeignTy,
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index c07ac35cba3..39db295044e 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -74,7 +74,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
             // we have some type like `&<Ty as Trait>::Assoc`, since users of
             // autoderef expect this type to have been structurally normalized.
             if self.infcx.next_trait_solver()
-                && let ty::Alias(ty::Projection, _) = ty.kind()
+                && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind()
             {
                 let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
                 self.state.obligations.extend(obligations);
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 73627a818e5..49307d96cc2 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -728,7 +728,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
                 check_opaque(tcx, id);
             }
         }
-        DefKind::TyAlias => {
+        DefKind::TyAlias { .. } => {
             let pty_ty = tcx.type_of(id.owner_id).instantiate_identity();
             let generics = tcx.generics_of(id.owner_id);
             check_type_params_are_used(tcx, &generics, pty_ty);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 970efaf312c..f89e2e5c25b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -273,6 +273,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ],
                 Ty::new_unit(tcx),
             ),
+            sym::compare_bytes => {
+                let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8);
+                (0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32)
+            }
             sym::write_bytes | sym::volatile_set_memory => (
                 1,
                 vec![
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 2950ce683a3..83220be6883 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -82,7 +82,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 tcx,
                 def_id,
                 lifetime_mapping.iter().map(|(lifetime, def_id)| {
-                    (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
+                    (**lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
                 }),
                 tcx.generics_of(def_id.to_def_id()),
                 &mut predicates,
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 3cc6f574aec..6dd0c840de6 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1480,7 +1480,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 DefKind::Struct
                 | DefKind::Union
                 | DefKind::Enum
-                | DefKind::TyAlias
+                | DefKind::TyAlias { .. }
                 | DefKind::Trait,
                 def_id,
             ) if depth == 0 => Some(def_id),
@@ -1990,7 +1990,7 @@ fn is_late_bound_map(
 
                 hir::TyKind::Path(hir::QPath::Resolved(
                     None,
-                    hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
+                    hir::Path { res: Res::Def(DefKind::TyAlias { .. }, alias_def), segments, span },
                 )) => {
                     // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
                     // args to be unconstrained.
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 4a3d522e488..8a40509d7cc 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -78,9 +78,8 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
                 }
             }
             DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
-            DefKind::TyAlias
-                if tcx.features().lazy_type_alias
-                    || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
+            DefKind::TyAlias { lazy }
+                if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
             {
                 constraint_cx.build_constraints_for_item(def_id)
             }
@@ -111,8 +110,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
 
         // The type as returned by `type_of` is the underlying type and generally not a weak projection.
         // Therefore we need to check the `DefKind` first.
-        if let DefKind::TyAlias = tcx.def_kind(def_id)
-            && (tcx.features().lazy_type_alias || ty.has_opaque_types())
+        if let DefKind::TyAlias { lazy } = tcx.def_kind(def_id)
+            && (lazy || ty.has_opaque_types())
         {
             self.add_constraints_from_ty(current_item, ty, self.covariant);
             return;
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 2ef294c6793..d91d9fcbc8e 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -56,9 +56,8 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
             let crate_map = tcx.crate_variances(());
             return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
         }
-        DefKind::TyAlias
-            if tcx.features().lazy_type_alias
-                || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
+        DefKind::TyAlias { lazy }
+            if lazy || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
         {
             // These are inferred.
             let crate_map = tcx.crate_variances(());
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1ef3d383bd8..1a8ec5f0853 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -97,9 +97,8 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
                 }
             }
             DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
-            DefKind::TyAlias
-                if tcx.features().lazy_type_alias
-                    || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
+            DefKind::TyAlias { lazy }
+                if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
             {
                 terms_cx.add_inferreds_for_item(def_id)
             }
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index fa6bad84376..b2b3f435505 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1012,6 +1012,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         cause: Option<ObligationCause<'tcx>>,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
         let source = self.try_structurally_resolve_type(expr.span, expr_ty);
+        let target = self.try_structurally_resolve_type(
+            cause.as_ref().map_or(expr.span, |cause| cause.span),
+            target,
+        );
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let cause =
@@ -1097,8 +1101,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     where
         E: AsCoercionSite,
     {
-        let prev_ty = self.resolve_vars_with_obligations(prev_ty);
-        let new_ty = self.resolve_vars_with_obligations(new_ty);
+        let prev_ty = self.try_structurally_resolve_type(cause.span, prev_ty);
+        let new_ty = self.try_structurally_resolve_type(new.span, new_ty);
         debug!(
             "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
             prev_ty,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 1433c67d55d..322d726a89d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1474,7 +1474,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty = self.resolve_vars_with_obligations(ty);
 
         if self.next_trait_solver()
-            && let ty::Alias(ty::Projection, _) = ty.kind()
+            && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind()
         {
             match self
                 .at(&self.misc(sp), self.param_env)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index c63dab63145..40f9a954034 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1359,7 +1359,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 _ => bug!("unexpected type: {:?}", ty.normalized),
             },
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            Res::Def(
+                DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
+                _,
+            )
             | Res::SelfTyParam { .. }
             | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
                 Some(adt) if !adt.is_enum() => {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 4ea53c7eaae..7fb1dc2347e 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -557,7 +557,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                 Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
             }
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
-            | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            | Res::Def(
+                DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
+                _,
+            )
             | Res::SelfCtor(..)
             | Res::SelfTyParam { .. }
             | Res::SelfTyAlias { .. } => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 9dfa45858a7..f2a3c47bdfe 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -951,7 +951,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
             //
             // See the `need_type_info/issue-103053.rs` test for
             // a example.
-            if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+            if !matches!(path.res, Res::Def(DefKind::TyAlias { .. }, _)) => {
                 if let Some(ty) = self.opt_node_type(expr.hir_id)
                     && let ty::Adt(_, args) = ty.kind()
                 {
@@ -1080,7 +1080,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                         ) => {
                             if tcx.res_generics_def_id(path.res) != Some(def.did()) {
                                 match path.res {
-                                    Res::Def(DefKind::TyAlias, _) => {
+                                    Res::Def(DefKind::TyAlias { .. }, _) => {
                                         // FIXME: Ideally we should support this. For that
                                         // we have to map back from the self type to the
                                         // type alias though. That's difficult.
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index a6052f52917..1c3a5c36076 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> {
             ct_op: |ct| ct,
             ty_op: |ty| match *ty.kind() {
                 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
-                    if replace_opaque_type(def_id) =>
+                    if replace_opaque_type(def_id) && !ty.has_escaping_bound_vars() =>
                 {
                     let def_span = self.tcx.def_span(def_id);
                     let span = if span.contains(def_span) { def_span } else { span };
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 6b3facd041c..a34fdf4ecc9 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -846,10 +846,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
                     },
                     {
                         sess.time("lint_checking", || {
-                            rustc_lint::check_crate(tcx, || {
-                                rustc_lint::BuiltinCombinedLateLintPass::new()
-                            });
+                            rustc_lint::check_crate(tcx);
                         });
+                    },
+                    {
+                        tcx.ensure().clashing_extern_declarations(());
                     }
                 );
             },
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5e61073694f..2c9d212a6a6 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -24,10 +24,9 @@ use crate::fluent_generated as fluent;
 use crate::{
     errors::BuiltinEllipsisInclusiveRangePatterns,
     lints::{
-        BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern,
-        BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
-        BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
-        BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
+        BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle,
+        BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed,
+        BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
         BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
         BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
         BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
@@ -40,8 +39,7 @@ use crate::{
         BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
         BuiltinWhileTrue, SuggestChangingAssocTypes,
     },
-    types::{transparent_newtype_field, CItemKind},
-    EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
+    EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
 };
 use hir::IsAsync;
 use rustc_ast::attr;
@@ -49,29 +47,29 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Applicability, DecorateLint, MultiSpan};
 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::FnKind as HirFnKind;
-use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin};
+use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::layout::{LayoutError, LayoutOf};
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::GenericArgKind;
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
 use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, Span};
-use rustc_target::abi::{Abi, FIRST_VARIANT};
+use rustc_target::abi::Abi;
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
@@ -461,10 +459,7 @@ declare_lint! {
     report_in_external_macro
 }
 
-pub struct MissingDoc {
-    /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
-    doc_hidden_stack: Vec<bool>,
-}
+pub struct MissingDoc;
 
 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
 
@@ -493,14 +488,6 @@ fn has_doc(attr: &ast::Attribute) -> bool {
 }
 
 impl MissingDoc {
-    pub fn new() -> MissingDoc {
-        MissingDoc { doc_hidden_stack: vec![false] }
-    }
-
-    fn doc_hidden(&self) -> bool {
-        *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
-    }
-
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
@@ -514,11 +501,6 @@ impl MissingDoc {
             return;
         }
 
-        // `#[doc(hidden)]` disables missing_docs check.
-        if self.doc_hidden() {
-            return;
-        }
-
         // Only check publicly-visible items, using the result from the privacy pass.
         // It's an option so the crate root can also use this function (it doesn't
         // have a `NodeId`).
@@ -541,23 +523,6 @@ impl MissingDoc {
 }
 
 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
-    #[inline]
-    fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
-        let doc_hidden = self.doc_hidden()
-            || attrs.iter().any(|attr| {
-                attr.has_name(sym::doc)
-                    && match attr.meta_item_list() {
-                        None => false,
-                        Some(l) => attr::list_contains_name(&l, sym::hidden),
-                    }
-            });
-        self.doc_hidden_stack.push(doc_hidden);
-    }
-
-    fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) {
-        self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
-    }
-
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
     }
@@ -710,6 +675,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
         if ty.is_copy_modulo_regions(cx.tcx, param_env) {
             return;
         }
+        if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) {
+            return;
+        }
 
         // We shouldn't recommend implementing `Copy` on stateful things,
         // such as iterators.
@@ -745,6 +713,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
     }
 }
 
+/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints.
+fn type_implements_negative_copy_modulo_regions<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> bool {
+    let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
+    let pred = ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Negative };
+    let obligation = traits::Obligation {
+        cause: traits::ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: ty::Binder::dummy(pred).to_predicate(tcx),
+    };
+
+    tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
+}
+
 declare_lint! {
     /// The `missing_debug_implementations` lint detects missing
     /// implementations of [`fmt::Debug`] for public types.
@@ -778,9 +764,7 @@ declare_lint! {
 }
 
 #[derive(Default)]
-pub struct MissingDebugImplementations {
-    impling_types: Option<LocalDefIdSet>,
-}
+pub(crate) struct MissingDebugImplementations;
 
 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
 
@@ -795,23 +779,20 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             _ => return,
         }
 
-        let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return };
-
-        if self.impling_types.is_none() {
-            let mut impls = LocalDefIdSet::default();
-            cx.tcx.for_each_impl(debug, |d| {
-                if let Some(ty_def) = cx.tcx.type_of(d).instantiate_identity().ty_adt_def() {
-                    if let Some(def_id) = ty_def.did().as_local() {
-                        impls.insert(def_id);
-                    }
-                }
-            });
-
-            self.impling_types = Some(impls);
-            debug!("{:?}", self.impling_types);
+        // Avoid listing trait impls if the trait is allowed.
+        let (level, _) = cx.tcx.lint_level_at_node(MISSING_DEBUG_IMPLEMENTATIONS, item.hir_id());
+        if level == Level::Allow {
+            return;
         }
 
-        if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
+        let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return };
+
+        let has_impl = cx
+            .tcx
+            .non_blanket_impls_for_ty(debug, cx.tcx.type_of(item.owner_id).instantiate_identity())
+            .next()
+            .is_some();
+        if !has_impl {
             cx.emit_spanned_lint(
                 MISSING_DEBUG_IMPLEMENTATIONS,
                 item.span,
@@ -2613,381 +2594,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
 }
 
 declare_lint! {
-    /// The `clashing_extern_declarations` lint detects when an `extern fn`
-    /// has been declared with the same name but different types.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// mod m {
-    ///     extern "C" {
-    ///         fn foo();
-    ///     }
-    /// }
-    ///
-    /// extern "C" {
-    ///     fn foo(_: u32);
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Because two symbols of the same name cannot be resolved to two
-    /// different functions at link time, and one function cannot possibly
-    /// have two types, a clashing extern declaration is almost certainly a
-    /// mistake. Check to make sure that the `extern` definitions are correct
-    /// and equivalent, and possibly consider unifying them in one location.
-    ///
-    /// This lint does not run between crates because a project may have
-    /// dependencies which both rely on the same extern function, but declare
-    /// it in a different (but valid) way. For example, they may both declare
-    /// an opaque type for one or more of the arguments (which would end up
-    /// distinct types), or use types that are valid conversions in the
-    /// language the `extern fn` is defined in. In these cases, the compiler
-    /// can't say that the clashing declaration is incorrect.
-    pub CLASHING_EXTERN_DECLARATIONS,
-    Warn,
-    "detects when an extern fn has been declared with the same name but different types"
-}
-
-pub struct ClashingExternDeclarations {
-    /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
-    /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
-    /// the symbol should be reported as a clashing declaration.
-    // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
-    // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
-    seen_decls: FxHashMap<Symbol, hir::OwnerId>,
-}
-
-/// Differentiate between whether the name for an extern decl came from the link_name attribute or
-/// just from declaration itself. This is important because we don't want to report clashes on
-/// symbol name if they don't actually clash because one or the other links against a symbol with a
-/// different name.
-enum SymbolName {
-    /// The name of the symbol + the span of the annotation which introduced the link name.
-    Link(Symbol, Span),
-    /// No link name, so just the name of the symbol.
-    Normal(Symbol),
-}
-
-impl SymbolName {
-    fn get_name(&self) -> Symbol {
-        match self {
-            SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
-        }
-    }
-}
-
-impl ClashingExternDeclarations {
-    pub(crate) fn new() -> Self {
-        ClashingExternDeclarations { seen_decls: FxHashMap::default() }
-    }
-
-    /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
-    /// for the item, return its HirId without updating the set.
-    fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> {
-        let did = fi.owner_id.to_def_id();
-        let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
-        let name = Symbol::intern(tcx.symbol_name(instance).name);
-        if let Some(&existing_id) = self.seen_decls.get(&name) {
-            // Avoid updating the map with the new entry when we do find a collision. We want to
-            // make sure we're always pointing to the first definition as the previous declaration.
-            // This lets us avoid emitting "knock-on" diagnostics.
-            Some(existing_id)
-        } else {
-            self.seen_decls.insert(name, fi.owner_id)
-        }
-    }
-
-    /// Get the name of the symbol that's linked against for a given extern declaration. That is,
-    /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
-    /// symbol's name.
-    fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
-        if let Some((overridden_link_name, overridden_link_name_span)) =
-            tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| {
-                // FIXME: Instead of searching through the attributes again to get span
-                // information, we could have codegen_fn_attrs also give span information back for
-                // where the attribute was defined. However, until this is found to be a
-                // bottleneck, this does just fine.
-                (overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span)
-            })
-        {
-            SymbolName::Link(overridden_link_name, overridden_link_name_span)
-        } else {
-            SymbolName::Normal(fi.ident.name)
-        }
-    }
-
-    /// Checks whether two types are structurally the same enough that the declarations shouldn't
-    /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
-    /// with the same members (as the declarations shouldn't clash).
-    fn structurally_same_type<'tcx>(
-        cx: &LateContext<'tcx>,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-        ckind: CItemKind,
-    ) -> bool {
-        fn structurally_same_type_impl<'tcx>(
-            seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
-            cx: &LateContext<'tcx>,
-            a: Ty<'tcx>,
-            b: Ty<'tcx>,
-            ckind: CItemKind,
-        ) -> bool {
-            debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
-            let tcx = cx.tcx;
-
-            // Given a transparent newtype, reach through and grab the inner
-            // type unless the newtype makes the type non-null.
-            let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
-                loop {
-                    if let ty::Adt(def, args) = *ty.kind() {
-                        let is_transparent = def.repr().transparent();
-                        let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def);
-                        debug!(
-                            "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
-                            ty, is_transparent, is_non_null
-                        );
-                        if is_transparent && !is_non_null {
-                            debug_assert_eq!(def.variants().len(), 1);
-                            let v = &def.variant(FIRST_VARIANT);
-                            // continue with `ty`'s non-ZST field,
-                            // otherwise `ty` is a ZST and we can return
-                            if let Some(field) = transparent_newtype_field(tcx, v) {
-                                ty = field.ty(tcx, args);
-                                continue;
-                            }
-                        }
-                    }
-                    debug!("non_transparent_ty -> {:?}", ty);
-                    return ty;
-                }
-            };
-
-            let a = non_transparent_ty(a);
-            let b = non_transparent_ty(b);
-
-            if !seen_types.insert((a, b)) {
-                // We've encountered a cycle. There's no point going any further -- the types are
-                // structurally the same.
-                true
-            } else if a == b {
-                // All nominally-same types are structurally same, too.
-                true
-            } else {
-                // Do a full, depth-first comparison between the two.
-                use rustc_type_ir::sty::TyKind::*;
-                let a_kind = a.kind();
-                let b_kind = b.kind();
-
-                let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
-                    debug!("compare_layouts({:?}, {:?})", a, b);
-                    let a_layout = &cx.layout_of(a)?.layout.abi();
-                    let b_layout = &cx.layout_of(b)?.layout.abi();
-                    debug!(
-                        "comparing layouts: {:?} == {:?} = {}",
-                        a_layout,
-                        b_layout,
-                        a_layout == b_layout
-                    );
-                    Ok(a_layout == b_layout)
-                };
-
-                #[allow(rustc::usage_of_ty_tykind)]
-                let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
-                    kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
-                };
-
-                ensure_sufficient_stack(|| {
-                    match (a_kind, b_kind) {
-                        (Adt(a_def, _), Adt(b_def, _)) => {
-                            // We can immediately rule out these types as structurally same if
-                            // their layouts differ.
-                            match compare_layouts(a, b) {
-                                Ok(false) => return false,
-                                _ => (), // otherwise, continue onto the full, fields comparison
-                            }
-
-                            // Grab a flattened representation of all fields.
-                            let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
-                            let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
-
-                            // Perform a structural comparison for each field.
-                            a_fields.eq_by(
-                                b_fields,
-                                |&ty::FieldDef { did: a_did, .. },
-                                 &ty::FieldDef { did: b_did, .. }| {
-                                    structurally_same_type_impl(
-                                        seen_types,
-                                        cx,
-                                        tcx.type_of(a_did).instantiate_identity(),
-                                        tcx.type_of(b_did).instantiate_identity(),
-                                        ckind,
-                                    )
-                                },
-                            )
-                        }
-                        (Array(a_ty, a_const), Array(b_ty, b_const)) => {
-                            // For arrays, we also check the constness of the type.
-                            a_const.kind() == b_const.kind()
-                                && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
-                        }
-                        (Slice(a_ty), Slice(b_ty)) => {
-                            structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
-                        }
-                        (RawPtr(a_tymut), RawPtr(b_tymut)) => {
-                            a_tymut.mutbl == b_tymut.mutbl
-                                && structurally_same_type_impl(
-                                    seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
-                                )
-                        }
-                        (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
-                            // For structural sameness, we don't need the region to be same.
-                            a_mut == b_mut
-                                && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
-                        }
-                        (FnDef(..), FnDef(..)) => {
-                            let a_poly_sig = a.fn_sig(tcx);
-                            let b_poly_sig = b.fn_sig(tcx);
-
-                            // We don't compare regions, but leaving bound regions around ICEs, so
-                            // we erase them.
-                            let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
-                            let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
-
-                            (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
-                                == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
-                                && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
-                                    structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
-                                })
-                                && structurally_same_type_impl(
-                                    seen_types,
-                                    cx,
-                                    a_sig.output(),
-                                    b_sig.output(),
-                                    ckind,
-                                )
-                        }
-                        (Tuple(a_args), Tuple(b_args)) => {
-                            a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| {
-                                structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
-                            })
-                        }
-                        // For these, it's not quite as easy to define structural-sameness quite so easily.
-                        // For the purposes of this lint, take the conservative approach and mark them as
-                        // not structurally same.
-                        (Dynamic(..), Dynamic(..))
-                        | (Error(..), Error(..))
-                        | (Closure(..), Closure(..))
-                        | (Generator(..), Generator(..))
-                        | (GeneratorWitness(..), GeneratorWitness(..))
-                        | (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
-                        | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
-                        | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
-
-                        // These definitely should have been caught above.
-                        (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
-
-                        // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
-                        // enum layout optimisation is being applied.
-                        (Adt(..), other_kind) | (other_kind, Adt(..))
-                            if is_primitive_or_pointer(other_kind) =>
-                        {
-                            let (primitive, adt) =
-                                if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
-                            if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
-                                ty == primitive
-                            } else {
-                                compare_layouts(a, b).unwrap_or(false)
-                            }
-                        }
-                        // Otherwise, just compare the layouts. This may fail to lint for some
-                        // incompatible types, but at the very least, will stop reads into
-                        // uninitialised memory.
-                        _ => compare_layouts(a, b).unwrap_or(false),
-                    }
-                })
-            }
-        }
-        let mut seen_types = FxHashSet::default();
-        structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
-    }
-}
-
-impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
-
-impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
-    #[instrument(level = "trace", skip(self, cx))]
-    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) {
-        if let ForeignItemKind::Fn(..) = this_fi.kind {
-            let tcx = cx.tcx;
-            if let Some(existing_did) = self.insert(tcx, this_fi) {
-                let existing_decl_ty = tcx.type_of(existing_did).skip_binder();
-                let this_decl_ty = tcx.type_of(this_fi.owner_id).instantiate_identity();
-                debug!(
-                    "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
-                    existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty
-                );
-                // Check that the declarations match.
-                if !Self::structurally_same_type(
-                    cx,
-                    existing_decl_ty,
-                    this_decl_ty,
-                    CItemKind::Declaration,
-                ) {
-                    let orig_fi = tcx.hir().expect_foreign_item(existing_did);
-                    let orig = Self::name_of_extern_decl(tcx, orig_fi);
-
-                    // We want to ensure that we use spans for both decls that include where the
-                    // name was defined, whether that was from the link_name attribute or not.
-                    let get_relevant_span =
-                        |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
-                            SymbolName::Normal(_) => fi.span,
-                            SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
-                        };
-
-                    // Finally, emit the diagnostic.
-                    let this = this_fi.ident.name;
-                    let orig = orig.get_name();
-                    let previous_decl_label = get_relevant_span(orig_fi);
-                    let mismatch_label = get_relevant_span(this_fi);
-                    let sub = BuiltinClashingExternSub {
-                        tcx,
-                        expected: existing_decl_ty,
-                        found: this_decl_ty,
-                    };
-                    let decorator = if orig == this {
-                        BuiltinClashingExtern::SameName {
-                            this,
-                            orig,
-                            previous_decl_label,
-                            mismatch_label,
-                            sub,
-                        }
-                    } else {
-                        BuiltinClashingExtern::DiffName {
-                            this,
-                            orig,
-                            previous_decl_label,
-                            mismatch_label,
-                            sub,
-                        }
-                    };
-                    tcx.emit_spanned_lint(
-                        CLASHING_EXTERN_DECLARATIONS,
-                        this_fi.hir_id(),
-                        get_relevant_span(this_fi),
-                        decorator,
-                    );
-                }
-            }
-        }
-    }
-}
-
-declare_lint! {
     /// The `deref_nullptr` lint detects when an null pointer is dereferenced,
     /// which causes [undefined behavior].
     ///
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
new file mode 100644
index 00000000000..7b291d558e0
--- /dev/null
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -0,0 +1,402 @@
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_middle::query::Providers;
+use rustc_middle::ty::layout::LayoutError;
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_session::lint::{lint_array, LintArray};
+use rustc_span::{sym, Span, Symbol};
+use rustc_target::abi::FIRST_VARIANT;
+
+use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub};
+use crate::types;
+
+pub(crate) fn provide(providers: &mut Providers) {
+    *providers = Providers { clashing_extern_declarations, ..*providers };
+}
+
+pub(crate) fn get_lints() -> LintArray {
+    lint_array!(CLASHING_EXTERN_DECLARATIONS)
+}
+
+fn clashing_extern_declarations(tcx: TyCtxt<'_>, (): ()) {
+    let mut lint = ClashingExternDeclarations::new();
+    for id in tcx.hir_crate_items(()).foreign_items() {
+        lint.check_foreign_item(tcx, id);
+    }
+}
+
+declare_lint! {
+    /// The `clashing_extern_declarations` lint detects when an `extern fn`
+    /// has been declared with the same name but different types.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// mod m {
+    ///     extern "C" {
+    ///         fn foo();
+    ///     }
+    /// }
+    ///
+    /// extern "C" {
+    ///     fn foo(_: u32);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Because two symbols of the same name cannot be resolved to two
+    /// different functions at link time, and one function cannot possibly
+    /// have two types, a clashing extern declaration is almost certainly a
+    /// mistake. Check to make sure that the `extern` definitions are correct
+    /// and equivalent, and possibly consider unifying them in one location.
+    ///
+    /// This lint does not run between crates because a project may have
+    /// dependencies which both rely on the same extern function, but declare
+    /// it in a different (but valid) way. For example, they may both declare
+    /// an opaque type for one or more of the arguments (which would end up
+    /// distinct types), or use types that are valid conversions in the
+    /// language the `extern fn` is defined in. In these cases, the compiler
+    /// can't say that the clashing declaration is incorrect.
+    pub CLASHING_EXTERN_DECLARATIONS,
+    Warn,
+    "detects when an extern fn has been declared with the same name but different types"
+}
+
+struct ClashingExternDeclarations {
+    /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
+    /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
+    /// the symbol should be reported as a clashing declaration.
+    // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
+    // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
+    seen_decls: FxHashMap<Symbol, hir::OwnerId>,
+}
+
+/// Differentiate between whether the name for an extern decl came from the link_name attribute or
+/// just from declaration itself. This is important because we don't want to report clashes on
+/// symbol name if they don't actually clash because one or the other links against a symbol with a
+/// different name.
+enum SymbolName {
+    /// The name of the symbol + the span of the annotation which introduced the link name.
+    Link(Symbol, Span),
+    /// No link name, so just the name of the symbol.
+    Normal(Symbol),
+}
+
+impl SymbolName {
+    fn get_name(&self) -> Symbol {
+        match self {
+            SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
+        }
+    }
+}
+
+impl ClashingExternDeclarations {
+    pub(crate) fn new() -> Self {
+        ClashingExternDeclarations { seen_decls: FxHashMap::default() }
+    }
+
+    /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
+    /// for the item, return its HirId without updating the set.
+    fn insert(&mut self, tcx: TyCtxt<'_>, fi: hir::ForeignItemId) -> Option<hir::OwnerId> {
+        let did = fi.owner_id.to_def_id();
+        let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
+        let name = Symbol::intern(tcx.symbol_name(instance).name);
+        if let Some(&existing_id) = self.seen_decls.get(&name) {
+            // Avoid updating the map with the new entry when we do find a collision. We want to
+            // make sure we're always pointing to the first definition as the previous declaration.
+            // This lets us avoid emitting "knock-on" diagnostics.
+            Some(existing_id)
+        } else {
+            self.seen_decls.insert(name, fi.owner_id)
+        }
+    }
+
+    #[instrument(level = "trace", skip(self, tcx))]
+    fn check_foreign_item<'tcx>(&mut self, tcx: TyCtxt<'tcx>, this_fi: hir::ForeignItemId) {
+        let DefKind::Fn = tcx.def_kind(this_fi.owner_id) else { return };
+        let Some(existing_did) = self.insert(tcx, this_fi) else { return };
+
+        let existing_decl_ty = tcx.type_of(existing_did).skip_binder();
+        let this_decl_ty = tcx.type_of(this_fi.owner_id).instantiate_identity();
+        debug!(
+            "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
+            existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty
+        );
+
+        // Check that the declarations match.
+        if !structurally_same_type(
+            tcx,
+            tcx.param_env(this_fi.owner_id),
+            existing_decl_ty,
+            this_decl_ty,
+            types::CItemKind::Declaration,
+        ) {
+            let orig = name_of_extern_decl(tcx, existing_did);
+
+            // Finally, emit the diagnostic.
+            let this = tcx.item_name(this_fi.owner_id.to_def_id());
+            let orig = orig.get_name();
+            let previous_decl_label = get_relevant_span(tcx, existing_did);
+            let mismatch_label = get_relevant_span(tcx, this_fi.owner_id);
+            let sub =
+                BuiltinClashingExternSub { tcx, expected: existing_decl_ty, found: this_decl_ty };
+            let decorator = if orig == this {
+                BuiltinClashingExtern::SameName {
+                    this,
+                    orig,
+                    previous_decl_label,
+                    mismatch_label,
+                    sub,
+                }
+            } else {
+                BuiltinClashingExtern::DiffName {
+                    this,
+                    orig,
+                    previous_decl_label,
+                    mismatch_label,
+                    sub,
+                }
+            };
+            tcx.emit_spanned_lint(
+                CLASHING_EXTERN_DECLARATIONS,
+                this_fi.hir_id(),
+                mismatch_label,
+                decorator,
+            );
+        }
+    }
+}
+
+/// Get the name of the symbol that's linked against for a given extern declaration. That is,
+/// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
+/// symbol's name.
+fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName {
+    if let Some((overridden_link_name, overridden_link_name_span)) =
+        tcx.codegen_fn_attrs(fi).link_name.map(|overridden_link_name| {
+            // FIXME: Instead of searching through the attributes again to get span
+            // information, we could have codegen_fn_attrs also give span information back for
+            // where the attribute was defined. However, until this is found to be a
+            // bottleneck, this does just fine.
+            (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span)
+        })
+    {
+        SymbolName::Link(overridden_link_name, overridden_link_name_span)
+    } else {
+        SymbolName::Normal(tcx.item_name(fi.to_def_id()))
+    }
+}
+
+/// We want to ensure that we use spans for both decls that include where the
+/// name was defined, whether that was from the link_name attribute or not.
+fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span {
+    match name_of_extern_decl(tcx, fi) {
+        SymbolName::Normal(_) => tcx.def_span(fi),
+        SymbolName::Link(_, annot_span) => annot_span,
+    }
+}
+
+/// Checks whether two types are structurally the same enough that the declarations shouldn't
+/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
+/// with the same members (as the declarations shouldn't clash).
+fn structurally_same_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    a: Ty<'tcx>,
+    b: Ty<'tcx>,
+    ckind: types::CItemKind,
+) -> bool {
+    let mut seen_types = FxHashSet::default();
+    structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind)
+}
+
+fn structurally_same_type_impl<'tcx>(
+    seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    a: Ty<'tcx>,
+    b: Ty<'tcx>,
+    ckind: types::CItemKind,
+) -> bool {
+    debug!("structurally_same_type_impl(tcx, a = {:?}, b = {:?})", a, b);
+
+    // Given a transparent newtype, reach through and grab the inner
+    // type unless the newtype makes the type non-null.
+    let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
+        loop {
+            if let ty::Adt(def, args) = *ty.kind() {
+                let is_transparent = def.repr().transparent();
+                let is_non_null = types::nonnull_optimization_guaranteed(tcx, def);
+                debug!(
+                    "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
+                    ty, is_transparent, is_non_null
+                );
+                if is_transparent && !is_non_null {
+                    debug_assert_eq!(def.variants().len(), 1);
+                    let v = &def.variant(FIRST_VARIANT);
+                    // continue with `ty`'s non-ZST field,
+                    // otherwise `ty` is a ZST and we can return
+                    if let Some(field) = types::transparent_newtype_field(tcx, v) {
+                        ty = field.ty(tcx, args);
+                        continue;
+                    }
+                }
+            }
+            debug!("non_transparent_ty -> {:?}", ty);
+            return ty;
+        }
+    };
+
+    let a = non_transparent_ty(a);
+    let b = non_transparent_ty(b);
+
+    if !seen_types.insert((a, b)) {
+        // We've encountered a cycle. There's no point going any further -- the types are
+        // structurally the same.
+        true
+    } else if a == b {
+        // All nominally-same types are structurally same, too.
+        true
+    } else {
+        // Do a full, depth-first comparison between the two.
+        use rustc_type_ir::sty::TyKind::*;
+        let a_kind = a.kind();
+        let b_kind = b.kind();
+
+        let compare_layouts = |a, b| -> Result<bool, &'tcx LayoutError<'tcx>> {
+            debug!("compare_layouts({:?}, {:?})", a, b);
+            let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi();
+            let b_layout = &tcx.layout_of(param_env.and(b))?.layout.abi();
+            debug!(
+                "comparing layouts: {:?} == {:?} = {}",
+                a_layout,
+                b_layout,
+                a_layout == b_layout
+            );
+            Ok(a_layout == b_layout)
+        };
+
+        #[allow(rustc::usage_of_ty_tykind)]
+        let is_primitive_or_pointer =
+            |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..));
+
+        ensure_sufficient_stack(|| {
+            match (a_kind, b_kind) {
+                (Adt(a_def, _), Adt(b_def, _)) => {
+                    // We can immediately rule out these types as structurally same if
+                    // their layouts differ.
+                    match compare_layouts(a, b) {
+                        Ok(false) => return false,
+                        _ => (), // otherwise, continue onto the full, fields comparison
+                    }
+
+                    // Grab a flattened representation of all fields.
+                    let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
+                    let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
+
+                    // Perform a structural comparison for each field.
+                    a_fields.eq_by(
+                        b_fields,
+                        |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| {
+                            structurally_same_type_impl(
+                                seen_types,
+                                tcx,
+                                param_env,
+                                tcx.type_of(a_did).instantiate_identity(),
+                                tcx.type_of(b_did).instantiate_identity(),
+                                ckind,
+                            )
+                        },
+                    )
+                }
+                (Array(a_ty, a_const), Array(b_ty, b_const)) => {
+                    // For arrays, we also check the constness of the type.
+                    a_const.kind() == b_const.kind()
+                        && structurally_same_type_impl(
+                            seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
+                        )
+                }
+                (Slice(a_ty), Slice(b_ty)) => {
+                    structurally_same_type_impl(seen_types, tcx, param_env, *a_ty, *b_ty, ckind)
+                }
+                (RawPtr(a_tymut), RawPtr(b_tymut)) => {
+                    a_tymut.mutbl == b_tymut.mutbl
+                        && structurally_same_type_impl(
+                            seen_types, tcx, param_env, a_tymut.ty, b_tymut.ty, ckind,
+                        )
+                }
+                (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
+                    // For structural sameness, we don't need the region to be same.
+                    a_mut == b_mut
+                        && structurally_same_type_impl(
+                            seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
+                        )
+                }
+                (FnDef(..), FnDef(..)) => {
+                    let a_poly_sig = a.fn_sig(tcx);
+                    let b_poly_sig = b.fn_sig(tcx);
+
+                    // We don't compare regions, but leaving bound regions around ICEs, so
+                    // we erase them.
+                    let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
+                    let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
+
+                    (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
+                        == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+                        && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
+                            structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind)
+                        })
+                        && structurally_same_type_impl(
+                            seen_types,
+                            tcx,
+                            param_env,
+                            a_sig.output(),
+                            b_sig.output(),
+                            ckind,
+                        )
+                }
+                (Tuple(a_args), Tuple(b_args)) => {
+                    a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| {
+                        structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind)
+                    })
+                }
+                // For these, it's not quite as easy to define structural-sameness quite so easily.
+                // For the purposes of this lint, take the conservative approach and mark them as
+                // not structurally same.
+                (Dynamic(..), Dynamic(..))
+                | (Error(..), Error(..))
+                | (Closure(..), Closure(..))
+                | (Generator(..), Generator(..))
+                | (GeneratorWitness(..), GeneratorWitness(..))
+                | (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
+                | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
+                | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
+
+                // These definitely should have been caught above.
+                (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
+
+                // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
+                // enum layout optimisation is being applied.
+                (Adt(..), other_kind) | (other_kind, Adt(..))
+                    if is_primitive_or_pointer(other_kind) =>
+                {
+                    let (primitive, adt) =
+                        if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
+                    if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, adt, ckind) {
+                        ty == primitive
+                    } else {
+                        compare_layouts(a, b).unwrap_or(false)
+                    }
+                }
+                // Otherwise, just compare the layouts. This may fail to lint for some
+                // incompatible types, but at the very least, will stop reads into
+                // uninitialised memory.
+                _ => compare_layouts(a, b).unwrap_or(false),
+            }
+        })
+    }
+}
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index fb12ded71d6..3331dbad4a9 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -17,7 +17,7 @@
 use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
 use rustc_ast as ast;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_data_structures::sync::{join, DynSend};
+use rustc_data_structures::sync::join;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit as hir_visit;
@@ -336,7 +336,7 @@ macro_rules! impl_late_lint_pass {
 
 crate::late_lint_methods!(impl_late_lint_pass, []);
 
-pub(super) fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
+pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
     tcx: TyCtxt<'tcx>,
     module_def_id: LocalDefId,
     builtin_lints: T,
@@ -376,6 +376,12 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
     let mut cx = LateContextAndPass { context, pass };
 
     let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
+
+    // There is no module lint that will have the crate itself as an item, so check it here.
+    if hir_id == hir::CRATE_HIR_ID {
+        lint_callback!(cx, check_crate,);
+    }
+
     cx.process_mod(module, hir_id);
 
     // Visit the crate attributes
@@ -383,10 +389,19 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
         for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() {
             cx.visit_attribute(attr)
         }
+        lint_callback!(cx, check_crate_post,);
     }
 }
 
-fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
+fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
+    // Note: `passes` is often empty.
+    let mut passes: Vec<_> =
+        unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
+
+    if passes.is_empty() {
+        return;
+    }
+
     let context = LateContext {
         tcx,
         enclosing_body: None,
@@ -399,18 +414,8 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builti
         only_module: false,
     };
 
-    // Note: `passes` is often empty. In that case, it's faster to run
-    // `builtin_lints` directly rather than bundling it up into the
-    // `RuntimeCombinedLateLintPass`.
-    let mut passes: Vec<_> =
-        unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
-    if passes.is_empty() {
-        late_lint_crate_inner(tcx, context, builtin_lints);
-    } else {
-        passes.push(Box::new(builtin_lints));
-        let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
-        late_lint_crate_inner(tcx, context, pass);
-    }
+    let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+    late_lint_crate_inner(tcx, context, pass);
 }
 
 fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
@@ -432,15 +437,12 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
 }
 
 /// Performs lint checking on a crate.
-pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(
-    tcx: TyCtxt<'tcx>,
-    builtin_lints: impl FnOnce() -> T + Send + DynSend,
-) {
+pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
     join(
         || {
             tcx.sess.time("crate_lints", || {
                 // Run whole crate non-incremental lints
-                late_lint_crate(tcx, builtin_lints());
+                late_lint_crate(tcx);
             });
         },
         || {
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index fb407be1f02..18b178d8882 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,4 +1,5 @@
 use crate::{
+    builtin::MISSING_DOCS,
     context::{CheckLintNameResult, LintStore},
     fluent_generated as fluent,
     late::unerased_lint_store,
@@ -667,6 +668,16 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                 continue;
             }
 
+            // `#[doc(hidden)]` disables missing_docs check.
+            if attr.has_name(sym::doc)
+                && attr
+                    .meta_item_list()
+                    .map_or(false, |l| ast::attr::list_contains_name(&l, sym::hidden))
+            {
+                self.insert(LintId::of(MISSING_DOCS), (Level::Allow, LintLevelSource::Default));
+                continue;
+            }
+
             let level = match Level::from_attr(attr) {
                 None => continue,
                 // This is the only lint level with a `LintExpectationId` that can be created from an attribute
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 80bf53ea866..42378951af3 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -59,6 +59,7 @@ mod enum_intrinsics_non_enums;
 mod errors;
 mod expect;
 mod for_loops_over_fallibles;
+mod foreign_modules;
 pub mod hidden_unicode_codepoints;
 mod internal;
 mod invalid_from_utf8;
@@ -125,11 +126,11 @@ use types::*;
 use unused::*;
 
 /// Useful for other parts of the compiler / Clippy.
-pub use builtin::SoftLints;
+pub use builtin::{MissingDoc, SoftLints};
 pub use context::{CheckLintNameResult, FindLintError, LintStore};
 pub use context::{EarlyContext, LateContext, LintContext};
 pub use early::{check_ast_node, EarlyCheckNode};
-pub use late::{check_crate, unerased_lint_store};
+pub use late::{check_crate, late_lint_mod, unerased_lint_store};
 pub use passes::{EarlyLintPass, LateLintPass};
 pub use rustc_session::lint::Level::{self, *};
 pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
@@ -140,11 +141,12 @@ fluent_messages! { "../messages.ftl" }
 pub fn provide(providers: &mut Providers) {
     levels::provide(providers);
     expect::provide(providers);
+    foreign_modules::provide(providers);
     *providers = Providers { lint_mod, ..*providers };
 }
 
 fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
+    late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
 }
 
 early_lint_methods!(
@@ -182,25 +184,6 @@ early_lint_methods!(
     ]
 );
 
-// FIXME: Make a separate lint type which does not require typeck tables.
-
-late_lint_methods!(
-    declare_combined_late_lint_pass,
-    [
-        pub BuiltinCombinedLateLintPass,
-        [
-            // Tracks attributes of parents
-            MissingDoc: MissingDoc::new(),
-            // Builds a global list of all impls of `Debug`.
-            // FIXME: Turn the computation of types which implement Debug into a query
-            // and change this to a module lint pass
-            MissingDebugImplementations: MissingDebugImplementations::default(),
-            // Keeps a global list of foreign declarations.
-            ClashingExternDeclarations: ClashingExternDeclarations::new(),
-        ]
-    ]
-);
-
 late_lint_methods!(
     declare_combined_late_lint_pass,
     [
@@ -253,6 +236,8 @@ late_lint_methods!(
             OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
             MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
             MapUnitFn: MapUnitFn,
+            MissingDebugImplementations: MissingDebugImplementations,
+            MissingDoc: MissingDoc,
         ]
     ]
 );
@@ -281,7 +266,7 @@ fn register_builtins(store: &mut LintStore) {
     store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
     store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
     store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
-    store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
+    store.register_lints(&foreign_modules::get_lints());
 
     add_lint_group!(
         "nonstandard_style",
@@ -521,20 +506,20 @@ fn register_internals(store: &mut LintStore) {
     store.register_lints(&LintPassImpl::get_lints());
     store.register_early_pass(|| Box::new(LintPassImpl));
     store.register_lints(&DefaultHashTypes::get_lints());
-    store.register_late_pass(|_| Box::new(DefaultHashTypes));
+    store.register_late_mod_pass(|_| Box::new(DefaultHashTypes));
     store.register_lints(&QueryStability::get_lints());
-    store.register_late_pass(|_| Box::new(QueryStability));
+    store.register_late_mod_pass(|_| Box::new(QueryStability));
     store.register_lints(&ExistingDocKeyword::get_lints());
-    store.register_late_pass(|_| Box::new(ExistingDocKeyword));
+    store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword));
     store.register_lints(&TyTyKind::get_lints());
-    store.register_late_pass(|_| Box::new(TyTyKind));
+    store.register_late_mod_pass(|_| Box::new(TyTyKind));
     store.register_lints(&Diagnostics::get_lints());
     store.register_early_pass(|| Box::new(Diagnostics));
-    store.register_late_pass(|_| Box::new(Diagnostics));
+    store.register_late_mod_pass(|_| Box::new(Diagnostics));
     store.register_lints(&BadOptAccess::get_lints());
-    store.register_late_pass(|_| Box::new(BadOptAccess));
+    store.register_late_mod_pass(|_| Box::new(BadOptAccess));
     store.register_lints(&PassByValue::get_lints());
-    store.register_late_pass(|_| Box::new(PassByValue));
+    store.register_late_mod_pass(|_| Box::new(PassByValue));
     // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
     // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
     // these lints will trigger all of the time - change this once migration to diagnostic structs
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 70311a5c576..25982a45853 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1496,7 +1496,7 @@ pub enum InvalidNanComparisons {
     #[diag(lint_invalid_nan_comparisons_eq_ne)]
     EqNe {
         #[subdiagnostic]
-        suggestion: InvalidNanComparisonsSuggestion,
+        suggestion: Option<InvalidNanComparisonsSuggestion>,
     },
     #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)]
     LtLeGtGe,
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 226d01b79a8..1ba746eddeb 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -572,32 +572,36 @@ fn lint_nan<'tcx>(
     }
 
     fn eq_ne(
+        cx: &LateContext<'_>,
         e: &hir::Expr<'_>,
         l: &hir::Expr<'_>,
         r: &hir::Expr<'_>,
         f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion,
     ) -> InvalidNanComparisons {
-        let suggestion =
+        // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const.
+        let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| {
             if let Some(l_span) = l.span.find_ancestor_inside(e.span) &&
-                let Some(r_span) = r.span.find_ancestor_inside(e.span) {
+                let Some(r_span) = r.span.find_ancestor_inside(e.span)
+            {
                 f(l_span, r_span)
             } else {
                 InvalidNanComparisonsSuggestion::Spanless
-            };
+            }
+        });
 
         InvalidNanComparisons::EqNe { suggestion }
     }
 
     let lint = match binop.node {
         hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => {
-            eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
+            eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
                 nan_plus_binop: l_span.until(r_span),
                 float: r_span.shrink_to_hi(),
                 neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()),
             })
         }
         hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => {
-            eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
+            eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
                 nan_plus_binop: l_span.shrink_to_hi().to(r_span),
                 float: l_span.shrink_to_hi(),
                 neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()),
@@ -815,8 +819,7 @@ pub fn transparent_newtype_field<'a, 'tcx>(
 }
 
 /// Is type known to be non-null?
-fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
-    let tcx = cx.tcx;
+fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
     match ty.kind() {
         ty::FnPtr(_) => true,
         ty::Ref(..) => true,
@@ -835,8 +838,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
 
             def.variants()
                 .iter()
-                .filter_map(|variant| transparent_newtype_field(cx.tcx, variant))
-                .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, args), mode))
+                .filter_map(|variant| transparent_newtype_field(tcx, variant))
+                .any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode))
         }
         _ => false,
     }
@@ -844,15 +847,12 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
 
 /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
 /// If the type passed in was not scalar, returns None.
-fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-    let tcx = cx.tcx;
+fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     Some(match *ty.kind() {
         ty::Adt(field_def, field_args) => {
             let inner_field_ty = {
-                let mut first_non_zst_ty = field_def
-                    .variants()
-                    .iter()
-                    .filter_map(|v| transparent_newtype_field(cx.tcx, v));
+                let mut first_non_zst_ty =
+                    field_def.variants().iter().filter_map(|v| transparent_newtype_field(tcx, v));
                 debug_assert_eq!(
                     first_non_zst_ty.clone().count(),
                     1,
@@ -863,7 +863,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
                     .expect("No non-zst fields in transparent type.")
                     .ty(tcx, field_args)
             };
-            return get_nullable_type(cx, inner_field_ty);
+            return get_nullable_type(tcx, inner_field_ty);
         }
         ty::Int(ty) => Ty::new_int(tcx, ty),
         ty::Uint(ty) => Ty::new_uint(tcx, ty),
@@ -895,43 +895,44 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
 /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
 /// FIXME: This duplicates code in codegen.
 pub(crate) fn repr_nullable_ptr<'tcx>(
-    cx: &LateContext<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     ckind: CItemKind,
 ) -> Option<Ty<'tcx>> {
-    debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
+    debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty);
     if let ty::Adt(ty_def, args) = ty.kind() {
         let field_ty = match &ty_def.variants().raw[..] {
             [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
-                ([], [field]) | ([field], []) => field.ty(cx.tcx, args),
+                ([], [field]) | ([field], []) => field.ty(tcx, args),
                 _ => return None,
             },
             _ => return None,
         };
 
-        if !ty_is_known_nonnull(cx, field_ty, ckind) {
+        if !ty_is_known_nonnull(tcx, field_ty, ckind) {
             return None;
         }
 
         // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
         // If the computed size for the field and the enum are different, the nonnull optimization isn't
         // being applied (and we've got a problem somewhere).
-        let compute_size_skeleton = |t| SizeSkeleton::compute(t, cx.tcx, cx.param_env).unwrap();
+        let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).unwrap();
         if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
             bug!("improper_ctypes: Option nonnull optimization not applied?");
         }
 
         // Return the nullable type this Option-like enum can be safely represented with.
-        let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
+        let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi;
         if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
-            match field_ty_scalar.valid_range(cx) {
+            match field_ty_scalar.valid_range(&tcx) {
                 WrappingRange { start: 0, end }
-                    if end == field_ty_scalar.size(&cx.tcx).unsigned_int_max() - 1 =>
+                    if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 =>
                 {
-                    return Some(get_nullable_type(cx, field_ty).unwrap());
+                    return Some(get_nullable_type(tcx, field_ty).unwrap());
                 }
                 WrappingRange { start: 1, .. } => {
-                    return Some(get_nullable_type(cx, field_ty).unwrap());
+                    return Some(get_nullable_type(tcx, field_ty).unwrap());
                 }
                 WrappingRange { start, end } => {
                     unreachable!("Unhandled start and end range: ({}, {})", start, end)
@@ -1116,7 +1117,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
                         {
                             // Special-case types like `Option<extern fn()>`.
-                            if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
+                            if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
+                                .is_none()
+                            {
                                 return FfiUnsafe {
                                     ty,
                                     reason: fluent::lint_improper_ctypes_enum_repr_reason,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index ebf8a50ae8b..48b5fd6e283 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -322,8 +322,6 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM,
 
 #if LLVM_VERSION_GE(17, 0)
   const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions();
-#elif defined(LLVM_RUSTLLVM)
-  const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable();
 #else
   Buf << "Full target CPU help is not supported by this LLVM version.\n\n";
   SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} };
@@ -1120,9 +1118,15 @@ struct LLVMRustThinLTOData {
 
   // Not 100% sure what these are, but they impact what's internalized and
   // what's inlined across modules, I believe.
+#if LLVM_VERSION_GE(18, 0)
+  DenseMap<StringRef, FunctionImporter::ImportMapTy> ImportLists;
+  DenseMap<StringRef, FunctionImporter::ExportSetTy> ExportLists;
+  DenseMap<StringRef, GVSummaryMapTy> ModuleToDefinedGVSummaries;
+#else
   StringMap<FunctionImporter::ImportMapTy> ImportLists;
   StringMap<FunctionImporter::ExportSetTy> ExportLists;
   StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+#endif
   StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
 
   LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index f12094a271f..b34fead821f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -819,7 +819,7 @@ fn should_encode_span(def_kind: DefKind) -> bool {
         | DefKind::Enum
         | DefKind::Variant
         | DefKind::Trait
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::AssocTy
@@ -854,7 +854,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
         | DefKind::Enum
         | DefKind::Variant
         | DefKind::Trait
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::AssocTy
@@ -895,7 +895,7 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool {
         | DefKind::Variant
         | DefKind::Trait
         | DefKind::Impl { .. } => true,
-        DefKind::TyAlias
+        DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::AssocTy
@@ -930,7 +930,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
         | DefKind::Enum
         | DefKind::Variant
         | DefKind::Trait
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::AssocTy
@@ -974,7 +974,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
         | DefKind::Const
         | DefKind::Fn
         | DefKind::ForeignMod
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::OpaqueTy
         | DefKind::Enum
         | DefKind::Union
@@ -1067,9 +1067,8 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def
         | DefKind::Closure
         | DefKind::Generator
         | DefKind::ExternCrate => false,
-        DefKind::TyAlias => {
-            tcx.features().lazy_type_alias
-                || tcx.type_of(def_id).instantiate_identity().has_opaque_types()
+        DefKind::TyAlias { lazy } => {
+            lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types()
         }
     }
 }
@@ -1081,7 +1080,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
         | DefKind::Enum
         | DefKind::Variant
         | DefKind::Trait
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::AssocTy
@@ -1121,7 +1120,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
         | DefKind::Fn
         | DefKind::Const
         | DefKind::Static(..)
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::Impl { .. }
         | DefKind::AssocFn
@@ -1181,7 +1180,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
         | DefKind::Const
         | DefKind::Static(..)
         | DefKind::Ctor(..)
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::OpaqueTy
         | DefKind::ForeignTy
         | DefKind::Impl { .. }
@@ -1222,7 +1221,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
         | DefKind::AssocConst
         | DefKind::AnonConst
         | DefKind::Static(..)
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::OpaqueTy
         | DefKind::Impl { of_trait: false }
         | DefKind::ForeignTy
@@ -1255,7 +1254,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
         | DefKind::Field
         | DefKind::Fn
         | DefKind::Static(..)
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::OpaqueTy
         | DefKind::ForeignTy
         | DefKind::Impl { .. }
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 4287799a8e6..ea66c770b77 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -126,7 +126,8 @@ fixed_size_enum! {
         ( Enum                                     )
         ( Variant                                  )
         ( Trait                                    )
-        ( TyAlias                                  )
+        ( TyAlias { lazy: false }                  )
+        ( TyAlias { lazy: true }                   )
         ( ForeignTy                                )
         ( TraitAlias                               )
         ( AssocTy                                  )
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 0256e09e4b5..fbc32263874 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -196,7 +196,9 @@ impl<'hir> Map<'hir> {
                 ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
                 ItemKind::Mod(..) => DefKind::Mod,
                 ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
-                ItemKind::TyAlias(..) => DefKind::TyAlias,
+                ItemKind::TyAlias(..) => {
+                    DefKind::TyAlias { lazy: self.tcx.features().lazy_type_alias }
+                }
                 ItemKind::Enum(..) => DefKind::Enum,
                 ItemKind::Struct(..) => DefKind::Struct,
                 ItemKind::Union(..) => DefKind::Union,
@@ -735,17 +737,6 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Returns the `OwnerId` of `id`'s nearest module parent, or `id` itself if no
-    /// module parent is in this map.
-    pub(super) fn get_module_parent_node(self, hir_id: HirId) -> OwnerId {
-        for (def_id, node) in self.parent_owner_iter(hir_id) {
-            if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
-                return def_id;
-            }
-        }
-        CRATE_OWNER_ID
-    }
-
     /// When on an if expression, a match arm tail expression or a match arm, give back
     /// the enclosing `if` or `match` expression.
     ///
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 45a07fdd293..06b25556c82 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -102,7 +102,21 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn parent_module(self, id: HirId) -> LocalDefId {
-        self.parent_module_from_def_id(id.owner.def_id)
+        if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
+            id.owner.def_id
+        } else {
+            self.parent_module_from_def_id(id.owner.def_id)
+        }
+    }
+
+    pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalDefId {
+        while let Some(parent) = self.opt_local_parent(id) {
+            id = parent;
+            if self.def_kind(id) == DefKind::Mod {
+                break;
+            }
+        }
+        id
     }
 
     pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<ImplSubject<'tcx>> {
@@ -120,10 +134,6 @@ impl<'tcx> TyCtxt<'tcx> {
 }
 
 pub fn provide(providers: &mut Providers) {
-    providers.parent_module_from_def_id = |tcx, id| {
-        let hir = tcx.hir();
-        hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)).def_id
-    };
     providers.hir_crate_items = map::hir_crate_items;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index c1f87d79b83..ddb5e248cdc 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1592,14 +1592,13 @@ impl<'tcx> Place<'tcx> {
         self.projection.iter().any(|elem| elem.is_indirect())
     }
 
-    /// If MirPhase >= Derefered and if projection contains Deref,
-    /// It's guaranteed to be in the first place
-    pub fn has_deref(&self) -> bool {
-        // To make sure this is not accidentally used in wrong mir phase
-        debug_assert!(
-            self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
-        );
-        self.projection.first() == Some(&PlaceElem::Deref)
+    /// Returns `true` if this `Place`'s first projection is `Deref`.
+    ///
+    /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later,
+    /// `Deref` projections can only occur as the first projection. In that case this method
+    /// is equivalent to `is_indirect`, but faster.
+    pub fn is_indirect_first_projection(&self) -> bool {
+        self.as_ref().is_indirect_first_projection()
     }
 
     /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
@@ -1672,9 +1671,16 @@ impl<'tcx> PlaceRef<'tcx> {
         self.projection.iter().any(|elem| elem.is_indirect())
     }
 
-    /// If MirPhase >= Derefered and if projection contains Deref,
-    /// It's guaranteed to be in the first place
-    pub fn has_deref(&self) -> bool {
+    /// Returns `true` if this `Place`'s first projection is `Deref`.
+    ///
+    /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later,
+    /// `Deref` projections can only occur as the first projection. In that case this method
+    /// is equivalent to `is_indirect`, but faster.
+    pub fn is_indirect_first_projection(&self) -> bool {
+        // To make sure this is not accidentally used in wrong mir phase
+        debug_assert!(
+            self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
+        );
         self.projection.first() == Some(&PlaceElem::Deref)
     }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index a02f9a9f796..52a18c99edb 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -231,7 +231,7 @@ rustc_queries! {
             action = {
                 use rustc_hir::def::DefKind;
                 match tcx.def_kind(key) {
-                    DefKind::TyAlias => "expanding type alias",
+                    DefKind::TyAlias { .. } => "expanding type alias",
                     DefKind::TraitAlias => "expanding trait alias",
                     _ => "computing type of",
                 }
@@ -398,11 +398,6 @@ rustc_queries! {
         desc { "computing `#[expect]`ed lints in this crate" }
     }
 
-    query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
-        eval_always
-        desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key) }
-    }
-
     query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
         desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
         separate_provide_extern
@@ -1596,6 +1591,11 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    /// Lint against `extern fn` declarations having incompatible types.
+    query clashing_extern_declarations(_: ()) {
+        desc { "checking `extern fn` declarations are compatible" }
+    }
+
     /// Identifies the entry-point (e.g., the `main` function) for a given
     /// crate, returning `None` if there is no entry point (such as for library crates).
     query entry_fn(_: ()) -> Option<(DefId, EntryFnType)> {
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 6ba13a76563..b4c6e0d970a 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -448,7 +448,7 @@ impl<'tcx> AdtDef<'tcx> {
             Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid),
             Res::Def(DefKind::Struct, _)
             | Res::Def(DefKind::Union, _)
-            | Res::Def(DefKind::TyAlias, _)
+            | Res::Def(DefKind::TyAlias { .. }, _)
             | Res::Def(DefKind::AssocTy, _)
             | Res::SelfTyParam { .. }
             | Res::SelfTyAlias { .. }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5eef3e45f32..0b2d95506bf 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1062,7 +1062,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id)
             && let hir::TyKind::Path(hir::QPath::Resolved(
                 None,
-                hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind
+                hir::Path { res: hir::def::Res::Def(DefKind::TyAlias { .. }, def_id), .. }, )) = hir_output.kind
             && let Some(local_id) = def_id.as_local()
             && let Some(alias_ty) = self.hir().get_by_def_id(local_id).alias_ty() // it is type alias
             && let Some(alias_generics) = self.hir().get_by_def_id(local_id).generics()
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 8570f83dcc6..e71482326da 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -492,7 +492,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
             Alias(Opaque, AliasTy { def_id, .. }) => {
                 let parent = self.tcx.parent(def_id);
                 let parent_ty = self.tcx.type_of(parent).instantiate_identity();
-                if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
+                if let DefKind::TyAlias { .. } | DefKind::AssocTy = self.tcx.def_kind(parent)
                     && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
                     && parent_opaque_def_id == def_id
                 {
@@ -576,7 +576,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
             Alias(Opaque, AliasTy { def_id, .. }) => {
                 let parent = self.tcx.parent(def_id);
                 let parent_ty = self.tcx.type_of(parent).instantiate_identity();
-                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
+                if let hir::def::DefKind::TyAlias { .. } | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
                     && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
                     && parent_opaque_def_id == def_id
                 {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index d3fd49150ba..27ade16739d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -364,7 +364,7 @@ pub trait PrettyPrinter<'tcx>:
                 self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?;
                 self.write_str("::")?;
             } else if let DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait
-                | DefKind::TyAlias | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
+                | DefKind::TyAlias { .. } | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind
             {
             } else {
                 // If not covered above, like for example items out of `impl` blocks, fallback.
@@ -766,7 +766,7 @@ pub trait PrettyPrinter<'tcx>:
 
                 let parent = self.tcx().parent(def_id);
                 match self.tcx().def_kind(parent) {
-                    DefKind::TyAlias | DefKind::AssocTy => {
+                    DefKind::TyAlias { .. } | DefKind::AssocTy => {
                         // NOTE: I know we should check for NO_QUERIES here, but it's alright.
                         // `type_of` on a type alias or assoc type should never cause a cycle.
                         if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
@@ -2983,7 +2983,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
 
             match child.res {
                 def::Res::Def(DefKind::AssocTy, _) => {}
-                def::Res::Def(DefKind::TyAlias, _) => {}
+                def::Res::Def(DefKind::TyAlias { .. }, _) => {}
                 def::Res::Def(defkind, def_id) => {
                     if let Some(ns) = defkind.ns() {
                         collect_fn(&child.ident, ns, def_id);
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a695febf087..e6baa624205 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1223,7 +1223,7 @@ impl<'tcx> AliasTy<'tcx> {
             DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
             DefKind::AssocTy => ty::Projection,
             DefKind::OpaqueTy => ty::Opaque,
-            DefKind::TyAlias => ty::Weak,
+            DefKind::TyAlias { .. } => ty::Weak,
             kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
         }
     }
@@ -1945,7 +1945,7 @@ impl<'tcx> Ty<'tcx> {
             (kind, tcx.def_kind(alias_ty.def_id)),
             (ty::Opaque, DefKind::OpaqueTy)
                 | (ty::Projection | ty::Inherent, DefKind::AssocTy)
-                | (ty::Weak, DefKind::TyAlias)
+                | (ty::Weak, DefKind::TyAlias { .. })
         );
         Ty::new(tcx, Alias(kind, alias_ty))
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 90ecc8aa857..564f982f842 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -156,7 +156,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 | DefKind::Enum
                 | DefKind::Trait
                 | DefKind::OpaqueTy
-                | DefKind::TyAlias
+                | DefKind::TyAlias { .. }
                 | DefKind::ForeignTy
                 | DefKind::TraitAlias
                 | DefKind::AssocTy
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index b0961d91787..384a368434a 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -209,7 +209,7 @@ fn find_item_ty_spans(
     match ty.kind {
         hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
             if let Res::Def(kind, def_id) = path.res
-                && kind != DefKind::TyAlias {
+                && !matches!(kind, DefKind::TyAlias { .. }) {
                 let check_params = def_id.as_local().map_or(true, |def_id| {
                     if def_id == needle {
                         spans.push(ty.span);
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 4fdc3178c4e..099fefbf068 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -19,7 +19,7 @@ extern crate rustc_middle;
 mod build;
 mod check_unsafety;
 mod errors;
-mod lints;
+pub mod lints;
 pub mod thir;
 
 use rustc_middle::query::Providers;
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 3f0cc69ec59..7fb73b5c7b2 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -3,14 +3,18 @@ use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
 use rustc_hir::def::DefKind;
-use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
-use rustc_middle::ty::{self, Instance, TyCtxt};
+use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgs};
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
 use std::ops::ControlFlow;
 
 pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    check_call_recursion(tcx, body);
+}
+
+fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let def_id = body.source.def_id().expect_local();
 
     if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
@@ -23,7 +27,19 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
             _ => &[],
         };
 
-        let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_args };
+        check_recursion(tcx, body, CallRecursion { trait_args })
+    }
+}
+
+fn check_recursion<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    classifier: impl TerminatorClassifier<'tcx>,
+) {
+    let def_id = body.source.def_id().expect_local();
+
+    if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
+        let mut vis = Search { tcx, body, classifier, reachable_recursive_calls: vec![] };
         if let Some(NonRecursive) =
             TriColorDepthFirstSearch::new(&body.basic_blocks).run_from_start(&mut vis)
         {
@@ -46,20 +62,66 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     }
 }
 
+/// Requires drop elaboration to have been performed first.
+pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    let def_id = body.source.def_id().expect_local();
+
+    // First check if `body` is an `fn drop()` of `Drop`
+    if let DefKind::AssocFn = tcx.def_kind(def_id) &&
+        let Some(trait_ref) = tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) &&
+        let Some(drop_trait) = tcx.lang_items().drop_trait() && drop_trait == trait_ref.instantiate_identity().def_id {
+
+        // It was. Now figure out for what type `Drop` is implemented and then
+        // check for recursion.
+        if let ty::Ref(_, dropped_ty, _) = tcx.liberate_late_bound_regions(
+            def_id.to_def_id(),
+            tcx.fn_sig(def_id).instantiate_identity().input(0),
+        ).kind() {
+            check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty });
+        }
+    }
+}
+
+trait TerminatorClassifier<'tcx> {
+    fn is_recursive_terminator(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        body: &Body<'tcx>,
+        terminator: &Terminator<'tcx>,
+    ) -> bool;
+}
+
 struct NonRecursive;
 
-struct Search<'mir, 'tcx> {
+struct Search<'mir, 'tcx, C: TerminatorClassifier<'tcx>> {
     tcx: TyCtxt<'tcx>,
     body: &'mir Body<'tcx>,
-    trait_args: &'tcx [GenericArg<'tcx>],
+    classifier: C,
 
     reachable_recursive_calls: Vec<Span>,
 }
 
-impl<'mir, 'tcx> Search<'mir, 'tcx> {
+struct CallRecursion<'tcx> {
+    trait_args: &'tcx [GenericArg<'tcx>],
+}
+
+struct RecursiveDrop<'tcx> {
+    /// The type that `Drop` is implemented for.
+    drop_for: Ty<'tcx>,
+}
+
+impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> {
     /// Returns `true` if `func` refers to the function we are searching in.
-    fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool {
-        let Search { tcx, body, trait_args, .. } = *self;
+    fn is_recursive_terminator(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        body: &Body<'tcx>,
+        terminator: &Terminator<'tcx>,
+    ) -> bool {
+        let TerminatorKind::Call { func, args, .. } = &terminator.kind else {
+            return false;
+        };
+
         // Resolving function type to a specific instance that is being called is expensive. To
         // avoid the cost we check the number of arguments first, which is sufficient to reject
         // most of calls as non-recursive.
@@ -86,14 +148,30 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
             // calling into an entirely different method (for example, a call from the default
             // method in the trait to `<A as Trait<B>>::method`, where `A` and/or `B` are
             // specific types).
-            return callee == caller && &call_args[..trait_args.len()] == trait_args;
+            return callee == caller && &call_args[..self.trait_args.len()] == self.trait_args;
         }
 
         false
     }
 }
 
-impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
+impl<'tcx> TerminatorClassifier<'tcx> for RecursiveDrop<'tcx> {
+    fn is_recursive_terminator(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        body: &Body<'tcx>,
+        terminator: &Terminator<'tcx>,
+    ) -> bool {
+        let TerminatorKind::Drop { place, .. } = &terminator.kind else { return false };
+
+        let dropped_ty = place.ty(body, tcx).ty;
+        dropped_ty == self.drop_for
+    }
+}
+
+impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx>>
+    for Search<'mir, 'tcx, C>
+{
     type BreakVal = NonRecursive;
 
     fn node_examined(
@@ -138,10 +216,8 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
     fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
         // When we examine a node for the last time, remember it if it is a recursive call.
         let terminator = self.body[bb].terminator();
-        if let TerminatorKind::Call { func, args, .. } = &terminator.kind {
-            if self.is_recursive_call(func, args) {
-                self.reachable_recursive_calls.push(terminator.source_info.span);
-            }
+        if self.classifier.is_recursive_terminator(self.tcx, self.body, terminator) {
+            self.reachable_recursive_calls.push(terminator.source_info.span);
         }
 
         ControlFlow::Continue(())
@@ -149,15 +225,14 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
 
     fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
         let terminator = self.body[bb].terminator();
-        if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
-            && terminator.successors().count() > 1
+        let ignore_unwind = terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
+            && terminator.successors().count() > 1;
+        if ignore_unwind || self.classifier.is_recursive_terminator(self.tcx, self.body, terminator)
         {
             return true;
         }
-        // Don't traverse successors of recursive calls or false CFG edges.
-        match self.body[bb].terminator().kind {
-            TerminatorKind::Call { ref func, ref args, .. } => self.is_recursive_call(func, args),
-            TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
+        match &terminator.kind {
+            TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == &target,
             _ => false,
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 3c3cbbf3614..c08fe54c39c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -439,7 +439,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 DefKind::Struct
                 | DefKind::Ctor(CtorOf::Struct, ..)
                 | DefKind::Union
-                | DefKind::TyAlias
+                | DefKind::TyAlias { .. }
                 | DefKind::AssocTy,
                 _,
             )
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 8d78ec04821..17bb8fc37ad 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -839,7 +839,7 @@ impl Map {
         tail_elem: Option<TrackElem>,
         f: &mut impl FnMut(ValueIndex),
     ) {
-        if place.has_deref() {
+        if place.is_indirect_first_projection() {
             // We do not track indirect places.
             return;
         }
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index eca5f98a2c0..f1198d9bfd3 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -18,6 +18,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_const_eval = { path = "../rustc_const_eval" }
+rustc_mir_build = { path = "../rustc_mir_build" }
 rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index d9e7339f1b2..75473ca53fb 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -60,7 +60,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
         let basic_blocks = body.basic_blocks.as_mut();
         let local_decls = &body.local_decls;
         let needs_retag = |place: &Place<'tcx>| {
-            !place.has_deref() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway
+            !place.is_indirect_first_projection() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway
                 && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
                 && !local_decls[place.local].is_deref_temp()
         };
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 47d9f52bfb5..9a3798eea3b 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -154,7 +154,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
     fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
         if let Operand::Move(place) = *operand
             // A move out of a projection of a copy is equivalent to a copy of the original projection.
-            && !place.has_deref()
+            && !place.is_indirect_first_projection()
             && !self.fully_moved.contains(place.local)
         {
             *operand = Operand::Copy(place);
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 734321e97d8..f99a51fea0b 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -338,38 +338,16 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
         return shim::build_adt_ctor(tcx, def.to_def_id());
     }
 
-    let context = tcx
-        .hir()
-        .body_const_context(def)
-        .expect("mir_for_ctfe should not be used for runtime functions");
-
-    let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+    let body = tcx.mir_drops_elaborated_and_const_checked(def);
+    let body = match tcx.hir().body_const_context(def) {
+        // consts and statics do not have `optimized_mir`, so we can steal the body instead of
+        // cloning it.
+        Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(),
+        Some(hir::ConstContext::ConstFn) => body.borrow().clone(),
+        None => bug!("`mir_for_ctfe` called on non-const {def:?}"),
+    };
 
     let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
-
-    match context {
-        // Do not const prop functions, either they get executed at runtime or exported to metadata,
-        // so we run const prop on them, or they don't, in which case we const evaluate some control
-        // flow paths of the function and any errors in those paths will get emitted as const eval
-        // errors.
-        hir::ConstContext::ConstFn => {}
-        // Static items always get evaluated, so we can just let const eval see if any erroneous
-        // control flow paths get executed.
-        hir::ConstContext::Static(_) => {}
-        // Associated constants get const prop run so we detect common failure situations in the
-        // crate that defined the constant.
-        // Technically we want to not run on regular const items, but oli-obk doesn't know how to
-        // conveniently detect that at this point without looking at the HIR.
-        hir::ConstContext::Const => {
-            pm::run_passes(
-                tcx,
-                &mut body,
-                &[&const_prop::ConstProp],
-                Some(MirPhase::Runtime(RuntimePhase::Optimized)),
-            );
-        }
-    }
-
     pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
 
     body
@@ -446,6 +424,10 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
 
     run_analysis_to_runtime_passes(tcx, &mut body);
 
+    // Now that drop elaboration has been performed, we can check for
+    // unconditional drop recursion.
+    rustc_mir_build::lints::check_drop_recursion(tcx, &body);
+
     tcx.alloc_steal_mir(body)
 }
 
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index d31bf2072b1..a8b7a0dbb68 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -143,7 +143,7 @@ fn mark_used_by_default_parameters<'tcx>(
         | DefKind::Enum
         | DefKind::Variant
         | DefKind::Trait
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::AssocTy
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 5b3cc5d99cc..6eacbebe75f 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -428,6 +428,10 @@ passes_link_section =
 passes_macro_export =
     `#[macro_export]` only has an effect on macro definitions
 
+passes_macro_export_on_decl_macro =
+    `#[macro_export]` has no effect on declarative macro definitions
+    .note = declarative macros follow the same exporting rules as regular items
+
 passes_macro_use =
     `#[{$name}]` only has an effect on `extern crate` and modules
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index cbb030958c6..4f9b362e237 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2133,6 +2133,20 @@ impl CheckAttrVisitor<'_> {
                     );
                 }
             }
+        } else {
+            // special case when `#[macro_export]` is applied to a macro 2.0
+            let (macro_definition, _) =
+                self.tcx.hir().find(hir_id).unwrap().expect_item().expect_macro();
+            let is_decl_macro = !macro_definition.macro_rules;
+
+            if is_decl_macro {
+                self.tcx.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::MacroExport::OnDeclMacro,
+                );
+            }
         }
     }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index fbe6fc3bee4..07b437f463f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -87,7 +87,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
 
     fn handle_res(&mut self, res: Res) {
         match res {
-            Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => {
+            Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias { .. }, def_id) => {
                 self.check_def_id(def_id);
             }
             _ if self.in_pat => {}
@@ -861,7 +861,7 @@ impl<'tcx> DeadVisitor<'tcx> {
             | DefKind::Fn
             | DefKind::Static(_)
             | DefKind::Const
-            | DefKind::TyAlias
+            | DefKind::TyAlias { .. }
             | DefKind::Enum
             | DefKind::Union
             | DefKind::ForeignTy => self.warn_dead_code(def_id, "used"),
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 4f5514372d1..683717344ce 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -690,6 +690,10 @@ pub enum MacroExport {
     #[diag(passes_macro_export)]
     Normal,
 
+    #[diag(passes_macro_export_on_decl_macro)]
+    #[note]
+    OnDeclMacro,
+
     #[diag(passes_invalid_macro_export_arguments)]
     UnknownItem { name: Symbol },
 
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 794dbda3688..0463ee2914b 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -16,7 +16,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
         for id in tcx.hir().items() {
             if matches!(
                 tcx.def_kind(id.owner_id),
-                DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
+                DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union
             ) {
                 for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
                     dump_layout_of(tcx, id.owner_id.def_id, attr);
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index af9efb82beb..30a4235d371 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -583,7 +583,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         self.update(def_id, macro_ev, Level::Reachable);
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
-            DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
+            DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias { .. } => {
                 if vis.is_accessible_from(module, self.tcx) {
                     self.update(def_id, macro_ev, Level::Reachable);
                 }
@@ -1992,8 +1992,8 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> {
         let def_kind = tcx.def_kind(def_id);
 
         match def_kind {
-            DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
-                if let DefKind::TyAlias = def_kind {
+            DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias { .. } => {
+                if let DefKind::TyAlias { .. } = def_kind {
                     self.check_unnameable(def_id, effective_vis);
                 }
                 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index bfc51da170d..1b124892441 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -592,7 +592,10 @@ pub(crate) fn report_cycle<'a, D: DepKind>(
         });
     }
 
-    let alias = if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) {
+    let alias = if stack
+        .iter()
+        .all(|entry| matches!(entry.query.def_kind, Some(DefKind::TyAlias { .. })))
+    {
         Some(crate::error::Alias::Ty)
     } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) {
         Some(crate::error::Alias::Trait)
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2f432799022..a655667d01d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -278,7 +278,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 };
                 match self.r.resolve_path(
                     &segments,
-                    Some(TypeNS),
+                    None,
                     parent_scope,
                     finalize.then(|| Finalize::new(id, path.span)),
                     None,
@@ -700,7 +700,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
 
             // These items live in the type namespace.
             ItemKind::TyAlias(..) => {
-                let res = Res::Def(DefKind::TyAlias, def_id);
+                let res = Res::Def(
+                    DefKind::TyAlias { lazy: self.r.tcx.features().lazy_type_alias },
+                    def_id,
+                );
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
@@ -948,7 +951,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 DefKind::Struct
                 | DefKind::Union
                 | DefKind::Variant
-                | DefKind::TyAlias
+                | DefKind::TyAlias { .. }
                 | DefKind::ForeignTy
                 | DefKind::OpaqueTy
                 | DefKind::TraitAlias
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 7b590d16d8c..6007295b930 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -470,7 +470,7 @@ impl<'a> PathSource<'a> {
                         | DefKind::Enum
                         | DefKind::Trait
                         | DefKind::TraitAlias
-                        | DefKind::TyAlias
+                        | DefKind::TyAlias { .. }
                         | DefKind::AssocTy
                         | DefKind::TyParam
                         | DefKind::OpaqueTy
@@ -509,7 +509,7 @@ impl<'a> PathSource<'a> {
                     DefKind::Struct
                         | DefKind::Union
                         | DefKind::Variant
-                        | DefKind::TyAlias
+                        | DefKind::TyAlias { .. }
                         | DefKind::AssocTy,
                     _,
                 ) | Res::SelfTyParam { .. }
@@ -904,9 +904,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                             sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
                             &sig.decl.output,
                         );
+
+                        if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() {
+                            this.record_lifetime_params_for_impl_trait(async_node_id, span);
+                        }
                     },
                 );
-                self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id());
                 return;
             }
             FnKind::Fn(..) => {
@@ -942,12 +945,14 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                                         .iter()
                                         .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
                                     &declaration.output,
-                                )
+                                );
+
+                                if let Some((async_node_id, span)) = async_node_id {
+                                    this.record_lifetime_params_for_impl_trait(async_node_id, span);
+                                }
                             },
                         );
 
-                        this.record_lifetime_params_for_async(fn_id, async_node_id);
-
                         if let Some(body) = body {
                             // Ignore errors in function bodies if this is rustdoc
                             // Be sure not to set this until the function signature has been resolved.
@@ -1694,6 +1699,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         // Leave the responsibility to create the `LocalDefId` to lowering.
         let param = self.r.next_node_id();
         let res = LifetimeRes::Fresh { param, binder };
+        self.record_lifetime_param(param, res);
 
         // Record the created lifetime parameter so lowering can pick it up and add it to HIR.
         self.r
@@ -1734,7 +1740,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 Res::Def(DefKind::Struct, def_id)
                 | Res::Def(DefKind::Union, def_id)
                 | Res::Def(DefKind::Enum, def_id)
-                | Res::Def(DefKind::TyAlias, def_id)
+                | Res::Def(DefKind::TyAlias { .. }, def_id)
                 | Res::Def(DefKind::Trait, def_id)
                     if i + 1 == proj_start =>
                 {
@@ -3944,11 +3950,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
         if path.len() > 1
             && let Some(res) = result.full_res()
+            && let Some((&last_segment, prev_segs)) = path.split_last()
+            && prev_segs.iter().all(|seg| !seg.has_generic_args)
             && res != Res::Err
             && path[0].ident.name != kw::PathRoot
             && path[0].ident.name != kw::DollarCrate
         {
-            let last_segment = *path.last().unwrap();
             let unqualified_result = {
                 match self.resolve_path(&[last_segment], Some(ns), None) {
                     PathResult::NonModule(path_res) => path_res.expect_full_res(),
@@ -4325,39 +4332,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         )
     }
 
-    /// Construct the list of in-scope lifetime parameters for async lowering.
+    /// Construct the list of in-scope lifetime parameters for impl trait lowering.
     /// We include all lifetime parameters, either named or "Fresh".
     /// The order of those parameters does not matter, as long as it is
     /// deterministic.
-    fn record_lifetime_params_for_async(
-        &mut self,
-        fn_id: NodeId,
-        async_node_id: Option<(NodeId, Span)>,
-    ) {
-        if let Some((async_node_id, span)) = async_node_id {
-            let mut extra_lifetime_params =
-                self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
-            for rib in self.lifetime_ribs.iter().rev() {
-                extra_lifetime_params.extend(
-                    rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)),
-                );
-                match rib.kind {
-                    LifetimeRibKind::Item => break,
-                    LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
-                        if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
-                            extra_lifetime_params.extend(earlier_fresh);
-                        }
-                    }
-                    LifetimeRibKind::Generics { .. } => {}
-                    _ => {
-                        // We are in a function definition. We should only find `Generics`
-                        // and `AnonymousCreateParameter` inside the innermost `Item`.
-                        span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
+    fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) {
+        let mut extra_lifetime_params = vec![];
+
+        for rib in self.lifetime_ribs.iter().rev() {
+            extra_lifetime_params
+                .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)));
+            match rib.kind {
+                LifetimeRibKind::Item => break,
+                LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                    if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
+                        extra_lifetime_params.extend(earlier_fresh);
                     }
                 }
+                LifetimeRibKind::Generics { .. } => {}
+                _ => {
+                    // We are in a function definition. We should only find `Generics`
+                    // and `AnonymousCreateParameter` inside the innermost `Item`.
+                    span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
+                }
             }
-            self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
         }
+        self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params);
     }
 
     fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 974580f815b..c34b7df9b46 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -555,7 +555,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
             })
             .collect::<Vec<_>>();
-        let crate_def_id = CRATE_DEF_ID.to_def_id();
         // Try to filter out intrinsics candidates, as long as we have
         // some other candidates to suggest.
         let intrinsic_candidates: Vec<_> = candidates
@@ -566,8 +565,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             .collect();
         if candidates.is_empty() {
             // Put them back if we have no more candidates to suggest...
-            candidates.extend(intrinsic_candidates);
+            candidates = intrinsic_candidates;
         }
+        let crate_def_id = CRATE_DEF_ID.to_def_id();
         if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
             let mut enum_candidates: Vec<_> = self
                 .r
@@ -1180,37 +1180,34 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
     /// return the span of whole call and the span for all arguments expect the first one (`self`).
     fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
         let mut has_self_arg = None;
-        if let PathSource::Expr(Some(parent)) = source {
-            match &parent.kind {
-                ExprKind::Call(_, args) if !args.is_empty() => {
-                    let mut expr_kind = &args[0].kind;
-                    loop {
-                        match expr_kind {
-                            ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
-                                if arg_name.segments[0].ident.name == kw::SelfLower {
-                                    let call_span = parent.span;
-                                    let tail_args_span = if args.len() > 1 {
-                                        Some(Span::new(
-                                            args[1].span.lo(),
-                                            args.last().unwrap().span.hi(),
-                                            call_span.ctxt(),
-                                            None,
-                                        ))
-                                    } else {
-                                        None
-                                    };
-                                    has_self_arg = Some((call_span, tail_args_span));
-                                }
-                                break;
+        if let PathSource::Expr(Some(parent)) = source
+            && let ExprKind::Call(_, args) = &parent.kind
+            && !args.is_empty() {
+                let mut expr_kind = &args[0].kind;
+                loop {
+                    match expr_kind {
+                        ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
+                            if arg_name.segments[0].ident.name == kw::SelfLower {
+                                let call_span = parent.span;
+                                let tail_args_span = if args.len() > 1 {
+                                    Some(Span::new(
+                                        args[1].span.lo(),
+                                        args.last().unwrap().span.hi(),
+                                        call_span.ctxt(),
+                                        None,
+                                    ))
+                                } else {
+                                    None
+                                };
+                                has_self_arg = Some((call_span, tail_args_span));
                             }
-                            ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
-                            _ => break,
+                            break;
                         }
+                        ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
+                        _ => break,
                     }
                 }
-                _ => (),
-            }
-        };
+        }
         has_self_arg
     }
 
@@ -1220,15 +1217,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         // where a brace being opened means a block is being started. Look
         // ahead for the next text to see if `span` is followed by a `{`.
         let sm = self.r.tcx.sess.source_map();
-        let sp = sm.span_look_ahead(span, None, Some(50));
-        let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
-        // In case this could be a struct literal that needs to be surrounded
-        // by parentheses, find the appropriate span.
-        let closing_span = sm.span_look_ahead(span, Some("}"), Some(50));
-        let closing_brace: Option<Span> = sm
-            .span_to_snippet(closing_span)
-            .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None });
-        (followed_by_brace, closing_brace)
+        if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) {
+            // In case this could be a struct literal that needs to be surrounded
+            // by parentheses, find the appropriate span.
+            let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50));
+            let closing_brace = close_brace_span.map(|sp| span.to(sp));
+            (true, closing_brace)
+        } else {
+            (false, None)
+        }
     }
 
     /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
@@ -1422,7 +1419,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
                 err.span_label(span, fallback_label.to_string());
             }
-            (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
+            (Res::Def(DefKind::TyAlias { .. }, def_id), PathSource::Trait(_)) => {
                 err.span_label(span, "type aliases cannot be used as traits");
                 if self.r.tcx.sess.is_nightly_build() {
                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
@@ -1591,7 +1588,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 err.span_label(span, fallback_label.to_string());
                 err.note("can't use `Self` as a constructor, you must use the implemented struct");
             }
-            (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
+            (Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, _), _) if ns == ValueNS => {
                 err.note("can't use a type alias as a constructor");
             }
             _ => return false,
@@ -2407,7 +2404,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         should_continue = suggest(err, false, span, message, sugg);
                     }
                 }
-                LifetimeRibKind::Item => break,
+                LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
                 _ => {}
             }
             if !should_continue {
@@ -2513,7 +2510,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             .lifetime_ribs
             .iter()
             .rev()
-            .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item))
+            .take_while(|rib| {
+                !matches!(rib.kind, LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy)
+            })
             .flat_map(|rib| rib.bindings.iter())
             .map(|(&ident, &res)| (ident, res))
             .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 6a26a4a22ed..39541c845b3 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -68,6 +68,10 @@ impl<'tcx> Tables<'tcx> {
         self.def_ids[item.0]
     }
 
+    pub fn trait_def_id(&self, trait_def: &stable_mir::ty::TraitDef) -> DefId {
+        self.def_ids[trait_def.0]
+    }
+
     pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
         stable_mir::CrateItem(self.create_def_id(did))
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index c4bdec0ee28..d12de92db8a 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -41,6 +41,21 @@ impl<'tcx> Context for Tables<'tcx> {
     fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
         Some(self.crate_item(self.tcx.entry_fn(())?.0))
     }
+
+    fn all_trait_decls(&mut self) -> stable_mir::TraitDecls {
+        self.tcx
+            .traits(LOCAL_CRATE)
+            .iter()
+            .map(|trait_def_id| self.trait_def(*trait_def_id))
+            .collect()
+    }
+
+    fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
+        let def_id = self.trait_def_id(trait_def);
+        let trait_def = self.tcx.trait_def(def_id);
+        trait_def.stable(self)
+    }
+
     fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
         let def_id = self.item_def_id(item);
         let mir = self.tcx.optimized_mir(def_id);
@@ -515,7 +530,7 @@ impl<'tcx> Stable<'tcx> for mir::RetagKind {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_middle::ty::UserTypeAnnotationIndex {
+impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex {
     type T = usize;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
         self.as_usize()
@@ -826,7 +841,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
     type T = stable_mir::ty::FnSig;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         use rustc_target::spec::abi;
-        use stable_mir::ty::{Abi, FnSig, Unsafety};
+        use stable_mir::ty::{Abi, FnSig};
 
         FnSig {
             inputs_and_output: self
@@ -835,10 +850,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
                 .map(|ty| tables.intern_ty(ty))
                 .collect(),
             c_variadic: self.c_variadic,
-            unsafety: match self.unsafety {
-                hir::Unsafety::Normal => Unsafety::Normal,
-                hir::Unsafety::Unsafe => Unsafety::Unsafe,
-            },
+            unsafety: self.unsafety.stable(tables),
             abi: match self.abi {
                 abi::Abi::Rust => Abi::Rust,
                 abi::Abi::C { unwind } => Abi::C { unwind },
@@ -1048,7 +1060,7 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_middle::ty::ParamTy {
+impl<'tcx> Stable<'tcx> for ty::ParamTy {
     type T = stable_mir::ty::ParamTy;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
         use stable_mir::ty::ParamTy;
@@ -1056,10 +1068,80 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::ParamTy {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_middle::ty::BoundTy {
+impl<'tcx> Stable<'tcx> for ty::BoundTy {
     type T = stable_mir::ty::BoundTy;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         use stable_mir::ty::BoundTy;
         BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) }
     }
 }
+
+impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
+    type T = stable_mir::ty::Allocation;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let size = self.size();
+        let mut bytes: Vec<Option<u8>> = self
+            .inspect_with_uninit_and_ptr_outside_interpreter(0..size.bytes_usize())
+            .iter()
+            .copied()
+            .map(Some)
+            .collect();
+        for (i, b) in bytes.iter_mut().enumerate() {
+            if !self.init_mask().get(rustc_target::abi::Size::from_bytes(i)) {
+                *b = None;
+            }
+        }
+        stable_mir::ty::Allocation {
+            bytes: bytes,
+            provenance: {
+                let mut ptrs = Vec::new();
+                for (size, prov) in self.provenance().ptrs().iter() {
+                    ptrs.push((size.bytes_usize(), opaque(prov)));
+                }
+                stable_mir::ty::ProvenanceMap { ptrs }
+            },
+            align: self.align.bytes(),
+            mutability: self.mutability.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind {
+    type T = stable_mir::ty::TraitSpecializationKind;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::TraitSpecializationKind;
+
+        match self {
+            ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None,
+            ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker,
+            ty::trait_def::TraitSpecializationKind::AlwaysApplicable => {
+                TraitSpecializationKind::AlwaysApplicable
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TraitDef {
+    type T = stable_mir::ty::TraitDecl;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::TraitDecl;
+
+        TraitDecl {
+            def_id: rustc_internal::trait_def(self.def_id),
+            unsafety: self.unsafety.stable(tables),
+            paren_sugar: self.paren_sugar,
+            has_auto_impl: self.has_auto_impl,
+            is_marker: self.is_marker,
+            is_coinductive: self.is_coinductive,
+            skip_array_during_method_dispatch: self.skip_array_during_method_dispatch,
+            specialization_kind: self.specialization_kind.stable(tables),
+            must_implement_one_of: self
+                .must_implement_one_of
+                .as_ref()
+                .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()),
+            implement_via_object: self.implement_via_object,
+            deny_explicit_impl: self.deny_explicit_impl,
+        }
+    }
+}
diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs
index 5e599a77bcd..d93f25249b9 100644
--- a/compiler/rustc_smir/src/stable_mir/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/mod.rs
@@ -15,7 +15,7 @@ use std::cell::Cell;
 
 use crate::rustc_smir::Tables;
 
-use self::ty::{Ty, TyKind};
+use self::ty::{TraitDecl, TraitDef, Ty, TyKind};
 
 pub mod mir;
 pub mod ty;
@@ -32,6 +32,9 @@ pub type DefId = usize;
 /// A list of crate items.
 pub type CrateItems = Vec<CrateItem>;
 
+/// A list of crate items.
+pub type TraitDecls = Vec<TraitDef>;
+
 /// Holds information about a crate.
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct Crate {
@@ -84,6 +87,8 @@ pub trait Context {
     /// Retrieve all items of the local crate that have a MIR associated with them.
     fn all_local_items(&mut self) -> CrateItems;
     fn mir_body(&mut self, item: &CrateItem) -> mir::Body;
+    fn all_trait_decls(&mut self) -> TraitDecls;
+    fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl;
     /// Get information about the local crate.
     fn local_crate(&self) -> Crate;
     /// Retrieve a list of all external crates.
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 025225b8d19..c487db5b732 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -1,4 +1,4 @@
-use super::{mir::Mutability, with, DefId};
+use super::{mir::Mutability, mir::Safety, with, DefId};
 use crate::rustc_internal::Opaque;
 
 #[derive(Copy, Clone, Debug)]
@@ -11,6 +11,7 @@ impl Ty {
 }
 
 pub(crate) type Const = Opaque;
+type Ident = Opaque;
 pub(crate) type Region = Opaque;
 type Span = Opaque;
 
@@ -104,6 +105,12 @@ pub struct AliasDef(pub(crate) DefId);
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct TraitDef(pub(crate) DefId);
 
+impl TraitDef {
+    pub fn trait_decl(&self) -> TraitDecl {
+        with(|cx| cx.trait_decl(self))
+    }
+}
+
 #[derive(Clone, Debug)]
 pub struct GenericArgs(pub Vec<GenericArgKind>);
 
@@ -140,17 +147,11 @@ pub type PolyFnSig = Binder<FnSig>;
 pub struct FnSig {
     pub inputs_and_output: Vec<Ty>,
     pub c_variadic: bool,
-    pub unsafety: Unsafety,
+    pub unsafety: Safety,
     pub abi: Abi,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
-pub enum Unsafety {
-    Unsafe,
-    Normal,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
 pub enum Abi {
     Rust,
     C { unwind: bool },
@@ -242,3 +243,45 @@ pub struct BoundTy {
     pub var: usize,
     pub kind: BoundTyKind,
 }
+
+pub type Bytes = Vec<Option<u8>>;
+pub type Size = usize;
+pub type Prov = Opaque;
+pub type Align = u64;
+pub type InitMaskMaterialized = Vec<u64>;
+
+/// Stores the provenance information of pointers stored in memory.
+#[derive(Clone, Debug)]
+pub struct ProvenanceMap {
+    /// Provenance in this map applies from the given offset for an entire pointer-size worth of
+    /// bytes. Two entries in this map are always at least a pointer size apart.
+    pub ptrs: Vec<(Size, Prov)>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Allocation {
+    pub bytes: Bytes,
+    pub provenance: ProvenanceMap,
+    pub align: Align,
+    pub mutability: Mutability,
+}
+
+pub enum TraitSpecializationKind {
+    None,
+    Marker,
+    AlwaysApplicable,
+}
+
+pub struct TraitDecl {
+    pub def_id: TraitDef,
+    pub unsafety: Safety,
+    pub paren_sugar: bool,
+    pub has_auto_impl: bool,
+    pub is_marker: bool,
+    pub is_coinductive: bool,
+    pub skip_array_during_method_dispatch: bool,
+    pub specialization_kind: TraitSpecializationKind,
+    pub must_implement_one_of: Option<Vec<Ident>>,
+    pub implement_via_object: bool,
+    pub deny_explicit_impl: bool,
+}
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 86716da1712..983b2ab04a4 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -973,24 +973,21 @@ impl SourceMap {
         Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None)
     }
 
-    /// Returns a new span to check next none-whitespace character or some specified expected character
-    /// If `expect` is none, the first span of non-whitespace character is returned.
-    /// If `expect` presented, the first span of the character `expect` is returned
-    /// Otherwise, the span reached to limit is returned.
-    pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
+    /// Check whether span is followed by some specified expected string in limit scope
+    pub fn span_look_ahead(&self, span: Span, expect: &str, limit: Option<usize>) -> Option<Span> {
         let mut sp = span;
         for _ in 0..limit.unwrap_or(100_usize) {
             sp = self.next_point(sp);
             if let Ok(ref snippet) = self.span_to_snippet(sp) {
-                if expect.is_some_and(|es| snippet == es) {
-                    break;
+                if snippet == expect {
+                    return Some(sp);
                 }
-                if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) {
+                if snippet.chars().any(|c| !c.is_whitespace()) {
                     break;
                 }
             }
         }
-        sp
+        None
     }
 
     /// Finds the width of the character, either before or after the end of provided span,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 44820ae6f72..9ea9efb047c 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -498,6 +498,7 @@ symbols! {
         cold,
         collapse_debuginfo,
         column,
+        compare_bytes,
         compare_exchange,
         compare_exchange_weak,
         compile_error,
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index eb3f66ac308..dc233121f66 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -150,7 +150,8 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
         // Stable
         "Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind"
         | "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind"
-        | "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" => Ok(()),
+        | "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" | "thiscall"
+        | "thiscall-unwind" => Ok(()),
         "rust-intrinsic" => Err(AbiDisabled::Unstable {
             feature: sym::intrinsics,
             explain: "intrinsics are subject to change",
@@ -167,14 +168,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
             feature: sym::abi_vectorcall,
             explain: "vectorcall-unwind ABI is experimental and subject to change",
         }),
-        "thiscall" => Err(AbiDisabled::Unstable {
-            feature: sym::abi_thiscall,
-            explain: "thiscall is experimental and subject to change",
-        }),
-        "thiscall-unwind" => Err(AbiDisabled::Unstable {
-            feature: sym::abi_thiscall,
-            explain: "thiscall-unwind ABI is experimental and subject to change",
-        }),
         "rust-call" => Err(AbiDisabled::Unstable {
             feature: sym::unboxed_closures,
             explain: "rust-call ABI is subject to change",
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index fbec44b716a..cd324c94bbe 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -23,7 +23,7 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
                 LinkerFlavor::Gnu(Cc::Yes, Lld::No),
                 &["-lgcc"],
             ),
-            max_atomic_width: Some(0),
+            max_atomic_width: Some(16),
             atomic_cas: false,
             relocation_model: RelocModel::Static,
             ..TargetOptions::default()
diff --git a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs
index 34934379c7e..4e105a03e28 100644
--- a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-ibm-aix".into(),
         pointer_width: 64,
-        data_layout: "E-m:a-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: base,
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 08b27320730..e8fe55a00db 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-freebsd".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64".into(),
+        data_layout: "E-m:e-Fn32-i64:64-n32:64".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index ce64de861cd..7a0cc539f1a 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index 81286a668fe..f80b22828c1 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
index 7232dce3e96..3643f7b0c37 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-openbsd".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64".into(),
+        data_layout: "E-m:e-Fn32-i64:64-n32:64".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index 10da7872c73..b0472e64e13 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
index 8c941e10651..342b1cf4f4c 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-freebsd".into(),
         pointer_width: 64,
-        data_layout: "e-m:e-i64:64-n32:64".into(),
+        data_layout: "e-m:e-Fn32-i64:64-n32:64".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index fd896e086b5..815e3d2781c 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".into(),
         pointer_width: 64,
-        data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index 3cffcf49772..0b9b78bcec8 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".into(),
         pointer_width: 64,
-        data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
index 342f321bd5b..e036f5bdbad 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
@@ -14,7 +14,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-freebsd13.0".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions {
             endian: Endian::Big,
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
index c8c61dc46ee..c8d6f8b9c67 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index 5c51ec91f71..fdaa9d366d9 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions {
             abi: "spe".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index fc7d802cbf4..7fe708cf530 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-musl".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 912149c79e4..6f8875ba7b4 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-netbsd".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "__mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
index dec85f9961b..280d36698b4 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-openbsd".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: base,
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index a8c1c2a6132..6f245e6ab62 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions { endian: Endian::Big, features: "+secure-plt".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index abb8d13daef..1d5a5e5c6ac 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -10,7 +10,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".into(),
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i64:64-n32".into(),
+        data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
         arch: "powerpc".into(),
         options: TargetOptions {
             abi: "spe".into(),
diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
index 6389d68641a..75a65a26849 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(0),
             atomic_cas: false,
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
index a177a73483f..f2242bbe087 100644
--- a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(0),
             atomic_cas: false,
             features: "+m".into(),
             panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
index fd620696cb2..01e773fae97 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
             linker: Some("rust-lld".into()),
             cpu: "generic-rv32".into(),
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(0),
             atomic_cas: false,
             features: "+m,+c".into(),
             panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
index 12968abda08..b10e6264b73 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -5,7 +5,7 @@ pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.endian = Endian::Big;
     base.cpu = "v9".into();
-    base.max_atomic_width = Some(64);
+    base.max_atomic_width = Some(32);
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mv8plus"]);
 
     Target {
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 267f345c062..1391b51e67f 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -152,16 +152,12 @@ pub(super) trait GoalKind<'tcx>:
             let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
                 bug!("expected object type in `consider_object_bound_candidate`");
             };
-            ecx.add_goals(
-                structural_traits::predicates_for_object_candidate(
-                    &ecx,
-                    goal.param_env,
-                    goal.predicate.trait_ref(tcx),
-                    bounds,
-                )
-                .into_iter()
-                .map(|pred| goal.with(tcx, pred)),
-            );
+            ecx.add_goals(structural_traits::predicates_for_object_candidate(
+                &ecx,
+                goal.param_env,
+                goal.predicate.trait_ref(tcx),
+                bounds,
+            ));
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 72ba4f59137..b882ec254e3 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -3,6 +3,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
+use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
@@ -345,7 +346,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-) -> Vec<ty::Clause<'tcx>> {
+) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
     let tcx = ecx.tcx();
     let mut requirements = vec![];
     requirements.extend(
@@ -376,17 +377,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
         }
     }
 
-    requirements.fold_with(&mut ReplaceProjectionWith {
-        ecx,
-        param_env,
-        mapping: replace_projection_with,
-    })
+    let mut folder =
+        ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] };
+    let folded_requirements = requirements.fold_with(&mut folder);
+
+    folder
+        .nested
+        .into_iter()
+        .chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause)))
+        .collect()
 }
 
 struct ReplaceProjectionWith<'a, 'tcx> {
     ecx: &'a EvalCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
+    nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
 }
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
@@ -402,13 +408,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
             // but the where clauses we instantiated are not. We can solve this by instantiating
             // the binder at the usage site.
             let proj = self.ecx.instantiate_binder_with_infer(*replacement);
-            // FIXME: Technically this folder could be fallible?
-            let nested = self
-                .ecx
-                .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
-                .expect("expected to be able to unify goal projection with dyn's projection");
-            // FIXME: Technically we could register these too..
-            assert!(nested.is_empty(), "did not expect unification to have any nested goals");
+            // FIXME: Technically this equate could be fallible...
+            self.nested.extend(
+                self.ecx
+                    .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
+                    .expect("expected to be able to unify goal projection with dyn's projection"),
+            );
             proj.term.ty().unwrap()
         } else {
             ty.super_fold_with(self)
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 5ec9ddfe64a..60c49f665a6 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -391,13 +391,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             debug!("rerunning goal to check result is stable");
             self.search_graph.reset_encountered_overflow(encountered_overflow);
             let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
-            let new_canonical_response = EvalCtxt::evaluate_canonical_goal(
+            let Ok(new_canonical_response) = EvalCtxt::evaluate_canonical_goal(
                 self.tcx(),
                 self.search_graph,
                 canonical_goal,
                 // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal`
                 &mut ProofTreeBuilder::new_noop(),
-            )?;
+            ) else {
+                bug!(
+                    "goal went from {certainty:?} to error: re-canonicalized goal={canonical_goal:#?} \
+                    first_response={canonical_response:#?},
+                    second response was error"
+                );
+            };
             // We only check for modulo regions as we convert all regions in
             // the input to new existentials, even if they're expected to be
             // `'static` or a placeholder region.
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 75cf33d8194..e1980f4d7bb 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -58,7 +58,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             }
             DefKind::AnonConst => self.normalize_anon_const(goal),
             DefKind::OpaqueTy => self.normalize_opaque_type(goal),
-            DefKind::TyAlias => self.normalize_weak_type(goal),
+            DefKind::TyAlias { .. } => self.normalize_weak_type(goal),
             kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 1c59f3ff6c7..2b8571796df 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1429,20 +1429,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                         // Issue #109436, we need to add parentheses properly for method calls
                         // for example, `foo.into()` should be `(&foo).into()`
-                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(
-                            self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)),
-                        ) {
-                            if snippet == "." {
-                                err.multipart_suggestion_verbose(
-                                    sugg_msg,
-                                    vec![
-                                        (span.shrink_to_lo(), format!("({sugg_prefix}")),
-                                        (span.shrink_to_hi(), ")".to_string()),
-                                    ],
-                                    Applicability::MaybeIncorrect,
-                                );
-                                return true;
-                            }
+                        if let Some(_) =
+                            self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50))
+                        {
+                            err.multipart_suggestion_verbose(
+                                sugg_msg,
+                                vec![
+                                    (span.shrink_to_lo(), format!("({sugg_prefix}")),
+                                    (span.shrink_to_hi(), ")".to_string()),
+                                ],
+                                Applicability::MaybeIncorrect,
+                            );
+                            return true;
                         }
 
                         // Issue #104961, we need to add parentheses properly for compound expressions
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index 84746eba3ec..d3c4dc45923 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -22,7 +22,9 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
         assert!(!ty.is_ty_var(), "should have resolved vars before calling");
 
         if self.infcx.next_trait_solver() {
-            while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() {
+            while let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, projection_ty) =
+                *ty.kind()
+            {
                 let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::NormalizeProjectionType,
                     span: self.cause.span,
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 7eb1042d2f8..aa49a5561d1 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -128,7 +128,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
         },
         DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
         DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
-            DefKind::TyAlias => ty::List::empty(),
+            DefKind::TyAlias { .. } => ty::List::empty(),
             DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
             // Nested opaque types only occur in associated types:
             // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
@@ -145,7 +145,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
         | DefKind::Enum
         | DefKind::Variant
         | DefKind::Trait
-        | DefKind::TyAlias
+        | DefKind::TyAlias { .. }
         | DefKind::ForeignTy
         | DefKind::TraitAlias
         | DefKind::TyParam
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 06a30677d20..38768f0a05b 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -53,7 +53,9 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
 
     fn parent(&self) -> Option<LocalDefId> {
         match self.tcx.def_kind(self.item) {
-            DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None,
+            DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias { .. } => {
+                None
+            }
             DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
                 Some(self.tcx.local_parent(self.item))
             }
@@ -116,7 +118,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
             #[instrument(level = "trace", skip(self))]
             fn visit_nested_item(&mut self, id: rustc_hir::ItemId) {
                 let id = id.owner_id.def_id;
-                if let DefKind::TyAlias = self.collector.tcx.def_kind(id) {
+                if let DefKind::TyAlias { .. } = self.collector.tcx.def_kind(id) {
                     let items = self.collector.tcx.opaque_types_defined_by(id);
                     self.collector.opaques.extend(items);
                 }
@@ -295,7 +297,7 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
             collector.collect_body_and_predicate_taits();
         }
         // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
-        DefKind::TyAlias | DefKind::AssocTy => {
+        DefKind::TyAlias { .. } | DefKind::AssocTy => {
             tcx.type_of(item).instantiate_identity().visit_with(&mut collector);
         }
         DefKind::OpaqueTy => {
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 84977409904..921ce850d1e 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -223,8 +223,6 @@ impl str {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = "this is a string";
     /// let boxed_str = s.to_owned().into_boxed_str();
@@ -487,8 +485,6 @@ impl str {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let string = String::from("birthday gift");
     /// let boxed_str = string.clone().into_boxed_str();
@@ -602,8 +598,6 @@ impl str {
 ///
 /// # Examples
 ///
-/// Basic usage:
-///
 /// ```
 /// let smile_utf8 = Box::new([226, 152, 186]);
 /// let smile = unsafe { std::str::from_boxed_utf8_unchecked(smile_utf8) };
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 9254786d129..ed43244ebda 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -388,8 +388,6 @@ pub struct String {
 ///
 /// # Examples
 ///
-/// Basic usage:
-///
 /// ```
 /// // some invalid bytes, in a vector
 /// let bytes = vec![0, 159];
@@ -412,9 +410,8 @@ pub struct FromUtf8Error {
 /// This type is the error type for the [`from_utf16`] method on [`String`].
 ///
 /// [`from_utf16`]: String::from_utf16
-/// # Examples
 ///
-/// Basic usage:
+/// # Examples
 ///
 /// ```
 /// // 𝄞mu<invalid>ic
@@ -441,8 +438,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = String::new();
     /// ```
@@ -472,8 +467,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::with_capacity(10);
     ///
@@ -661,8 +654,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// // 𝄞music
     /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
@@ -704,8 +695,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// // 𝄞mus<invalid>ic<invalid>
     /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
@@ -784,8 +773,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::mem;
     ///
@@ -827,8 +814,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// // some bytes, in a vector
     /// let sparkle_heart = vec![240, 159, 146, 150];
@@ -852,8 +837,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = String::from("hello");
     /// let bytes = s.into_bytes();
@@ -871,8 +854,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = String::from("foo");
     ///
@@ -889,8 +870,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("foobar");
     /// let s_mut_str = s.as_mut_str();
@@ -910,8 +889,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("foo");
     ///
@@ -966,8 +943,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = String::with_capacity(10);
     ///
@@ -1157,8 +1132,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("foo");
     ///
@@ -1206,8 +1179,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("abc");
     ///
@@ -1235,8 +1206,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = String::from("hello");
     ///
@@ -1263,8 +1232,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("hello");
     ///
@@ -1287,8 +1254,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("abč");
     ///
@@ -1321,8 +1286,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("abç");
     ///
@@ -1514,8 +1477,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::with_capacity(3);
     ///
@@ -1563,8 +1524,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("bar");
     ///
@@ -1595,8 +1554,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("hello");
     ///
@@ -1620,8 +1577,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let a = String::from("foo");
     /// assert_eq!(a.len(), 3);
@@ -1641,8 +1596,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut v = String::new();
     /// assert!(v.is_empty());
@@ -1697,8 +1650,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("foo");
     ///
@@ -1734,8 +1685,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("α is alpha, β is beta");
     /// let beta_offset = s.find('β').unwrap_or(s.len());
@@ -1784,8 +1733,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let mut s = String::from("α is alpha, β is beta");
     /// let beta_offset = s.find('β').unwrap_or(s.len());
@@ -1834,8 +1781,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = String::from("hello");
     ///
@@ -1866,8 +1811,6 @@ impl String {
     ///
     /// # Examples
     ///
-    /// Simple usage:
-    ///
     /// ```
     /// let x = String::from("bucket");
     /// let static_ref: &'static mut str = x.leak();
@@ -1886,8 +1829,6 @@ impl FromUtf8Error {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// // some invalid bytes, in a vector
     /// let bytes = vec![0, 159];
@@ -1910,8 +1851,6 @@ impl FromUtf8Error {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// // some invalid bytes, in a vector
     /// let bytes = vec![0, 159];
@@ -1938,8 +1877,6 @@ impl FromUtf8Error {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// // some invalid bytes, in a vector
     /// let bytes = vec![0, 159];
@@ -2490,8 +2427,6 @@ pub trait ToString {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let i = 5;
     /// let five = String::from("5");
@@ -2711,8 +2646,6 @@ impl From<Box<str>> for String {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s1: String = String::from("hello world");
     /// let s2: Box<str> = s1.into_boxed_str();
@@ -2732,8 +2665,6 @@ impl From<String> for Box<str> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s1: String = String::from("hello world");
     /// let s2: Box<str> = Box::from(s1);
@@ -2866,8 +2797,6 @@ impl From<String> for Vec<u8> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s1 = String::from("hello world");
     /// let v1 = Vec::from(s1);
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index a6d6230d3a6..d7ca9c22dad 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -86,6 +86,46 @@
 /// }
 /// ```
 ///
+/// If we `derive`:
+///
+/// ```
+/// #[derive(Copy, Clone)]
+/// struct Generate<T>(fn() -> T);
+/// ```
+///
+/// the auto-derived implementations will have unnecessary `T: Copy` and `T: Clone` bounds:
+///
+/// ```
+/// # struct Generate<T>(fn() -> T);
+///
+/// // Automatically derived
+/// impl<T: Copy> Copy for Generate<T> { }
+///
+/// // Automatically derived
+/// impl<T: Clone> Clone for Generate<T> {
+///     fn clone(&self) -> Generate<T> {
+///         Generate(Clone::clone(&self.0))
+///     }
+/// }
+/// ```
+///
+/// The bounds are unnecessary because clearly the function itself should be
+/// copy- and cloneable even if its return type is not:
+///
+/// ```compile_fail,E0599
+/// #[derive(Copy, Clone)]
+/// struct Generate<T>(fn() -> T);
+///
+/// struct NotCloneable;
+///
+/// fn generate_not_cloneable() -> NotCloneable {
+///     NotCloneable
+/// }
+///
+/// Generate(generate_not_cloneable).clone(); // error: trait bounds were not satisfied
+/// // Note: With the manual implementations the above line will compile.
+/// ```
+///
 /// ## Additional implementors
 ///
 /// In addition to the [implementors listed below][impls],
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index d042aaf3084..9ef2c7cde02 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2385,6 +2385,25 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn raw_eq<T>(a: &T, b: &T) -> bool;
 
+    /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)`
+    /// as unsigned bytes, returning negative if `left` is less, zero if all the
+    /// bytes match, or positive if `right` is greater.
+    ///
+    /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`.
+    ///
+    /// # Safety
+    ///
+    /// `left` and `right` must each be [valid] for reads of `bytes` bytes.
+    ///
+    /// Note that this applies to the whole range, not just until the first byte
+    /// that differs.  That allows optimizations that can read in large chunks.
+    ///
+    /// [valid]: crate::ptr#safety
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")]
+    #[rustc_nounwind]
+    pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32;
+
     /// See documentation of [`std::hint::black_box`] for details.
     ///
     /// [`std::hint::black_box`]: crate::hint::black_box
@@ -2825,3 +2844,18 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
         write_bytes(dst, val, count)
     }
 }
+
+/// Backfill for bootstrap
+#[cfg(bootstrap)]
+pub unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32 {
+    extern "C" {
+        fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> crate::ffi::c_int;
+    }
+
+    if bytes != 0 {
+        // SAFETY: Since bytes is non-zero, the caller has met `memcmp`'s requirements.
+        unsafe { memcmp(left, right, bytes).into() }
+    } else {
+        0
+    }
+}
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index de638552fa3..be04dfe042e 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -361,6 +361,12 @@ macro_rules! impl_fold_via_try_fold {
     (rfold -> try_rfold) => {
         impl_fold_via_try_fold! { @internal rfold -> try_rfold }
     };
+    (spec_fold -> spec_try_fold) => {
+        impl_fold_via_try_fold! { @internal spec_fold -> spec_try_fold }
+    };
+    (spec_rfold -> spec_try_rfold) => {
+        impl_fold_via_try_fold! { @internal spec_rfold -> spec_try_rfold }
+    };
     (@internal $fold:ident -> $try_fold:ident) => {
         #[inline]
         fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 182d9f758ad..4c8af4eba78 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -379,4 +379,66 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
     fn nth_back(&mut self, n: usize) -> Option<I::Item> {
         (**self).nth_back(n)
     }
+    fn rfold<B, F>(self, init: B, f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        self.spec_rfold(init, f)
+    }
+    fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        self.spec_try_rfold(init, f)
+    }
+}
+
+/// Helper trait to specialize `rfold` and `rtry_fold` for `&mut I where I: Sized`
+trait DoubleEndedIteratorRefSpec: DoubleEndedIterator {
+    fn spec_rfold<B, F>(self, init: B, f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B;
+
+    fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>;
+}
+
+impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIteratorRefSpec for &mut I {
+    default fn spec_rfold<B, F>(self, init: B, mut f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let mut accum = init;
+        while let Some(x) = self.next_back() {
+            accum = f(accum, x);
+        }
+        accum
+    }
+
+    default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        let mut accum = init;
+        while let Some(x) = self.next_back() {
+            accum = f(accum, x)?;
+        }
+        try { accum }
+    }
+}
+
+impl<I: DoubleEndedIterator> DoubleEndedIteratorRefSpec for &mut I {
+    impl_fold_via_try_fold! { spec_rfold -> spec_try_rfold }
+
+    fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        (**self).try_rfold(init, f)
+    }
 }
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 98835228308..cecc120a6e2 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -4018,4 +4018,66 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
         (**self).nth(n)
     }
+    fn fold<B, F>(self, init: B, f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        self.spec_fold(init, f)
+    }
+    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        self.spec_try_fold(init, f)
+    }
+}
+
+/// Helper trait to specialize `fold` and `try_fold` for `&mut I where I: Sized`
+trait IteratorRefSpec: Iterator {
+    fn spec_fold<B, F>(self, init: B, f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B;
+
+    fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>;
+}
+
+impl<I: Iterator + ?Sized> IteratorRefSpec for &mut I {
+    default fn spec_fold<B, F>(self, init: B, mut f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        let mut accum = init;
+        while let Some(x) = self.next() {
+            accum = f(accum, x);
+        }
+        accum
+    }
+
+    default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        let mut accum = init;
+        while let Some(x) = self.next() {
+            accum = f(accum, x)?;
+        }
+        try { accum }
+    }
+}
+
+impl<I: Iterator> IteratorRefSpec for &mut I {
+    impl_fold_via_try_fold! { spec_fold -> spec_try_fold }
+
+    fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        (**self).try_fold(init, f)
+    }
 }
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 45e5b76272e..14cc523b0c1 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -312,7 +312,6 @@ macro_rules! debug_assert_ne {
 /// let c = Ok("abc".to_string());
 /// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100);
 /// ```
-#[macro_export]
 #[unstable(feature = "assert_matches", issue = "82775")]
 #[allow_internal_unstable(assert_matches)]
 #[rustc_macro_transparency = "semitransparent"]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 1020e655579..becb6330997 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1698,6 +1698,41 @@ impl<T> Option<T> {
         mem::replace(self, None)
     }
 
+    /// Takes the value out of the option, but only if the predicate evaluates to
+    /// `true` on a mutable reference to the value.
+    ///
+    /// In other words, replaces `self` with `None` if the predicate returns `true`.
+    /// This method operates similar to [`Option::take`] but conditional.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_take_if)]
+    ///
+    /// let mut x = Some(42);
+    ///
+    /// let prev = x.take_if(|v| if *v == 42 {
+    ///     *v += 1;
+    ///     false
+    /// } else {
+    ///     false
+    /// });
+    /// assert_eq!(x, Some(43));
+    /// assert_eq!(prev, None);
+    ///
+    /// let prev = x.take_if(|v| *v == 43);
+    /// assert_eq!(x, None);
+    /// assert_eq!(prev, Some(43));
+    /// ```
+    #[inline]
+    #[unstable(feature = "option_take_if", issue = "98934")]
+    pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
+    where
+        P: FnOnce(&mut T) -> bool,
+    {
+        if self.as_mut().map_or(false, predicate) { self.take() } else { None }
+    }
+
     /// Replaces the actual value in the option by the value given in parameter,
     /// returning the old value if present,
     /// leaving a [`Some`] in its place without deinitializing either one.
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 7601dd3c756..075347b80d0 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -1,22 +1,12 @@
 //! Comparison traits for `[T]`.
 
 use crate::cmp::{self, BytewiseEq, Ordering};
-use crate::ffi;
+use crate::intrinsics::compare_bytes;
 use crate::mem;
 
 use super::from_raw_parts;
 use super::memchr;
 
-extern "C" {
-    /// Calls implementation provided memcmp.
-    ///
-    /// Interprets the data as u8.
-    ///
-    /// Returns 0 for equal, < 0 for less than and > 0 for greater
-    /// than.
-    fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> ffi::c_int;
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A, B> PartialEq<[B]> for [A]
 where
@@ -74,7 +64,8 @@ where
     }
 }
 
-// Use memcmp for bytewise equality when the types allow
+// When each element can be compared byte-wise, we can compare all the bytes
+// from the whole size in one call to the intrinsics.
 impl<A, B> SlicePartialEq<B> for [A]
 where
     A: BytewiseEq<B>,
@@ -88,7 +79,7 @@ where
         // The two slices have been checked to have the same size above.
         unsafe {
             let size = mem::size_of_val(self);
-            memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
+            compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
         }
     }
 }
@@ -183,7 +174,7 @@ impl<A: Ord> SliceOrd for A {
     }
 }
 
-// memcmp compares a sequence of unsigned bytes lexicographically.
+// `compare_bytes` compares a sequence of unsigned bytes lexicographically.
 // this matches the order we want for [u8], but no others (not even [i8]).
 impl SliceOrd for u8 {
     #[inline]
@@ -195,7 +186,7 @@ impl SliceOrd for u8 {
         // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
         // We use the minimum of both lengths which guarantees that both regions are
         // valid for reads in that interval.
-        let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize };
+        let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
         if order == 0 {
             order = diff;
         }
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 2e5459321a2..009014de5c2 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -19,7 +19,7 @@
 #![feature(panic_unwind)]
 #![feature(staged_api)]
 #![feature(std_internals)]
-#![feature(abi_thiscall)]
+#![cfg_attr(bootstrap, feature(abi_thiscall))]
 #![feature(rustc_attrs)]
 #![panic_runtime]
 #![feature(panic_runtime)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 2f9cd7bc0ca..31481de8495 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -298,6 +298,7 @@
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_write_slice)]
+#![feature(offset_of)]
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index fbc7f04ce9a..7dc809a038b 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -7,17 +7,6 @@ use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
 use crate::mem;
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "solaris",
-    target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "illumos",
-    target_os = "nto",
-    target_os = "vita",
-))]
-use crate::mem::MaybeUninit;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
@@ -712,22 +701,10 @@ impl Iterator for ReadDir {
                 // requires the full extent of *entry_ptr to be in bounds of the same
                 // allocation, which is not necessarily the case here.
                 //
-                // Absent any other way to obtain a pointer to `(*entry_ptr).d_name`
-                // legally in Rust analogously to how it would be done in C, we instead
-                // need to make our own non-libc allocation that conforms to the weird
-                // imaginary definition of dirent64, and use that for a field offset
-                // computation.
+                // Instead we must access fields individually through their offsets.
                 macro_rules! offset_ptr {
                     ($entry_ptr:expr, $field:ident) => {{
-                        const OFFSET: isize = {
-                            let delusion = MaybeUninit::<dirent64>::uninit();
-                            let entry_ptr = delusion.as_ptr();
-                            unsafe {
-                                ptr::addr_of!((*entry_ptr).$field)
-                                    .cast::<u8>()
-                                    .offset_from(entry_ptr.cast::<u8>())
-                            }
-                        };
+                        const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize;
                         if true {
                             // Cast to the same type determined by the else branch.
                             $entry_ptr.byte_offset(OFFSET).cast::<_>()
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index a7beb2a1767..15e8c1eb9f8 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -180,7 +180,7 @@ def p(msg):
 
 
 def err(msg):
-    print("configure: error: " + msg)
+    print("\nconfigure: ERROR: " + msg + "\n")
     sys.exit(1)
 
 def is_value_list(key):
@@ -544,7 +544,14 @@ def write_config_toml(writer, section_order, targets, sections):
 
 def quit_if_file_exists(file):
     if os.path.isfile(file):
-        err("Existing '" + file + "' detected.")
+        msg = "Existing '{}' detected. Exiting".format(file)
+
+        # If the output object directory isn't empty, we can get these errors
+        host_objdir = os.environ.get("OBJDIR_ON_HOST")
+        if host_objdir is not None:
+            msg += "\nIs objdir '{}' clean?".format(host_objdir)
+
+        err(msg)
 
 if __name__ == "__main__":
     # If 'config.toml' already exists, exit the script at this point
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index 0613b999793..14ee5659ed5 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -1159,8 +1159,8 @@ impl Step for CrtBeginEnd {
             return out_dir;
         }
 
-        let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
-        let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
+        let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtbegin.c");
+        let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtend.c");
         if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o"))
             && up_to_date(&crtend_src, &out_dir.join("crtendS.o"))
         {
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 852f2e20935..b83b198780b 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -14,7 +14,8 @@ for example:
 ./src/ci/docker/run.sh x86_64-gnu
 ```
 
-Images will output artifacts in an `obj` dir at the root of a repository.
+Images will output artifacts in an `obj` dir at the root of a repository. Note
+that the script will overwrite the contents of this directory.
 
 To match conditions in rusts CI, also set the environment variable `DEPLOY=1`, e.g.:
 ```
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig
index 10075907beb..470cef1a84e 100644
--- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig
@@ -10,7 +10,7 @@ CT_ARCH_64=y
 CT_ARCH_ARCH="rv64gc"
 CT_KERNEL_LINUX=y
 CT_LINUX_V_4_20=y
-CT_BINUTILS_V_2_32=y
+CT_BINUTILS_V_2_36=y
 CT_GLIBC_V_2_29=y
 CT_GCC_V_8=y
 CT_CC_LANG_CXX=y
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 9bc074237e6..670e37b9d01 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -135,8 +135,8 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the
 # cross compilers.
-# Luckily one of the folders is /usr/local/include so symlink /usr/include/asm-generic there
-RUN ln -s /usr/include/asm-generic /usr/local/include/asm
+# Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there
+RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm
 
 ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \
   --set target.wasm32-wasi.wasi-root=/wasm32-wasi \
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index da9d68672c4..87db964a15f 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -266,6 +266,7 @@ docker \
   --env BASE_COMMIT="$BASE_COMMIT" \
   --env DIST_TRY_BUILD \
   --env PR_CI_JOB \
+  --env OBJDIR_ON_HOST="$objdir" \
   --init \
   --rm \
   rust-ci \
diff --git a/src/ci/run.sh b/src/ci/run.sh
index da1960fc057..b8cb758bf40 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -8,7 +8,7 @@ fi
 
 if [ "$NO_CHANGE_USER" = "" ]; then
   if [ "$LOCAL_USER_ID" != "" ]; then
-    useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user
+    id -u user &>/dev/null || useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user
     export HOME=/home/user
     unset LOCAL_USER_ID
 
@@ -154,13 +154,25 @@ fi
 # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
 # Pipelines it happened that the certificates were marked as expired.
 datecheck() {
-  echo "::group::Clock drift check"
+  # If an error has happened, we do not want to start a new group, because that will collapse
+  # a previous group that might have contained the error log.
+  exit_code=$?
+
+  if [ $exit_code -eq 0 ]
+  then
+    echo "::group::Clock drift check"
+  fi
+
   echo -n "  local time: "
   date
   echo -n "  network time: "
   curl -fs --head http://ci-caches.rust-lang.org | grep ^Date: \
       | sed 's/Date: //g' || true
-  echo "::endgroup::"
+
+  if [ $exit_code -eq 0 ]
+  then
+    echo "::endgroup::"
+  fi
 }
 datecheck
 trap datecheck EXIT
@@ -171,6 +183,9 @@ trap datecheck EXIT
 # sccache server at the start of the build, but no need to worry if this fails.
 SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
 
+# Our build may overwrite config.toml, so we remove it here
+rm -f config.toml
+
 $SRC/configure $RUST_CONFIGURE_ARGS
 
 retry make prepare
diff --git a/src/doc/unstable-book/src/language-features/abi-thiscall.md b/src/doc/unstable-book/src/language-features/abi-thiscall.md
deleted file mode 100644
index 73bc6eacf42..00000000000
--- a/src/doc/unstable-book/src/language-features/abi-thiscall.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# `abi_thiscall`
-
-The tracking issue for this feature is: [#42202]
-
-[#42202]: https://github.com/rust-lang/rust/issues/42202
-
-------------------------
-
-The MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++
-instance methods by default; it is identical to the usual (C) calling
-convention on x86 Windows except that the first parameter of the method,
-the `this` pointer, is passed in the ECX register.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index c31d104f8cb..384010034e6 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -79,7 +79,7 @@ pub(crate) fn try_inline(
             build_impls(cx, did, attrs_without_docs, &mut ret);
             clean::UnionItem(build_union(cx, did))
         }
-        Res::Def(DefKind::TyAlias, did) => {
+        Res::Def(DefKind::TyAlias { .. }, did) => {
             record_extern_fqn(cx, did, ItemType::Typedef);
             build_impls(cx, did, attrs_without_docs, &mut ret);
             clean::TypedefItem(build_type_alias(cx, did))
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a5efcc989f6..b6ba4c853d4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1706,7 +1706,7 @@ fn maybe_expand_private_type_alias<'tcx>(
     cx: &mut DocContext<'tcx>,
     path: &hir::Path<'tcx>,
 ) -> Option<Type> {
-    let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
+    let Res::Def(DefKind::TyAlias { .. }, def_id) = path.res else { return None };
     // Substitute private type aliases
     let def_id = def_id.as_local()?;
     let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id())
@@ -1970,7 +1970,7 @@ impl<'tcx> ContainerTy<'tcx> {
                 let (DefKind::Struct
                 | DefKind::Union
                 | DefKind::Enum
-                | DefKind::TyAlias
+                | DefKind::TyAlias { .. }
                 | DefKind::Trait
                 | DefKind::AssocTy
                 | DefKind::Variant) = tcx.def_kind(container)
@@ -2709,7 +2709,7 @@ fn clean_impl<'tcx>(
     let for_ = clean_ty(impl_.self_ty, cx);
     let type_alias =
         for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) {
-            DefKind::TyAlias => Some(clean_middle_ty(
+            DefKind::TyAlias { .. } => Some(clean_middle_ty(
                 ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()),
                 cx,
                 Some(def_id.to_def_id()),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 944d0145de2..3c79ce57782 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -504,8 +504,22 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
 
     let (kind, did) = match res {
         Res::Def(
-            kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct
-            | Union | Mod | ForeignTy | Const | Static(_) | Macro(..) | TraitAlias),
+            kind @ (AssocTy
+            | AssocFn
+            | AssocConst
+            | Variant
+            | Fn
+            | TyAlias { .. }
+            | Enum
+            | Trait
+            | Struct
+            | Union
+            | Mod
+            | ForeignTy
+            | Const
+            | Static(_)
+            | Macro(..)
+            | TraitAlias),
             did,
         ) => (kind.into(), did),
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 12d620b5b18..d7da8120996 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -10,6 +10,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Path};
 use rustc_interface::interface;
+use rustc_lint::{late_lint_mod, MissingDoc};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
@@ -262,8 +263,9 @@ pub(crate) fn create_config(
         parse_sess_created: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
         override_queries: Some(|_sess, providers, _external_providers| {
+            // We do not register late module lints, so this only runs `MissingDoc`.
             // Most lints will require typechecking, so just don't run them.
-            providers.lint_mod = |_, _| {};
+            providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc);
             // hack so that `used_trait_imports` won't try to call typeck
             providers.used_trait_imports = |_, _| {
                 static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default);
@@ -317,9 +319,7 @@ pub(crate) fn run_global_ctxt(
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
     tcx.sess.abort_if_errors();
-    tcx.sess.time("missing_docs", || {
-        rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
-    });
+    tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
     tcx.sess.time("check_mod_attrs", || {
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
     });
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index a3017201cb1..a788935581f 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -115,7 +115,7 @@ impl From<DefKind> for ItemType {
             DefKind::Struct => Self::Struct,
             DefKind::Union => Self::Union,
             DefKind::Trait => Self::Trait,
-            DefKind::TyAlias => Self::Typedef,
+            DefKind::TyAlias { .. } => Self::Typedef,
             DefKind::TraitAlias => Self::TraitAlias,
             DefKind::Macro(kind) => match kind {
                 MacroKind::Bang => ItemType::Macro,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 4de30e4ed9d..1b8d999024c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -592,7 +592,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                         .unwrap_or(Vec::new())
                 }
             }
-            Res::Def(DefKind::TyAlias, did) => {
+            Res::Def(DefKind::TyAlias { .. }, did) => {
                 // Resolve the link on the type the alias points to.
                 // FIXME: if the associated item is defined directly on the type alias,
                 // it will show up on its documentation page, we should link there instead.
@@ -1865,7 +1865,12 @@ fn resolution_failure(
                                 }
                                 return;
                             }
-                            Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
+                            Trait
+                            | TyAlias { .. }
+                            | ForeignTy
+                            | OpaqueTy
+                            | TraitAlias
+                            | TyParam
                             | Static(_) => "associated item",
                             Impl { .. } | GlobalAsm => unreachable!("not a path"),
                         }
diff --git a/src/llvm-project b/src/llvm-project
-Subproject a7d11c453784a3f258c7269b5108c58592d27e1
+Subproject 7c612e1732f3976fcfe29526ad796cbb6174b82
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 137bd9c9451..bc011a6c354 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1170,7 +1170,7 @@ fn referent_used_exactly_once<'tcx>(
         && let [location] = *local_assignments(mir, local).as_slice()
         && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
         && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
-        && !place.has_deref()
+        && !place.is_indirect_first_projection()
         // Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
         && TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
     {
diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
index f95d2c2edb1..b00fa104f98 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
                 && fields
                     .iter()
                     .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
-                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
+                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias { .. }, ..))
             {
                 let expr_spans = fields
                     .iter()
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 4cd8a8c3325..171b7faf219 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -286,7 +286,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
 /// Checks if the given `QPath` belongs to a type alias.
 pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
     match *qpath {
-        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
+        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, ..)),
         QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 0669ea72eb3..06fd9529044 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -219,7 +219,7 @@ fn path_segment_certainty(
                 // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value.
                 let certainty = lhs.join_clearing_def_ids(rhs);
                 if resolves_to_type {
-                    if cx.tcx.def_kind(def_id) == DefKind::TyAlias {
+                    if let DefKind::TyAlias { .. } = cx.tcx.def_kind(def_id) {
                         adt_def_id(cx.tcx.type_of(def_id).instantiate_identity())
                             .map_or(certainty, |def_id| certainty.with_def_id(def_id))
                     } else {
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index d2f258320f0..ff1d5cecb72 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -29,7 +29,7 @@ anyhow = "1"
 libc = "0.2"
 
 [target.'cfg(windows)'.dependencies]
-miow = "0.5"
+miow = "0.6"
 
 [target.'cfg(windows)'.dependencies.windows]
 version = "0.48.0"
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index c8a370085a0..7f73cac63cb 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -368,7 +368,6 @@ impl Checker {
             return;
         }
         // Search for intra-doc links that rustdoc didn't warn about
-        // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
         // NOTE: only looks at one line at a time; in practice this should find most links
         for (i, line) in source.lines().enumerate() {
             for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index a6e67ef8699..fa93c9e00b1 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -9,7 +9,7 @@ use std::{
 
 /// A vector clock index, this is associated with a thread id
 /// but in some cases one vector index may be shared with
-/// multiple thread ids if it safe to do so.
+/// multiple thread ids if it's safe to do so.
 #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
 pub struct VectorIdx(u32);
 
diff --git a/src/tools/miri/tests/fail/uninit_buffer.stderr b/src/tools/miri/tests/fail/uninit_buffer.stderr
index 8da532cfff0..90210bf7f11 100644
--- a/src/tools/miri/tests/fail/uninit_buffer.stderr
+++ b/src/tools/miri/tests/fail/uninit_buffer.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
   --> RUSTLIB/core/src/slice/cmp.rs:LL:CC
    |
-LL |         let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
+LL |         let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr
index 210fc8e109a..701ec601369 100644
--- a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr
+++ b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
   --> RUSTLIB/core/src/slice/cmp.rs:LL:CC
    |
-LL |         let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
+LL |         let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/opt-dist/src/environment/linux.rs b/src/tools/opt-dist/src/environment/linux.rs
index c2a328b1dbc..58b7e6d2306 100644
--- a/src/tools/opt-dist/src/environment/linux.rs
+++ b/src/tools/opt-dist/src/environment/linux.rs
@@ -14,7 +14,7 @@ impl Environment for LinuxEnvironment {
         Utf8PathBuf::from("/checkout")
     }
 
-    fn downloaded_llvm_dir(&self) -> Utf8PathBuf {
+    fn host_llvm_dir(&self) -> Utf8PathBuf {
         Utf8PathBuf::from("/rustroot")
     }
 
diff --git a/src/tools/opt-dist/src/environment/mod.rs b/src/tools/opt-dist/src/environment/mod.rs
index d28983d289c..a8650fad011 100644
--- a/src/tools/opt-dist/src/environment/mod.rs
+++ b/src/tools/opt-dist/src/environment/mod.rs
@@ -15,8 +15,8 @@ pub trait Environment {
     /// The rustc checkout, where the compiler source is located.
     fn checkout_path(&self) -> Utf8PathBuf;
 
-    /// Path to the downloaded host LLVM.
-    fn downloaded_llvm_dir(&self) -> Utf8PathBuf;
+    /// Path to the host LLVM used to compile LLVM in `src/llvm-project`.
+    fn host_llvm_dir(&self) -> Utf8PathBuf;
 
     /// Directory where the optimization artifacts (PGO/BOLT profiles, etc.)
     /// will be stored.
diff --git a/src/tools/opt-dist/src/environment/windows.rs b/src/tools/opt-dist/src/environment/windows.rs
index 12a63cbb03c..8a9733d6496 100644
--- a/src/tools/opt-dist/src/environment/windows.rs
+++ b/src/tools/opt-dist/src/environment/windows.rs
@@ -24,7 +24,7 @@ impl Environment for WindowsEnvironment {
         self.checkout_dir.clone()
     }
 
-    fn downloaded_llvm_dir(&self) -> Utf8PathBuf {
+    fn host_llvm_dir(&self) -> Utf8PathBuf {
         self.checkout_path().join("citools").join("clang-rust")
     }
 
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index a9e88bdbb60..59c73fbd695 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -66,20 +66,32 @@ fn init_compiler_benchmarks(
     .workdir(&env.rustc_perf_dir())
 }
 
+/// Describes which `llvm-profdata` binary should be used for merging PGO profiles.
+enum LlvmProfdata {
+    /// Use llvm-profdata from the host toolchain (i.e. from LLVM provided externally).
+    Host,
+    /// Use llvm-profdata from the target toolchain (i.e. from LLVM built from `src/llvm-project`).
+    Target,
+}
+
 fn merge_llvm_profiles(
     env: &dyn Environment,
     merged_path: &Utf8Path,
     profile_dir: &Utf8Path,
+    profdata: LlvmProfdata,
 ) -> anyhow::Result<()> {
-    cmd(&[
-        env.downloaded_llvm_dir().join("bin/llvm-profdata").as_str(),
-        "merge",
-        "-o",
-        merged_path.as_str(),
-        profile_dir.as_str(),
-    ])
-    .run()
-    .context("Cannot merge LLVM profiles")?;
+    let llvm_profdata = match profdata {
+        LlvmProfdata::Host => env.host_llvm_dir().join("bin/llvm-profdata"),
+        LlvmProfdata::Target => env
+            .build_artifacts()
+            .join("llvm")
+            .join("build")
+            .join(format!("bin/llvm-profdata{}", env.executable_extension())),
+    };
+
+    cmd(&[llvm_profdata.as_str(), "merge", "-o", merged_path.as_str(), profile_dir.as_str()])
+        .run()
+        .context("Cannot merge LLVM profiles")?;
     Ok(())
 }
 
@@ -118,7 +130,7 @@ pub fn gather_llvm_profiles(
     let merged_profile = env.opt_artifacts().join("llvm-pgo.profdata");
     log::info!("Merging LLVM PGO profiles to {merged_profile}");
 
-    merge_llvm_profiles(env, &merged_profile, profile_root)?;
+    merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Host)?;
     log_profile_stats("LLVM", &merged_profile, profile_root)?;
 
     // We don't need the individual .profraw files now that they have been merged
@@ -154,7 +166,7 @@ pub fn gather_rustc_profiles(
     let merged_profile = env.opt_artifacts().join("rustc-pgo.profdata");
     log::info!("Merging Rustc PGO profiles to {merged_profile}");
 
-    merge_llvm_profiles(env, &merged_profile, profile_root)?;
+    merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Target)?;
     log_profile_stats("Rustc", &merged_profile, profile_root)?;
 
     // We don't need the individual .profraw files now that they have been merged
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index c29446d8235..fae07111806 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -485,6 +485,7 @@ impl AttrsWithOwner {
             },
             AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
             AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it),
         };
 
         let attrs = raw_attrs.filter(db.upcast(), def.krate(db));
@@ -570,6 +571,7 @@ impl AttrsWithOwner {
             },
             AttrDefId::ExternBlockId(id) => any_has_attrs(db, id),
             AttrDefId::ExternCrateId(id) => any_has_attrs(db, id),
+            AttrDefId::UseId(id) => any_has_attrs(db, id),
         };
 
         AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 152c02743f7..3853a6ab3a5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -313,13 +313,7 @@ impl ExprCollector<'_> {
                 let body = self.collect_labelled_block_opt(label, e.loop_body());
                 self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
             }
-            ast::Expr::WhileExpr(e) => {
-                let label = e.label().map(|label| self.collect_label(label));
-                let body = self.collect_labelled_block_opt(label, e.loop_body());
-                let condition = self.collect_expr_opt(e.condition());
-
-                self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
-            }
+            ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
             ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
             ast::Expr::CallExpr(e) => {
                 let is_rustc_box = {
@@ -731,6 +725,32 @@ impl ExprCollector<'_> {
         expr_id
     }
 
+    /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into:
+    /// ```ignore (pseudo-rust)
+    /// [opt_ident]: loop {
+    ///   if <cond> {
+    ///     <body>
+    ///   }
+    ///   else {
+    ///     break;
+    ///   }
+    /// }
+    /// ```
+    /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`
+    /// to preserve drop semantics. We should probably do the same in future.
+    fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
+        let label = e.label().map(|label| self.collect_label(label));
+        let body = self.collect_labelled_block_opt(label, e.loop_body());
+        let condition = self.collect_expr_opt(e.condition());
+        let break_expr =
+            self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone());
+        let if_expr = self.alloc_expr(
+            Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
+            syntax_ptr.clone(),
+        );
+        self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr)
+    }
+
     /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
     /// ```ignore (pseudo-rust)
     /// match IntoIterator::into_iter(<head>) {
@@ -893,15 +913,14 @@ impl ExprCollector<'_> {
         self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
     }
 
-    fn collect_macro_call<F, T, U>(
+    fn collect_macro_call<T, U>(
         &mut self,
         mcall: ast::MacroCall,
         syntax_ptr: AstPtr<ast::MacroCall>,
         record_diagnostics: bool,
-        collector: F,
+        collector: impl FnOnce(&mut Self, Option<T>) -> U,
     ) -> U
     where
-        F: FnOnce(&mut Self, Option<T>) -> U,
         T: ast::AstNode,
     {
         // File containing the macro call. Expansion errors will be attached here.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index eeaed87164d..5d71abe37cc 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -178,14 +178,6 @@ impl Printer<'_> {
                 w!(self, "loop ");
                 self.print_expr(*body);
             }
-            Expr::While { condition, body, label } => {
-                if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name.display(self.db));
-                }
-                w!(self, "while ");
-                self.print_expr(*condition);
-                self.print_expr(*body);
-            }
             Expr::Call { callee, args, is_assignee_expr: _ } => {
                 self.print_expr(*callee);
                 w!(self, "(");
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index 69741c445fb..2a90a09f25e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -228,11 +228,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
             scopes.set_scope(expr, scope);
             compute_block_scopes(statements, *tail, body, scopes, &mut scope);
         }
-        Expr::While { condition, body: body_expr, label } => {
-            let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
-            compute_expr_scopes(*condition, body, scopes, &mut scope);
-            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
-        }
         Expr::Loop { body: body_expr, label } => {
             let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
             compute_expr_scopes(*body_expr, body, scopes, &mut scope);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
index bb79e28f267..4cfd318a433 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
@@ -14,8 +14,8 @@ use crate::{
     item_scope::ItemScope,
     nameres::DefMap,
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, MacroId,
-    ModuleDefId, ModuleId, TraitId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, ImplId,
+    Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, VariantId,
 };
 
 pub trait ChildBySource {
@@ -91,6 +91,8 @@ impl ChildBySource for ItemScope {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         self.declarations().for_each(|item| add_module_def(db, res, file_id, item));
         self.impls().for_each(|imp| add_impl(db, res, file_id, imp));
+        self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext));
+        self.use_decls().for_each(|ext| add_use(db, res, file_id, ext));
         self.unnamed_consts().for_each(|konst| {
             let loc = konst.lookup(db);
             if loc.id.file_id() == file_id {
@@ -167,6 +169,23 @@ impl ChildBySource for ItemScope {
                 map[keys::IMPL].insert(loc.source(db).value, imp)
             }
         }
+        fn add_extern_crate(
+            db: &dyn DefDatabase,
+            map: &mut DynMap,
+            file_id: HirFileId,
+            ext: ExternCrateId,
+        ) {
+            let loc = ext.lookup(db);
+            if loc.id.file_id() == file_id {
+                map[keys::EXTERN_CRATE].insert(loc.source(db).value, ext)
+            }
+        }
+        fn add_use(db: &dyn DefDatabase, map: &mut DynMap, file_id: HirFileId, ext: UseId) {
+            let loc = ext.lookup(db);
+            if loc.id.file_id() == file_id {
+                map[keys::USE].insert(loc.source(db).value, ext)
+            }
+        }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 54fe9a2e844..91db68058b0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -2,6 +2,7 @@
 
 pub mod adt;
 
+use base_db::CrateId;
 use hir_expand::{
     name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
 };
@@ -467,6 +468,7 @@ pub struct ExternCrateDeclData {
     pub name: Name,
     pub alias: Option<ImportAlias>,
     pub visibility: RawVisibility,
+    pub crate_id: Option<CrateId>,
 }
 
 impl ExternCrateDeclData {
@@ -478,10 +480,21 @@ impl ExternCrateDeclData {
         let item_tree = loc.id.item_tree(db);
         let extern_crate = &item_tree[loc.id.value];
 
+        let name = extern_crate.name.clone();
+        let crate_id = if name == hir_expand::name![self] {
+            Some(loc.container.krate())
+        } else {
+            db.crate_def_map(loc.container.krate())
+                .extern_prelude()
+                .find(|&(prelude_name, ..)| *prelude_name == name)
+                .map(|(_, root)| root.krate())
+        };
+
         Arc::new(Self {
             name: extern_crate.name.clone(),
             visibility: item_tree[extern_crate.visibility].clone(),
             alias: extern_crate.alias.clone(),
+            crate_id,
         })
     }
 }
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 82e6dfb30c8..e34a6768f28 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -23,17 +23,17 @@ use crate::{
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
     EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
-    FunctionLoc, GenericDefId, ImplId, ImplLoc, ImportId, ImportLoc, InTypeConstId, InTypeConstLoc,
-    LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc,
-    ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId,
-    TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId,
+    FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId,
+    LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc,
+    StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc,
+    TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
 pub trait InternDatabase: SourceDatabase {
     // region: items
     #[salsa::interned]
-    fn intern_import(&self, loc: ImportLoc) -> ImportId;
+    fn intern_use(&self, loc: UseLoc) -> UseId;
     #[salsa::interned]
     fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId;
     #[salsa::interned]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
index 4197d010608..d0f2bfab432 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs
@@ -10,7 +10,7 @@ use crate::{
     dyn_map::{DynMap, Policy},
     ConstId, EnumId, EnumVariantId, ExternCrateId, FieldId, FunctionId, ImplId, LifetimeParamId,
     Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
-    TypeOrConstParamId, UnionId,
+    TypeOrConstParamId, UnionId, UseId,
 };
 
 pub type Key<K, V> = crate::dyn_map::Key<K, V, AstPtrPolicy<K, V>>;
@@ -26,6 +26,7 @@ pub const STRUCT: Key<ast::Struct, StructId> = Key::new();
 pub const UNION: Key<ast::Union, UnionId> = Key::new();
 pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
 pub const EXTERN_CRATE: Key<ast::ExternCrate, ExternCrateId> = Key::new();
+pub const USE: Key<ast::Use, UseId> = Key::new();
 
 pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
 pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index cc85bd893ac..6db8398bc98 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -164,18 +164,26 @@ impl Expander {
             return ExpandResult { value: None, err };
         };
 
-        Self::enter_expand_inner(db, call_id, err).map(|value| {
-            value.and_then(|InFile { file_id, value }| {
-                let parse = value.cast::<T>()?;
-
-                self.recursion_depth += 1;
-                self.hygiene = Hygiene::new(db.upcast(), file_id);
-                let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
-                let mark =
-                    Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
-                Some((mark, parse))
-            })
-        })
+        let res = Self::enter_expand_inner(db, call_id, err);
+        match res.err {
+            // If proc-macro is disabled or unresolved, we want to expand to a missing expression
+            // instead of an empty tree which might end up in an empty block.
+            Some(ExpandError::UnresolvedProcMacro(_)) => res.map(|_| None),
+            _ => res.map(|value| {
+                value.and_then(|InFile { file_id, value }| {
+                    let parse = value.cast::<T>()?;
+
+                    self.recursion_depth += 1;
+                    self.hygiene = Hygiene::new(db.upcast(), file_id);
+                    let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
+                    let mark = Mark {
+                        file_id: old_file_id,
+                        bomb: DropBomb::new("expansion mark dropped"),
+                    };
+                    Some((mark, parse))
+                })
+            }),
+        }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index 8a140a1ec18..6591c92ac62 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -191,11 +191,6 @@ pub enum Expr {
         body: ExprId,
         label: Option<LabelId>,
     },
-    While {
-        condition: ExprId,
-        body: ExprId,
-        label: Option<LabelId>,
-    },
     Call {
         callee: ExprId,
         args: Box<[ExprId]>,
@@ -379,10 +374,6 @@ impl Expr {
                 }
             }
             Expr::Loop { body, .. } => f(*body),
-            Expr::While { condition, body, .. } => {
-                f(*condition);
-                f(*body);
-            }
             Expr::Call { callee, args, .. } => {
                 f(*callee);
                 args.iter().copied().for_each(f);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 2ac1bcdc079..873accafb43 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -16,6 +16,7 @@ use syntax::ast;
 use crate::{
     db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
     ExternCrateId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
+    UseId,
 };
 
 #[derive(Copy, Clone, Debug)]
@@ -113,6 +114,17 @@ impl ItemScope {
         self.declarations.iter().copied()
     }
 
+    pub fn extern_crate_decls(
+        &self,
+    ) -> impl Iterator<Item = ExternCrateId> + ExactSizeIterator + '_ {
+        self.extern_crate_decls.iter().copied()
+    }
+
+    pub fn use_decls(&self) -> impl Iterator<Item = UseId> + ExactSizeIterator + '_ {
+        // FIXME: to be implemented
+        std::iter::empty()
+    }
+
     pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
         self.impls.iter().copied()
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 6f80bb6e07c..c9b0f75f1a8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -188,7 +188,7 @@ impl ItemTree {
     fn shrink_to_fit(&mut self) {
         if let Some(data) = &mut self.data {
             let ItemTreeData {
-                imports,
+                uses,
                 extern_crates,
                 extern_blocks,
                 functions,
@@ -211,7 +211,7 @@ impl ItemTree {
                 vis,
             } = &mut **data;
 
-            imports.shrink_to_fit();
+            uses.shrink_to_fit();
             extern_crates.shrink_to_fit();
             extern_blocks.shrink_to_fit();
             functions.shrink_to_fit();
@@ -262,7 +262,7 @@ static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(P
 
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemTreeData {
-    imports: Arena<Import>,
+    uses: Arena<Use>,
     extern_crates: Arena<ExternCrate>,
     extern_blocks: Arena<ExternBlock>,
     functions: Arena<Function>,
@@ -486,7 +486,7 @@ macro_rules! mod_items {
 }
 
 mod_items! {
-    Import in imports -> ast::Use,
+    Use in uses -> ast::Use,
     ExternCrate in extern_crates -> ast::ExternCrate,
     ExternBlock in extern_blocks -> ast::ExternBlock,
     Function in functions -> ast::Fn,
@@ -541,7 +541,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Import {
+pub struct Use {
     pub visibility: RawVisibilityId,
     pub ast_id: FileAstId<ast::Use>,
     pub use_tree: UseTree,
@@ -744,7 +744,7 @@ pub struct MacroDef {
     pub ast_id: FileAstId<ast::MacroDef>,
 }
 
-impl Import {
+impl Use {
     /// Maps a `UseTree` contained in this import back to its AST node.
     pub fn use_tree_to_ast(
         &self,
@@ -870,7 +870,7 @@ macro_rules! impl_froms {
 impl ModItem {
     pub fn as_assoc_item(&self) -> Option<AssocItem> {
         match self {
-            ModItem::Import(_)
+            ModItem::Use(_)
             | ModItem::ExternCrate(_)
             | ModItem::ExternBlock(_)
             | ModItem::Struct(_)
@@ -892,7 +892,7 @@ impl ModItem {
 
     pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
         match self {
-            ModItem::Import(it) => tree[it.index].ast_id().upcast(),
+            ModItem::Use(it) => tree[it.index].ast_id().upcast(),
             ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(),
             ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(),
             ModItem::Function(it) => tree[it.index].ast_id().upcast(),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 46633667ed3..7b898e62dba 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -502,13 +502,13 @@ impl<'a> Ctx<'a> {
         Some(id(self.data().impls.alloc(res)))
     }
 
-    fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
+    fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
         let visibility = self.lower_visibility(use_item);
         let ast_id = self.source_ast_id_map.ast_id(use_item);
         let (use_tree, _) = lower_use_tree(self.db, self.hygiene(), use_item.use_tree()?)?;
 
-        let res = Import { visibility, ast_id, use_tree };
-        Some(id(self.data().imports.alloc(res)))
+        let res = Use { visibility, ast_id, use_tree };
+        Some(id(self.data().uses.alloc(res)))
     }
 
     fn lower_extern_crate(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index ddf668d20b0..da30830fe45 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -198,8 +198,8 @@ impl Printer<'_> {
         self.print_attrs_of(item);
 
         match item {
-            ModItem::Import(it) => {
-                let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
+            ModItem::Use(it) => {
+                let Use { visibility, use_tree, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "use ");
                 self.print_use_tree(use_tree);
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 1e74e2dfcb4..1901db8a0f9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -88,8 +88,8 @@ use crate::{
     builtin_type::BuiltinType,
     data::adt::VariantData,
     item_tree::{
-        Const, Enum, ExternCrate, Function, Impl, Import, ItemTreeId, ItemTreeNode, MacroDef,
-        MacroRules, Static, Struct, Trait, TraitAlias, TypeAlias, Union,
+        Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules,
+        Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use,
     },
 };
 
@@ -121,6 +121,12 @@ impl From<CrateRootModuleId> for ModuleDefId {
     }
 }
 
+impl From<CrateId> for CrateRootModuleId {
+    fn from(krate: CrateId) -> Self {
+        CrateRootModuleId { krate }
+    }
+}
+
 impl TryFrom<ModuleId> for CrateRootModuleId {
     type Error = ();
 
@@ -318,9 +324,9 @@ type ImplLoc = ItemLoc<Impl>;
 impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
-pub struct ImportId(salsa::InternId);
-type ImportLoc = ItemLoc<Import>;
-impl_intern!(ImportId, ImportLoc, intern_import, lookup_intern_import);
+pub struct UseId(salsa::InternId);
+type UseLoc = ItemLoc<Use>;
+impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ExternCrateId(salsa::InternId);
@@ -836,6 +842,7 @@ pub enum AttrDefId {
     GenericParamId(GenericParamId),
     ExternBlockId(ExternBlockId),
     ExternCrateId(ExternCrateId),
+    UseId(UseId),
 }
 
 impl_from!(
@@ -1073,6 +1080,7 @@ impl AttrDefId {
             }
             AttrDefId::MacroId(it) => it.module(db).krate,
             AttrDefId::ExternCrateId(it) => it.lookup(db).container.krate,
+            AttrDefId::UseId(it) => it.lookup(db).container.krate,
         }
     }
 }
@@ -1083,7 +1091,7 @@ pub trait AsMacroCall {
         &self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+        resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
     ) -> Option<MacroCallId> {
         self.as_call_id_with_errors(db, krate, resolver).ok()?.value
     }
@@ -1092,7 +1100,7 @@ pub trait AsMacroCall {
         &self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+        resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
     ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
 }
 
@@ -1101,7 +1109,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
         &self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
-        resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+        resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
     ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
         let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
@@ -1112,12 +1120,13 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
             return Ok(ExpandResult::only_err(ExpandError::other("malformed macro invocation")));
         };
 
-        macro_call_as_call_id_(
+        macro_call_as_call_id_with_eager(
             db,
             &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
             expands_to,
             krate,
             resolver,
+            resolver,
         )
     }
 }
@@ -1140,33 +1149,39 @@ fn macro_call_as_call_id(
     call: &AstIdWithPath<ast::MacroCall>,
     expand_to: ExpandTo,
     krate: CrateId,
-    resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+    resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
 ) -> Result<Option<MacroCallId>, UnresolvedMacro> {
-    macro_call_as_call_id_(db, call, expand_to, krate, resolver).map(|res| res.value)
+    macro_call_as_call_id_with_eager(db, call, expand_to, krate, resolver, resolver)
+        .map(|res| res.value)
 }
 
-fn macro_call_as_call_id_(
+fn macro_call_as_call_id_with_eager(
     db: &dyn ExpandDatabase,
     call: &AstIdWithPath<ast::MacroCall>,
     expand_to: ExpandTo,
     krate: CrateId,
-    resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
+    resolver: impl FnOnce(path::ModPath) -> Option<MacroDefId>,
+    eager_resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
 ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
     let def =
         resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
 
-    let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
-        let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db));
-        expand_eager_macro_input(db, krate, macro_call, def, &resolver)?
-    } else {
-        ExpandResult {
+    let res = match def.kind {
+        MacroDefKind::BuiltInEager(..) => {
+            let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db));
+            expand_eager_macro_input(db, krate, macro_call, def, &|path| {
+                eager_resolver(path).filter(MacroDefId::is_fn_like)
+            })
+        }
+        _ if def.is_fn_like() => ExpandResult {
             value: Some(def.as_lazy_macro(
                 db,
                 krate,
                 MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
             )),
             err: None,
-        }
+        },
+        _ => return Err(UnresolvedMacro { path: call.path.clone() }),
     };
     Ok(res)
 }
@@ -1251,6 +1266,7 @@ fn derive_macro_as_call_id(
     resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
 ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
     let (macro_id, def_id) = resolver(item_attr.path.clone())
+        .filter(|(_, def_id)| def_id.is_derive())
         .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
     let call_id = def_id.as_lazy_macro(
         db.upcast(),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index b232651db96..1250cbb742c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -238,7 +238,7 @@ fn main() {
     /* error: expected expression */;
     /* error: expected expression, expected COMMA */;
     /* error: expected expression */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(), ::core::fmt::Display::fmt), ]);
-    /* error: expected expression, expected R_PAREN */;
+    /* error: expected expression, expected expression */;
     ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]);
 }
 "##]],
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index b26f9867580..2170cadcf83 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -100,6 +100,30 @@ fn#19 main#20(#21)#21 {#22
 }
 
 #[test]
+fn eager_expands_with_unresolved_within() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main(foo: ()) {
+    format_args!("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar")
+}
+"#,
+        expect![[r##"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main(foo: ()) {
+    /* error: unresolved macro identity */::core::fmt::Arguments::new_v1(&["", " ", " ", ], &[::core::fmt::ArgumentV1::new(&(::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(0), ::core::fmt::Display::fmt), ])), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(foo), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(identity!(10)), ::core::fmt::Display::fmt), ])
+}
+"##]],
+    );
+}
+
+#[test]
 fn token_mapping_eager() {
     check(
         r#"
@@ -849,6 +873,37 @@ fn foo() {
 }
 
 #[test]
+fn test_type_path_is_transcribed_as_expr_path() {
+    check(
+        r#"
+macro_rules! m {
+    ($p:path) => { let $p; }
+}
+fn test() {
+    m!(S)
+    m!(S<i32>)
+    m!(S<S<i32>>)
+    m!(S<{ module::CONST < 42 }>)
+}
+"#,
+        expect![[r#"
+macro_rules! m {
+    ($p:path) => { let $p; }
+}
+fn test() {
+    let S;
+    let S:: <i32> ;
+    let S:: <S:: <i32>> ;
+    let S:: < {
+        module::CONST<42
+    }
+    > ;
+}
+"#]],
+    );
+}
+
+#[test]
 fn test_expr() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index c048716d740..eef54fc492e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -38,7 +38,7 @@ use crate::{
         self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
         MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
     },
-    macro_call_as_call_id, macro_id_to_def_id,
+    macro_call_as_call_id, macro_call_as_call_id_with_eager, macro_id_to_def_id,
     nameres::{
         diagnostics::DefDiagnostic,
         mod_resolution::ModDir,
@@ -52,10 +52,10 @@ use crate::{
     tt,
     visibility::{RawVisibility, Visibility},
     AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
-    ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, ImportLoc, Intern,
-    ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
-    MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc,
-    TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro,
+    ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
+    LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc,
+    ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc,
+    TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseLoc,
 };
 
 static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -146,7 +146,7 @@ impl PartialResolvedImport {
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 enum ImportSource {
-    Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
+    Use { id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree> },
     ExternCrate(ItemTreeId<item_tree::ExternCrate>),
 }
 
@@ -166,7 +166,7 @@ impl Import {
         db: &dyn DefDatabase,
         krate: CrateId,
         tree: &ItemTree,
-        id: ItemTreeId<item_tree::Import>,
+        id: ItemTreeId<item_tree::Use>,
         mut cb: impl FnMut(Self),
     ) {
         let it = &tree[id.value];
@@ -181,7 +181,7 @@ impl Import {
                 kind,
                 is_prelude,
                 is_macro_use: false,
-                source: ImportSource::Import { id, use_tree: idx },
+                source: ImportSource::Use { id, use_tree: idx },
             });
         });
     }
@@ -1474,7 +1474,7 @@ impl DefCollector<'_> {
         }
 
         for directive in &self.unresolved_imports {
-            if let ImportSource::Import { id: import, use_tree } = directive.import.source {
+            if let ImportSource::Use { id: import, use_tree } = directive.import.source {
                 if matches!(
                     (directive.import.path.segments().first(), &directive.import.path.kind),
                     (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
@@ -1576,12 +1576,10 @@ impl ModCollector<'_, '_> {
 
             match item {
                 ModItem::Mod(m) => self.collect_module(m, &attrs),
-                ModItem::Import(import_id) => {
-                    let _import_id = ImportLoc {
-                        container: module,
-                        id: ItemTreeId::new(self.tree_id, import_id),
-                    }
-                    .intern(db);
+                ModItem::Use(import_id) => {
+                    let _import_id =
+                        UseLoc { container: module, id: ItemTreeId::new(self.tree_id, import_id) }
+                            .intern(db);
                     Import::from_use(
                         db,
                         krate,
@@ -2187,7 +2185,7 @@ impl ModCollector<'_, '_> {
         // scopes without eager expansion.
 
         // Case 1: try to resolve macro calls with single-segment name and expand macro_rules
-        if let Ok(res) = macro_call_as_call_id(
+        if let Ok(res) = macro_call_as_call_id_with_eager(
             db.upcast(),
             &ast_id,
             mac.expand_to,
@@ -2210,19 +2208,34 @@ impl ModCollector<'_, '_> {
                         .map(|it| macro_id_to_def_id(self.def_collector.db, it))
                 })
             },
-        ) {
-            // Legacy macros need to be expanded immediately, so that any macros they produce
-            // are in scope.
-            if let Some(val) = res {
-                self.def_collector.collect_macro_expansion(
+            |path| {
+                let resolved_res = self.def_collector.def_map.resolve_path_fp_with_macro(
+                    db,
+                    ResolveMode::Other,
                     self.module_id,
-                    val,
-                    self.macro_depth + 1,
-                    container,
+                    &path,
+                    BuiltinShadowMode::Module,
+                    Some(MacroSubNs::Bang),
                 );
-            }
+                resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(db, it))
+            },
+        ) {
+            // FIXME: if there were errors, this mightve been in the eager expansion from an
+            // unresolved macro, so we need to push this into late macro resolution. see fixme above
+            if res.err.is_none() {
+                // Legacy macros need to be expanded immediately, so that any macros they produce
+                // are in scope.
+                if let Some(val) = res.value {
+                    self.def_collector.collect_macro_expansion(
+                        self.module_id,
+                        val,
+                        self.macro_depth + 1,
+                        container,
+                    );
+                }
 
-            return;
+                return;
+            }
         }
 
         // Case 2: resolve in module scope, expand during name resolution.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index e82e97b628e..9cffb3c9f37 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -19,7 +19,7 @@ pub enum DefDiagnosticKind {
 
     UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
 
-    UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
+    UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
 
     UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
 
@@ -70,7 +70,7 @@ impl DefDiagnostic {
 
     pub(super) fn unresolved_import(
         container: LocalModuleId,
-        id: ItemTreeId<item_tree::Import>,
+        id: ItemTreeId<item_tree::Use>,
         index: Idx<ast::UseTree>,
     ) -> Self {
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 4931c36bbca..40d3a16540d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -213,17 +213,17 @@ pub type Ty = ();
 
             for (_, res) in module_data.scope.resolutions() {
                 match res.values.or(res.types).unwrap().0 {
-                    ModuleDefId::FunctionId(f) => drop(db.function_data(f)),
+                    ModuleDefId::FunctionId(f) => _ = db.function_data(f),
                     ModuleDefId::AdtId(adt) => match adt {
-                        AdtId::StructId(it) => drop(db.struct_data(it)),
-                        AdtId::UnionId(it) => drop(db.union_data(it)),
-                        AdtId::EnumId(it) => drop(db.enum_data(it)),
+                        AdtId::StructId(it) => _ = db.struct_data(it),
+                        AdtId::UnionId(it) => _ = db.union_data(it),
+                        AdtId::EnumId(it) => _ = db.enum_data(it),
                     },
-                    ModuleDefId::ConstId(it) => drop(db.const_data(it)),
-                    ModuleDefId::StaticId(it) => drop(db.static_data(it)),
-                    ModuleDefId::TraitId(it) => drop(db.trait_data(it)),
-                    ModuleDefId::TraitAliasId(it) => drop(db.trait_alias_data(it)),
-                    ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)),
+                    ModuleDefId::ConstId(it) => _ = db.const_data(it),
+                    ModuleDefId::StaticId(it) => _ = db.static_data(it),
+                    ModuleDefId::TraitId(it) => _ = db.trait_data(it),
+                    ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_data(it),
+                    ModuleDefId::TypeAliasId(it) => _ = db.type_alias_data(it),
                     ModuleDefId::EnumVariantId(_)
                     | ModuleDefId::ModuleId(_)
                     | ModuleDefId::MacroId(_)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 10f5702845e..b112c1070d4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -25,7 +25,7 @@ use crate::{
     EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
     HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId,
     MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId,
-    TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, VariantId,
+    TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId,
 };
 
 #[derive(Debug, Clone)]
@@ -1024,6 +1024,12 @@ impl HasResolver for ExternCrateId {
     }
 }
 
+impl HasResolver for UseId {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+        self.lookup(db).container.resolver(db)
+    }
+}
+
 impl HasResolver for TypeOwnerId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index 309c0930d1a..5292a5fa1b1 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -430,14 +430,13 @@ fn macro_arg_node(
     let loc = db.lookup_intern_macro_call(id);
     let arg = if let MacroDefKind::BuiltInEager(..) = loc.def.kind {
         let res = if let Some(EagerCallInfo { arg, .. }) = loc.eager.as_deref() {
-            Some(mbe::token_tree_to_syntax_node(&arg.0, mbe::TopEntryPoint::Expr).0)
+            Some(mbe::token_tree_to_syntax_node(&arg.0, mbe::TopEntryPoint::MacroEagerInput).0)
         } else {
             loc.kind
                 .arg(db)
                 .and_then(|arg| ast::TokenTree::cast(arg.value))
-                .map(|tt| tt.reparse_as_expr().to_syntax())
+                .map(|tt| tt.reparse_as_comma_separated_expr().to_syntax())
         };
-
         match res {
             Some(res) if res.errors().is_empty() => res.syntax_node(),
             Some(res) => {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
index 876813eab5d..4110f284759 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
@@ -19,7 +19,7 @@
 //!
 //! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
 use base_db::CrateId;
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::{ted, Parse, SyntaxNode, TextRange, TextSize, WalkEvent};
 use triomphe::Arc;
 
@@ -29,7 +29,7 @@ use crate::{
     hygiene::Hygiene,
     mod_path::ModPath,
     EagerCallInfo, ExpandError, ExpandResult, ExpandTo, InFile, MacroCallId, MacroCallKind,
-    MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro,
+    MacroCallLoc, MacroDefId, MacroDefKind,
 };
 
 pub fn expand_eager_macro_input(
@@ -38,7 +38,7 @@ pub fn expand_eager_macro_input(
     macro_call: InFile<ast::MacroCall>,
     def: MacroDefId,
     resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
-) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
+) -> ExpandResult<Option<MacroCallId>> {
     let ast_map = db.ast_id_map(macro_call.file_id);
     // the expansion which the ast id map is built upon has no whitespace, so the offsets are wrong as macro_call is from the token tree that has whitespace!
     let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
@@ -71,41 +71,46 @@ pub fn expand_eager_macro_input(
             InFile::new(arg_id.as_file(), arg_exp.syntax_node()),
             krate,
             resolver,
-        )?
+        )
     };
     let err = parse_err.or(err);
 
     let Some((expanded_eager_input, mapping)) = expanded_eager_input else {
-        return Ok(ExpandResult { value: None, err });
+        return ExpandResult { value: None, err };
     };
 
-    let og_tmap = mbe::syntax_node_to_token_map(
-        macro_call.value.token_tree().expect("macro_arg_text succeeded").syntax(),
-    );
-
     let (mut subtree, expanded_eager_input_token_map) =
         mbe::syntax_node_to_token_tree(&expanded_eager_input);
 
-    // The tokenmap and ids of subtree point into the expanded syntax node, but that is inaccessible from the outside
-    // so we need to remap them to the original input of the eager macro.
-    subtree.visit_ids(&|id| {
-        // Note: we discard all token ids of braces and the like here, but that's not too bad and only a temporary fix
+    let og_tmap = if let Some(tt) = macro_call.value.token_tree() {
+        let mut ids_used = FxHashSet::default();
+        let mut og_tmap = mbe::syntax_node_to_token_map(tt.syntax());
+        // The tokenmap and ids of subtree point into the expanded syntax node, but that is inaccessible from the outside
+        // so we need to remap them to the original input of the eager macro.
+        subtree.visit_ids(&mut |id| {
+            // Note: we discard all token ids of braces and the like here, but that's not too bad and only a temporary fix
 
-        if let Some(range) =
-            expanded_eager_input_token_map.first_range_by_token(id, syntax::SyntaxKind::TOMBSTONE)
-        {
-            // remap from expanded eager input to eager input expansion
-            if let Some(og_range) = mapping.get(&range) {
-                // remap from eager input expansion to original eager input
-                if let Some(&og_range) = ws_mapping.get(og_range) {
-                    if let Some(og_token) = og_tmap.token_by_range(og_range) {
-                        return og_token;
+            if let Some(range) = expanded_eager_input_token_map
+                .first_range_by_token(id, syntax::SyntaxKind::TOMBSTONE)
+            {
+                // remap from expanded eager input to eager input expansion
+                if let Some(og_range) = mapping.get(&range) {
+                    // remap from eager input expansion to original eager input
+                    if let Some(&og_range) = ws_mapping.get(og_range) {
+                        if let Some(og_token) = og_tmap.token_by_range(og_range) {
+                            ids_used.insert(og_token);
+                            return og_token;
+                        }
                     }
                 }
             }
-        }
-        tt::TokenId::UNSPECIFIED
-    });
+            tt::TokenId::UNSPECIFIED
+        });
+        og_tmap.filter(|id| ids_used.contains(&id));
+        og_tmap
+    } else {
+        Default::default()
+    };
     subtree.delimiter = crate::tt::Delimiter::unspecified();
 
     let loc = MacroCallLoc {
@@ -119,7 +124,7 @@ pub fn expand_eager_macro_input(
         kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
     };
 
-    Ok(ExpandResult { value: Some(db.intern_macro_call(loc)), err })
+    ExpandResult { value: Some(db.intern_macro_call(loc)), err }
 }
 
 fn lazy_expand(
@@ -145,13 +150,13 @@ fn eager_macro_recur(
     curr: InFile<SyntaxNode>,
     krate: CrateId,
     macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
-) -> Result<ExpandResult<Option<(SyntaxNode, FxHashMap<TextRange, TextRange>)>>, UnresolvedMacro> {
+) -> ExpandResult<Option<(SyntaxNode, FxHashMap<TextRange, TextRange>)>> {
     let original = curr.value.clone_for_update();
     let mut mapping = FxHashMap::default();
 
     let mut replacements = Vec::new();
 
-    // Note: We only report a single error inside of eager expansions
+    // FIXME: We only report a single error inside of eager expansions
     let mut error = None;
     let mut offset = 0i32;
     let apply_offset = |it: TextSize, offset: i32| {
@@ -182,7 +187,14 @@ fn eager_macro_recur(
             }
         };
         let def = match call.path().and_then(|path| ModPath::from_src(db, path, hygiene)) {
-            Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?,
+            Some(path) => match macro_resolver(path.clone()) {
+                Some(def) => def,
+                None => {
+                    error =
+                        Some(ExpandError::other(format!("unresolved macro {}", path.display(db))));
+                    continue;
+                }
+            },
             None => {
                 error = Some(ExpandError::other("malformed macro invocation"));
                 continue;
@@ -190,32 +202,31 @@ fn eager_macro_recur(
         };
         let ExpandResult { value, err } = match def.kind {
             MacroDefKind::BuiltInEager(..) => {
-                let ExpandResult { value, err } = match expand_eager_macro_input(
+                let ExpandResult { value, err } = expand_eager_macro_input(
                     db,
                     krate,
                     curr.with_value(call.clone()),
                     def,
                     macro_resolver,
-                ) {
-                    Ok(it) => it,
-                    Err(err) => return Err(err),
-                };
+                );
                 match value {
                     Some(call_id) => {
                         let ExpandResult { value, err: err2 } =
                             db.parse_macro_expansion(call_id.as_macro_file());
 
-                        let call_tt_start =
-                            call.token_tree().unwrap().syntax().text_range().start();
-                        let call_start = apply_offset(call.syntax().text_range().start(), offset);
-                        if let Some((_, arg_map, _)) = db.macro_arg(call_id).value.as_deref() {
-                            mapping.extend(arg_map.entries().filter_map(|(tid, range)| {
-                                value
-                                    .1
-                                    .first_range_by_token(tid, syntax::SyntaxKind::TOMBSTONE)
-                                    .map(|r| (r + call_start, range + call_tt_start))
-                            }));
-                        };
+                        if let Some(tt) = call.token_tree() {
+                            let call_tt_start = tt.syntax().text_range().start();
+                            let call_start =
+                                apply_offset(call.syntax().text_range().start(), offset);
+                            if let Some((_, arg_map, _)) = db.macro_arg(call_id).value.as_deref() {
+                                mapping.extend(arg_map.entries().filter_map(|(tid, range)| {
+                                    value
+                                        .1
+                                        .first_range_by_token(tid, syntax::SyntaxKind::TOMBSTONE)
+                                        .map(|r| (r + call_start, range + call_tt_start))
+                                }));
+                            }
+                        }
 
                         ExpandResult {
                             value: Some(value.0.syntax_node().clone_for_update()),
@@ -247,25 +258,27 @@ fn eager_macro_recur(
                     parse.as_ref().map(|it| it.syntax_node()),
                     krate,
                     macro_resolver,
-                )?;
+                );
                 let err = err.or(error);
 
-                let call_tt_start = call.token_tree().unwrap().syntax().text_range().start();
-                let call_start = apply_offset(call.syntax().text_range().start(), offset);
-                if let Some((_tt, arg_map, _)) = parse
-                    .file_id
-                    .macro_file()
-                    .and_then(|id| db.macro_arg(id.macro_call_id).value)
-                    .as_deref()
-                {
-                    mapping.extend(arg_map.entries().filter_map(|(tid, range)| {
-                        tm.first_range_by_token(
-                            decl_mac.as_ref().map(|it| it.map_id_down(tid)).unwrap_or(tid),
-                            syntax::SyntaxKind::TOMBSTONE,
-                        )
-                        .map(|r| (r + call_start, range + call_tt_start))
-                    }));
-                };
+                if let Some(tt) = call.token_tree() {
+                    let call_tt_start = tt.syntax().text_range().start();
+                    let call_start = apply_offset(call.syntax().text_range().start(), offset);
+                    if let Some((_tt, arg_map, _)) = parse
+                        .file_id
+                        .macro_file()
+                        .and_then(|id| db.macro_arg(id.macro_call_id).value)
+                        .as_deref()
+                    {
+                        mapping.extend(arg_map.entries().filter_map(|(tid, range)| {
+                            tm.first_range_by_token(
+                                decl_mac.as_ref().map(|it| it.map_id_down(tid)).unwrap_or(tid),
+                                syntax::SyntaxKind::TOMBSTONE,
+                            )
+                            .map(|r| (r + call_start, range + call_tt_start))
+                        }));
+                    }
+                }
                 // FIXME: Do we need to re-use _m here?
                 ExpandResult { value: value.map(|(n, _m)| n), err }
             }
@@ -275,7 +288,7 @@ fn eager_macro_recur(
         }
         // check if the whole original syntax is replaced
         if call.syntax() == &original {
-            return Ok(ExpandResult { value: value.zip(Some(mapping)), err: error });
+            return ExpandResult { value: value.zip(Some(mapping)), err: error };
         }
 
         if let Some(insert) = value {
@@ -286,5 +299,5 @@ fn eager_macro_recur(
     }
 
     replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
-    Ok(ExpandResult { value: Some((original, mapping)), err: error })
+    ExpandResult { value: Some((original, mapping)), err: error }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index 54e74d50c87..ade4a592893 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -173,7 +173,7 @@ fn make_hygiene_info(
     db: &dyn ExpandDatabase,
     macro_file: MacroFile,
     loc: &MacroCallLoc,
-) -> Option<HygieneInfo> {
+) -> HygieneInfo {
     let def = loc.def.ast_id().left().and_then(|id| {
         let def_tt = match id.to_node(db) {
             ast::Macro::MacroRules(mac) => mac.token_tree()?,
@@ -204,7 +204,7 @@ fn make_hygiene_info(
         ))
     });
 
-    Some(HygieneInfo {
+    HygieneInfo {
         file: macro_file,
         attr_input_or_mac_def_start: attr_input_or_mac_def
             .map(|it| it.map(|tt| tt.syntax().text_range().start())),
@@ -212,7 +212,7 @@ fn make_hygiene_info(
         macro_arg,
         macro_def,
         exp_map,
-    })
+    }
 }
 
 impl HygieneFrame {
@@ -221,8 +221,7 @@ impl HygieneFrame {
             None => (None, None, false),
             Some(macro_file) => {
                 let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
-                let info =
-                    make_hygiene_info(db, macro_file, &loc).map(|info| (loc.kind.file_id(), info));
+                let info = Some((make_hygiene_info(db, macro_file, &loc), loc.kind.file_id()));
                 match loc.def.kind {
                     MacroDefKind::Declarative(_) => {
                         (info, Some(loc.def.krate), loc.def.local_inner)
@@ -236,17 +235,14 @@ impl HygieneFrame {
             }
         };
 
-        let (calling_file, info) = match info {
-            None => {
-                return HygieneFrame {
-                    expansion: None,
-                    local_inner,
-                    krate,
-                    call_site: None,
-                    def_site: None,
-                };
+        let Some((info, calling_file)) = info else {
+            return HygieneFrame {
+                expansion: None,
+                local_inner,
+                krate,
+                call_site: None,
+                def_site: None,
             }
-            Some(it) => it,
         };
 
         let def_site = info.attr_input_or_mac_def_start.map(|it| db.hygiene_frame(it.file_id));
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 9ed6c31ddde..1f1e20f49e3 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -415,6 +415,24 @@ impl MacroDefId {
         )
     }
 
+    pub fn is_derive(&self) -> bool {
+        matches!(
+            self.kind,
+            MacroDefKind::BuiltInDerive(..)
+                | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)
+        )
+    }
+
+    pub fn is_fn_like(&self) -> bool {
+        matches!(
+            self.kind,
+            MacroDefKind::BuiltIn(..)
+                | MacroDefKind::ProcMacro(_, ProcMacroKind::FuncLike, _)
+                | MacroDefKind::BuiltInEager(..)
+                | MacroDefKind::Declarative(..)
+        )
+    }
+
     pub fn is_attribute_derive(&self) -> bool {
         matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive())
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 98ebe557245..666955fa1c3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -1187,6 +1187,25 @@ fn pattern_matching_ergonomics() {
 }
 
 #[test]
+fn destructing_assignment() {
+    check_number(
+        r#"
+    //- minicore: add
+    const fn f(i: &mut u8) -> &mut u8 {
+        *i += 1;
+        i
+    }
+    const GOAL: u8 = {
+        let mut i = 4;
+        _ = f(&mut i);
+        i
+    };
+        "#,
+        5,
+    );
+}
+
+#[test]
 fn let_else() {
     check_number(
         r#"
@@ -1428,14 +1447,14 @@ fn builtin_derive_macro() {
     #[derive(Clone)]
     struct Y {
         field1: i32,
-        field2: u8,
+        field2: ((i32, u8), i64),
     }
 
     const GOAL: u8 = {
-        let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8);
+        let x = X(2, Z::Foo(Y { field1: 4, field2: ((32, 5), 12) }), 8);
         let x = x.clone();
         let Z::Foo(t) = x.1;
-        t.field2
+        t.field2.0 .1
     };
     "#,
         5,
@@ -1633,6 +1652,34 @@ const GOAL: i32 = {
 }
 
 #[test]
+fn closure_capture_unsized_type() {
+    check_number(
+        r#"
+    //- minicore: fn, copy, slice, index, coerce_unsized
+    fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty {
+        let c = || &*x;
+        c()
+    }
+
+    trait A {
+        type Ty;
+    }
+
+    impl A for i32 {
+        type Ty = [u8];
+    }
+
+    const GOAL: u8 = {
+        let k: &[u8] = &[1, 2, 3];
+        let k = f::<i32>(k);
+        k[0] + k[1] + k[2]
+    }
+    "#,
+        6,
+    );
+}
+
+#[test]
 fn closure_and_impl_fn() {
     check_number(
         r#"
@@ -1718,6 +1765,24 @@ fn function_pointer_in_constants() {
 }
 
 #[test]
+fn function_pointer_and_niche_optimization() {
+    check_number(
+        r#"
+    //- minicore: option
+    const GOAL: i32 = {
+        let f: fn(i32) -> i32 = |x| x + 2;
+        let init = Some(f);
+        match init {
+            Some(t) => t(3),
+            None => 222,
+        }
+    };
+        "#,
+        5,
+    );
+}
+
+#[test]
 fn function_pointer() {
     check_number(
         r#"
@@ -2331,11 +2396,14 @@ fn const_loop() {
 fn const_transfer_memory() {
     check_number(
         r#"
-    const A1: &i32 = &2;
-    const A2: &i32 = &5;
-    const GOAL: i32 = *A1 + *A2;
+    //- minicore: slice, index, coerce_unsized
+    const A1: &i32 = &1;
+    const A2: &i32 = &10;
+    const A3: [&i32; 3] = [&1, &2, &100];
+    const A4: (i32, &i32) = (1, &1000);
+    const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1;
     "#,
-        7,
+        1111,
     );
 }
 
@@ -2521,12 +2589,16 @@ fn const_trait_assoc() {
     );
     check_number(
         r#"
-    //- minicore: size_of
+    //- minicore: size_of, fn
     //- /a/lib.rs crate:a
     use core::mem::size_of;
     pub struct S<T>(T);
     impl<T> S<T> {
-        pub const X: usize = core::mem::size_of::<T>();
+        pub const X: usize = {
+            let k: T;
+            let f = || core::mem::size_of::<T>();
+            f()
+        };
     }
     //- /main.rs crate:main deps:a
     use a::{S};
@@ -2602,9 +2674,9 @@ fn exec_limits() {
         }
         sum
     }
-    const GOAL: i32 = f(10000);
+    const GOAL: i32 = f(1000);
     "#,
-        10000 * 10000,
+        1000 * 1000,
     );
 }
 
@@ -2651,7 +2723,7 @@ fn unsized_field() {
     //- minicore: coerce_unsized, index, slice, transmute
     use core::mem::transmute;
 
-    struct Slice([u8]);
+    struct Slice([usize]);
     struct Slice2(Slice);
 
     impl Slice2 {
@@ -2659,19 +2731,19 @@ fn unsized_field() {
             &self.0
         }
 
-        fn as_bytes(&self) -> &[u8] {
+        fn as_bytes(&self) -> &[usize] {
             &self.as_inner().0
         }
     }
 
-    const GOAL: u8 = unsafe {
-        let x: &[u8] = &[1, 2, 3];
+    const GOAL: usize = unsafe {
+        let x: &[usize] = &[1, 2, 3];
         let x: &Slice2 = transmute(x);
         let x = x.as_bytes();
-        x[0] + x[1] + x[2]
+        x[0] + x[1] + x[2] + x.len() * 100
     };
         "#,
-        6,
+        306,
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
index 9253e31d77b..2855f789001 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -252,6 +252,28 @@ fn wrapping_add() {
 }
 
 #[test]
+fn ptr_offset_from() {
+    check_number(
+        r#"
+        //- minicore: index, slice, coerce_unsized
+        extern "rust-intrinsic" {
+            pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
+            pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize;
+        }
+
+        const GOAL: isize = {
+            let x = [1, 2, 3, 4, 5i32];
+            let r1 = -ptr_offset_from(&x[0], &x[4]);
+            let r2 = ptr_offset_from(&x[3], &x[1]);
+            let r3 = ptr_offset_from_unsigned(&x[3], &x[0]) as isize;
+            r3 * 100 + r2 * 10 + r1
+        };
+        "#,
+        324,
+    );
+}
+
+#[test]
 fn saturating() {
     check_number(
         r#"
@@ -438,6 +460,8 @@ fn atomic() {
             pub fn atomic_nand_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
             pub fn atomic_or_release<T: Copy>(dst: *mut T, src: T) -> T;
             pub fn atomic_xor_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
+            pub fn atomic_fence_seqcst();
+            pub fn atomic_singlethreadfence_acqrel();
         }
 
         fn should_not_reach() {
@@ -452,6 +476,7 @@ fn atomic() {
             if (30, true) != atomic_cxchg_release_seqcst(&mut y, 30, 40) {
                 should_not_reach();
             }
+            atomic_fence_seqcst();
             if (40, false) != atomic_cxchg_release_seqcst(&mut y, 30, 50) {
                 should_not_reach();
             }
@@ -459,6 +484,7 @@ fn atomic() {
                 should_not_reach();
             }
             let mut z = atomic_xsub_seqcst(&mut x, -200);
+            atomic_singlethreadfence_acqrel();
             atomic_xor_seqcst(&mut x, 1024);
             atomic_load_seqcst(&x) + z * 3 + atomic_load_seqcst(&y) * 2
         };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 5aaa2bcc7c2..a94a962c1f8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -176,6 +176,7 @@ impl<'a> DeclValidator<'a> {
                 AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
                 AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()),
                 AttrDefId::ExternCrateId(id) =>  Some(id.lookup(self.db.upcast()).container.into()),
+                AttrDefId::UseId(id) =>  Some(id.lookup(self.db.upcast()).container.into()),
                 // These warnings should not explore macro definitions at all
                 AttrDefId::MacroId(_) => None,
                 AttrDefId::AdtId(aid) => match aid {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 96787959e1f..1b4ee4613d6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -48,22 +48,15 @@ use crate::{
 };
 
 pub trait HirWrite: fmt::Write {
-    fn start_location_link(&mut self, location: ModuleDefId);
-    fn end_location_link(&mut self);
+    fn start_location_link(&mut self, _location: ModuleDefId) {}
+    fn end_location_link(&mut self) {}
 }
 
 // String will ignore link metadata
-impl HirWrite for String {
-    fn start_location_link(&mut self, _: ModuleDefId) {}
-
-    fn end_location_link(&mut self) {}
-}
+impl HirWrite for String {}
 
 // `core::Formatter` will ignore metadata
-impl HirWrite for fmt::Formatter<'_> {
-    fn start_location_link(&mut self, _: ModuleDefId) {}
-    fn end_location_link(&mut self) {}
-}
+impl HirWrite for fmt::Formatter<'_> {}
 
 pub struct HirFormatter<'a> {
     pub db: &'a dyn HirDatabase,
@@ -885,6 +878,13 @@ impl HirDisplay for Ty {
             TyKind::FnDef(def, parameters) => {
                 let def = from_chalk(db, *def);
                 let sig = db.callable_item_signature(def).substitute(Interner, parameters);
+
+                if f.display_target.is_source_code() {
+                    // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
+                    // function pointer type.
+                    return sig.hir_fmt(f);
+                }
+
                 f.start_location_link(def.into());
                 match def {
                     CallableDefId::FunctionId(ff) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 0a617dae7d4..b4915dbf0f9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -13,6 +13,15 @@
 //! to certain types. To record this, we use the union-find implementation from
 //! the `ena` crate, which is extracted from rustc.
 
+mod cast;
+pub(crate) mod closure;
+mod coerce;
+mod expr;
+mod mutability;
+mod pat;
+mod path;
+pub(crate) mod unify;
+
 use std::{convert::identity, ops::Index};
 
 use chalk_ir::{
@@ -60,15 +69,8 @@ pub use coerce::could_coerce;
 #[allow(unreachable_pub)]
 pub use unify::could_unify;
 
-pub(crate) use self::closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
-
-pub(crate) mod unify;
-mod path;
-mod expr;
-mod pat;
-mod coerce;
-pub(crate) mod closure;
-mod mutability;
+use cast::CastCheck;
+pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
 
 /// The entry point of type inference.
 pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
@@ -508,6 +510,8 @@ pub(crate) struct InferenceContext<'a> {
     diverges: Diverges,
     breakables: Vec<BreakableContext>,
 
+    deferred_cast_checks: Vec<CastCheck>,
+
     // fields related to closure capture
     current_captures: Vec<CapturedItemWithoutTy>,
     current_closure: Option<ClosureId>,
@@ -582,7 +586,8 @@ impl<'a> InferenceContext<'a> {
             resolver,
             diverges: Diverges::Maybe,
             breakables: Vec::new(),
-            current_captures: vec![],
+            deferred_cast_checks: Vec::new(),
+            current_captures: Vec::new(),
             current_closure: None,
             deferred_closures: FxHashMap::default(),
             closure_dependencies: FxHashMap::default(),
@@ -594,7 +599,7 @@ impl<'a> InferenceContext<'a> {
     // used this function for another workaround, mention it here. If you really need this function and believe that
     // there is no problem in it being `pub(crate)`, remove this comment.
     pub(crate) fn resolve_all(self) -> InferenceResult {
-        let InferenceContext { mut table, mut result, .. } = self;
+        let InferenceContext { mut table, mut result, deferred_cast_checks, .. } = self;
         // Destructure every single field so whenever new fields are added to `InferenceResult` we
         // don't forget to handle them here.
         let InferenceResult {
@@ -622,6 +627,13 @@ impl<'a> InferenceContext<'a> {
 
         table.fallback_if_possible();
 
+        // Comment from rustc:
+        // Even though coercion casts provide type hints, we check casts after fallback for
+        // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+        for cast in deferred_cast_checks {
+            cast.check(&mut table);
+        }
+
         // FIXME resolve obligations as well (use Guidance if necessary)
         table.resolve_obligations_as_possible();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
new file mode 100644
index 00000000000..9e1c74b16fa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
@@ -0,0 +1,46 @@
+//! Type cast logic. Basically coercion + additional casts.
+
+use crate::{infer::unify::InferenceTable, Interner, Ty, TyExt, TyKind};
+
+#[derive(Clone, Debug)]
+pub(super) struct CastCheck {
+    expr_ty: Ty,
+    cast_ty: Ty,
+}
+
+impl CastCheck {
+    pub(super) fn new(expr_ty: Ty, cast_ty: Ty) -> Self {
+        Self { expr_ty, cast_ty }
+    }
+
+    pub(super) fn check(self, table: &mut InferenceTable<'_>) {
+        // FIXME: This function currently only implements the bits that influence the type
+        // inference. We should return the adjustments on success and report diagnostics on error.
+        let expr_ty = table.resolve_ty_shallow(&self.expr_ty);
+        let cast_ty = table.resolve_ty_shallow(&self.cast_ty);
+
+        if expr_ty.contains_unknown() || cast_ty.contains_unknown() {
+            return;
+        }
+
+        if table.coerce(&expr_ty, &cast_ty).is_ok() {
+            return;
+        }
+
+        if check_ref_to_ptr_cast(expr_ty, cast_ty, table) {
+            // Note that this type of cast is actually split into a coercion to a
+            // pointer type and a cast:
+            // &[T; N] -> *[T; N] -> *T
+            return;
+        }
+
+        // FIXME: Check other kinds of non-coercion casts and report error if any?
+    }
+}
+
+fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool {
+    let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { return false; };
+    let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { return false; };
+    let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { return false; };
+    table.coerce(expr_elt_ty, cast_inner_ty).is_ok()
+}
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 972e5321a47..1781f6c58f1 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
@@ -488,10 +488,6 @@ impl InferenceContext<'_> {
                     self.consume_expr(*tail);
                 }
             }
-            Expr::While { condition, body, label: _ } => {
-                self.consume_expr(*condition);
-                self.consume_expr(*body);
-            }
             Expr::Call { callee, args, is_assignee_expr: _ } => {
                 self.consume_expr(*callee);
                 self.consume_exprs(args.iter().copied());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 72e6443beb7..8cbdae62526 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -46,8 +46,8 @@ use crate::{
 };
 
 use super::{
-    coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges, Expectation,
-    InferenceContext, InferenceDiagnostic, TypeMismatch,
+    cast::CastCheck, coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges,
+    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
 };
 
 impl InferenceContext<'_> {
@@ -198,19 +198,6 @@ impl InferenceContext<'_> {
                     None => self.result.standard_types.never.clone(),
                 }
             }
-            &Expr::While { condition, body, label } => {
-                self.with_breakable_ctx(BreakableKind::Loop, None, label, |this| {
-                    this.infer_expr(
-                        condition,
-                        &Expectation::HasType(this.result.standard_types.bool_.clone()),
-                    );
-                    this.infer_expr(body, &Expectation::HasType(TyBuilder::unit()));
-                });
-
-                // the body may not run, so it diverging doesn't mean we diverge
-                self.diverges = Diverges::Maybe;
-                TyBuilder::unit()
-            }
             Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => {
                 assert_eq!(args.len(), arg_types.len());
 
@@ -574,16 +561,8 @@ impl InferenceContext<'_> {
             }
             Expr::Cast { expr, type_ref } => {
                 let cast_ty = self.make_ty(type_ref);
-                // FIXME: propagate the "castable to" expectation
-                let inner_ty = self.infer_expr_no_expect(*expr);
-                match (inner_ty.kind(Interner), cast_ty.kind(Interner)) {
-                    (TyKind::Ref(_, _, inner), TyKind::Raw(_, cast)) => {
-                        // FIXME: record invalid cast diagnostic in case of mismatch
-                        self.unify(inner, cast);
-                    }
-                    // FIXME check the other kinds of cast...
-                    _ => (),
-                }
+                let expr_ty = self.infer_expr(*expr, &Expectation::Castable(cast_ty.clone()));
+                self.deferred_cast_checks.push(CastCheck::new(expr_ty, cast_ty.clone()));
                 cast_ty
             }
             Expr::Ref { expr, rawness, mutability } => {
@@ -1592,7 +1571,7 @@ impl InferenceContext<'_> {
         output: Ty,
         inputs: Vec<Ty>,
     ) -> Vec<Ty> {
-        if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
+        if let Some(expected_ty) = expected_output.only_has_type(&mut self.table) {
             self.table.fudge_inference(|table| {
                 if table.try_unify(&expected_ty, &output).is_ok() {
                     table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index f517bc2c09f..396ca0044ff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -69,10 +69,6 @@ impl InferenceContext<'_> {
                     self.infer_mut_expr(*tail, Mutability::Not);
                 }
             }
-            &Expr::While { condition: c, body, label: _ } => {
-                self.infer_mut_expr(c, Mutability::Not);
-                self.infer_mut_expr(body, Mutability::Not);
-            }
             Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ }
             | Expr::Call { callee: it, args, is_assignee_expr: _ } => {
                 self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it)));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index ffc7a6f2ebd..b15339d4434 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -14,7 +14,7 @@ use triomphe::Arc;
 
 use crate::{
     consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
-    utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty,
+    utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
 };
 
 pub use self::{
@@ -279,7 +279,15 @@ pub fn layout_of_ty_query(
             //     return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
             // }
 
-            let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
+            let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
+            if let TyKind::AssociatedType(id, subst) = unsized_part.kind(Interner) {
+                unsized_part = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
+                    associated_ty_id: *id,
+                    substitution: subst.clone(),
+                }))
+                .intern(Interner);
+            }
+            unsized_part = normalize(db, trait_env.clone(), unsized_part);
             let metadata = match unsized_part.kind(Interner) {
                 TyKind::Slice(_) | TyKind::Str => {
                     scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
@@ -362,8 +370,16 @@ pub fn layout_of_ty_query(
             return Err(LayoutError::NotImplemented)
         }
         TyKind::Error => return Err(LayoutError::HasErrorType),
-        TyKind::AssociatedType(_, _)
-        | TyKind::Alias(_)
+        TyKind::AssociatedType(id, subst) => {
+            // Try again with `TyKind::Alias` to normalize the associated type.
+            let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
+                associated_ty_id: *id,
+                substitution: subst.clone(),
+            }))
+            .intern(Interner);
+            return db.layout_of_ty(ty, trait_env);
+        }
+        TyKind::Alias(_)
         | TyKind::Placeholder(_)
         | TyKind::BoundVar(_)
         | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 922e49d281d..4723c25ed08 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -234,6 +234,7 @@ impl Place {
         self.local == child.local && child.projection.starts_with(&self.projection)
     }
 
+    /// The place itself is not included
     fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ {
         (0..self.projection.len())
             .map(|x| &self.projection[0..x])
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 7bd2756c14f..9e30eed56f3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -1,6 +1,13 @@
 //! This module provides a MIR interpreter, which is used in const eval.
 
-use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Write, iter, mem, ops::Range};
+use std::{
+    borrow::Cow,
+    cell::RefCell,
+    collections::{HashMap, HashSet},
+    fmt::Write,
+    iter, mem,
+    ops::Range,
+};
 
 use base_db::{CrateId, FileId};
 use chalk_ir::Mutability;
@@ -39,7 +46,8 @@ use crate::{
 
 use super::{
     return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
-    MirSpan, Operand, Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp,
+    MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind,
+    UnOp,
 };
 
 mod shim;
@@ -68,18 +76,22 @@ pub struct VTableMap {
 }
 
 impl VTableMap {
+    const OFFSET: usize = 1000; // We should add some offset to ids to make 0 (null) an invalid id.
+
     fn id(&mut self, ty: Ty) -> usize {
         if let Some(it) = self.ty_to_id.get(&ty) {
             return *it;
         }
-        let id = self.id_to_ty.len();
+        let id = self.id_to_ty.len() + VTableMap::OFFSET;
         self.id_to_ty.push(ty.clone());
         self.ty_to_id.insert(ty, id);
         id
     }
 
     pub(crate) fn ty(&self, id: usize) -> Result<&Ty> {
-        self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id))
+        id.checked_sub(VTableMap::OFFSET)
+            .and_then(|id| self.id_to_ty.get(id))
+            .ok_or(MirEvalError::InvalidVTableId(id))
     }
 
     fn ty_of_bytes(&self, bytes: &[u8]) -> Result<&Ty> {
@@ -116,13 +128,18 @@ impl TlsData {
 }
 
 struct StackFrame {
-    body: Arc<MirBody>,
     locals: Locals,
     destination: Option<BasicBlockId>,
     prev_stack_ptr: usize,
     span: (MirSpan, DefWithBodyId),
 }
 
+#[derive(Clone)]
+enum MirOrDynIndex {
+    Mir(Arc<MirBody>),
+    Dyn(usize),
+}
+
 pub struct Evaluator<'a> {
     db: &'a dyn HirDatabase,
     trait_env: Arc<TraitEnvironment>,
@@ -141,6 +158,17 @@ pub struct Evaluator<'a> {
     stdout: Vec<u8>,
     stderr: Vec<u8>,
     layout_cache: RefCell<FxHashMap<Ty, Arc<Layout>>>,
+    projected_ty_cache: RefCell<FxHashMap<(Ty, PlaceElem), Ty>>,
+    not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,
+    mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, Substitution), MirOrDynIndex>>,
+    /// Constantly dropping and creating `Locals` is very costly. We store
+    /// old locals that we normaly want to drop here, to reuse their allocations
+    /// later.
+    unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals>>>,
+    cached_ptr_size: usize,
+    cached_fn_trait_func: Option<FunctionId>,
+    cached_fn_mut_trait_func: Option<FunctionId>,
+    cached_fn_once_trait_func: Option<FunctionId>,
     crate_id: CrateId,
     // FIXME: This is a workaround, see the comment on `interpret_mir`
     assert_placeholder_ty_is_unused: bool,
@@ -313,6 +341,7 @@ pub enum MirEvalError {
     InvalidVTableId(usize),
     CoerceUnsizedError(Ty),
     LangItemNotFound(LangItem),
+    BrokenLayout(Layout),
 }
 
 impl MirEvalError {
@@ -399,6 +428,7 @@ impl MirEvalError {
             | MirEvalError::TargetDataLayoutNotAvailable
             | MirEvalError::CoerceUnsizedError(_)
             | MirEvalError::LangItemNotFound(_)
+            | MirEvalError::BrokenLayout(_)
             | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
         }
         Ok(())
@@ -433,6 +463,7 @@ impl std::fmt::Debug for MirEvalError {
             Self::CoerceUnsizedError(arg0) => {
                 f.debug_tuple("CoerceUnsizedError").field(arg0).finish()
             }
+            Self::BrokenLayout(arg0) => f.debug_tuple("BrokenLayout").field(arg0).finish(),
             Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),
             Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
             Self::InvalidConst(arg0) => {
@@ -464,8 +495,16 @@ impl DropFlags {
 
     fn remove_place(&mut self, p: &Place) -> bool {
         // FIXME: replace parents with parts
+        if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) {
+            self.need_drop.remove(&parent);
+            return true;
+        }
         self.need_drop.remove(p)
     }
+
+    fn clear(&mut self) {
+        self.need_drop.clear();
+    }
 }
 
 #[derive(Debug)]
@@ -508,6 +547,11 @@ pub fn interpret_mir(
     )
 }
 
+#[cfg(test)]
+const EXECUTION_LIMIT: usize = 100_000;
+#[cfg(not(test))]
+const EXECUTION_LIMIT: usize = 10_000_000;
+
 impl Evaluator<'_> {
     pub fn new<'a>(
         db: &'a dyn HirDatabase,
@@ -531,9 +575,29 @@ impl Evaluator<'_> {
             stderr: vec![],
             assert_placeholder_ty_is_unused,
             stack_depth_limit: 100,
-            execution_limit: 1000_000,
+            execution_limit: EXECUTION_LIMIT,
             memory_limit: 1000_000_000, // 2GB, 1GB for stack and 1GB for heap
             layout_cache: RefCell::new(HashMap::default()),
+            projected_ty_cache: RefCell::new(HashMap::default()),
+            not_special_fn_cache: RefCell::new(HashSet::default()),
+            mir_or_dyn_index_cache: RefCell::new(HashMap::default()),
+            unused_locals_store: RefCell::new(HashMap::default()),
+            cached_ptr_size: match db.target_data_layout(crate_id) {
+                Some(it) => it.pointer_size.bytes_usize(),
+                None => 8,
+            },
+            cached_fn_trait_func: db
+                .lang_item(crate_id, LangItem::Fn)
+                .and_then(|x| x.as_trait())
+                .and_then(|x| db.trait_data(x).method_by_name(&name![call])),
+            cached_fn_mut_trait_func: db
+                .lang_item(crate_id, LangItem::FnMut)
+                .and_then(|x| x.as_trait())
+                .and_then(|x| db.trait_data(x).method_by_name(&name![call_mut])),
+            cached_fn_once_trait_func: db
+                .lang_item(crate_id, LangItem::FnOnce)
+                .and_then(|x| x.as_trait())
+                .and_then(|x| db.trait_data(x).method_by_name(&name![call_once])),
         }
     }
 
@@ -554,10 +618,34 @@ impl Evaluator<'_> {
     }
 
     fn ptr_size(&self) -> usize {
-        match self.db.target_data_layout(self.crate_id) {
-            Some(it) => it.pointer_size.bytes_usize(),
-            None => 8,
+        self.cached_ptr_size
+    }
+
+    fn projected_ty(&self, ty: Ty, proj: PlaceElem) -> Ty {
+        let pair = (ty, proj);
+        if let Some(r) = self.projected_ty_cache.borrow().get(&pair) {
+            return r.clone();
         }
+        let (ty, proj) = pair;
+        let r = proj.projected_ty(
+            ty.clone(),
+            self.db,
+            |c, subst, f| {
+                let (def, _) = self.db.lookup_intern_closure(c.into());
+                let infer = self.db.infer(def);
+                let (captures, _) = infer.closure_info(&c);
+                let parent_subst = ClosureSubst(subst).parent_subst();
+                captures
+                    .get(f)
+                    .expect("broken closure field")
+                    .ty
+                    .clone()
+                    .substitute(Interner, parent_subst)
+            },
+            self.crate_id,
+        );
+        self.projected_ty_cache.borrow_mut().insert((ty, proj), r.clone());
+        r
     }
 
     fn place_addr_and_ty_and_metadata<'a>(
@@ -570,23 +658,7 @@ impl Evaluator<'_> {
         let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
         for proj in &*p.projection {
             let prev_ty = ty.clone();
-            ty = proj.projected_ty(
-                ty,
-                self.db,
-                |c, subst, f| {
-                    let (def, _) = self.db.lookup_intern_closure(c.into());
-                    let infer = self.db.infer(def);
-                    let (captures, _) = infer.closure_info(&c);
-                    let parent_subst = ClosureSubst(subst).parent_subst();
-                    captures
-                        .get(f)
-                        .expect("broken closure field")
-                        .ty
-                        .clone()
-                        .substitute(Interner, parent_subst)
-                },
-                self.crate_id,
-            );
+            ty = self.projected_ty(ty, proj.clone());
             match proj {
                 ProjectionElem::Deref => {
                     metadata = if self.size_align_of(&ty, locals)?.is_none() {
@@ -680,8 +752,10 @@ impl Evaluator<'_> {
                         .offset(u32::from(f.local_id.into_raw()) as usize)
                         .bytes_usize();
                     addr = addr.offset(offset);
-                    // FIXME: support structs with unsized fields
-                    metadata = None;
+                    // Unsized field metadata is equal to the metadata of the struct
+                    if self.size_align_of(&ty, locals)?.is_some() {
+                        metadata = None;
+                    }
                 }
                 ProjectionElem::OpaqueCast(_) => not_supported!("opaque cast"),
             }
@@ -702,9 +776,7 @@ impl Evaluator<'_> {
     }
 
     fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> {
-        self.db.layout_of_adt(adt, subst.clone(), self.trait_env.clone()).map_err(|e| {
-            MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
-        })
+        self.layout(&TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
     }
 
     fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<Ty> {
@@ -740,18 +812,18 @@ impl Evaluator<'_> {
             return Err(MirEvalError::StackOverflow);
         }
         let mut current_block_idx = body.start_block;
-        let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body.clone(), None)?;
+        let (mut locals, prev_stack_ptr) = self.create_locals_for_body(&body, None)?;
         self.fill_locals_for_body(&body, &mut locals, args)?;
         let prev_code_stack = mem::take(&mut self.code_stack);
         let span = (MirSpan::Unknown, body.owner);
-        self.code_stack.push(StackFrame { body, locals, destination: None, prev_stack_ptr, span });
+        self.code_stack.push(StackFrame { locals, destination: None, prev_stack_ptr, span });
         'stack: loop {
             let Some(mut my_stack_frame) = self.code_stack.pop() else {
                 not_supported!("missing stack frame");
             };
             let e = (|| {
                 let mut locals = &mut my_stack_frame.locals;
-                let body = &*my_stack_frame.body;
+                let body = locals.body.clone();
                 loop {
                     let current_block = &body.basic_blocks[current_block_idx];
                     if let Some(it) = self.execution_limit.checked_sub(1) {
@@ -820,7 +892,7 @@ impl Evaluator<'_> {
                             locals.drop_flags.add_place(destination.clone());
                             if let Some(stack_frame) = stack_frame {
                                 self.code_stack.push(my_stack_frame);
-                                current_block_idx = stack_frame.body.start_block;
+                                current_block_idx = stack_frame.locals.body.start_block;
                                 self.code_stack.push(stack_frame);
                                 return Ok(None);
                             } else {
@@ -861,18 +933,24 @@ impl Evaluator<'_> {
                     let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack);
                     let mut error_stack = vec![];
                     for frame in my_code_stack.into_iter().rev() {
-                        if let DefWithBodyId::FunctionId(f) = frame.body.owner {
+                        if let DefWithBodyId::FunctionId(f) = frame.locals.body.owner {
                             error_stack.push((Either::Left(f), frame.span.0, frame.span.1));
                         }
                     }
                     return Err(MirEvalError::InFunction(Box::new(e), error_stack));
                 }
             };
+            let return_interval = my_stack_frame.locals.ptr[return_slot()];
+            self.unused_locals_store
+                .borrow_mut()
+                .entry(my_stack_frame.locals.body.owner)
+                .or_default()
+                .push(my_stack_frame.locals);
             match my_stack_frame.destination {
                 None => {
                     self.code_stack = prev_code_stack;
                     self.stack_depth_limit += 1;
-                    return Ok(my_stack_frame.locals.ptr[return_slot()].get(self)?.to_vec());
+                    return Ok(return_interval.get(self)?.to_vec());
                 }
                 Some(bb) => {
                     // We don't support const promotion, so we can't truncate the stack yet.
@@ -910,39 +988,45 @@ impl Evaluator<'_> {
 
     fn create_locals_for_body(
         &mut self,
-        body: Arc<MirBody>,
+        body: &Arc<MirBody>,
         destination: Option<Interval>,
     ) -> Result<(Locals, usize)> {
         let mut locals =
-            Locals { ptr: ArenaMap::new(), body: body.clone(), drop_flags: DropFlags::default() };
-        let (locals_ptr, stack_size) = {
+            match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() {
+                None => Locals {
+                    ptr: ArenaMap::new(),
+                    body: body.clone(),
+                    drop_flags: DropFlags::default(),
+                },
+                Some(mut l) => {
+                    l.drop_flags.clear();
+                    l.body = body.clone();
+                    l
+                }
+            };
+        let stack_size = {
             let mut stack_ptr = self.stack.len();
-            let addr = body
-                .locals
-                .iter()
-                .map(|(id, it)| {
-                    if id == return_slot() {
-                        if let Some(destination) = destination {
-                            return Ok((id, destination));
-                        }
-                    }
-                    let (size, align) = self.size_align_of_sized(
-                        &it.ty,
-                        &locals,
-                        "no unsized local in extending stack",
-                    )?;
-                    while stack_ptr % align != 0 {
-                        stack_ptr += 1;
+            for (id, it) in body.locals.iter() {
+                if id == return_slot() {
+                    if let Some(destination) = destination {
+                        locals.ptr.insert(id, destination);
+                        continue;
                     }
-                    let my_ptr = stack_ptr;
-                    stack_ptr += size;
-                    Ok((id, Interval { addr: Stack(my_ptr), size }))
-                })
-                .collect::<Result<ArenaMap<LocalId, _>>>()?;
-            let stack_size = stack_ptr - self.stack.len();
-            (addr, stack_size)
+                }
+                let (size, align) = self.size_align_of_sized(
+                    &it.ty,
+                    &locals,
+                    "no unsized local in extending stack",
+                )?;
+                while stack_ptr % align != 0 {
+                    stack_ptr += 1;
+                }
+                let my_ptr = stack_ptr;
+                stack_ptr += size;
+                locals.ptr.insert(id, Interval { addr: Stack(my_ptr), size });
+            }
+            stack_ptr - self.stack.len()
         };
-        locals.ptr = locals_ptr;
         let prev_stack_pointer = self.stack.len();
         if stack_size > self.memory_limit {
             return Err(MirEvalError::Panic(format!(
@@ -1543,12 +1627,18 @@ impl Evaluator<'_> {
     ) -> Result<Vec<u8>> {
         let mut result = vec![0; size];
         if let Some((offset, size, value)) = tag {
-            result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]);
+            match result.get_mut(offset..offset + size) {
+                Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
+                None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+            }
         }
         for (i, op) in values.enumerate() {
             let offset = variant_layout.fields.offset(i).bytes_usize();
             let op = op.get(&self)?;
-            result[offset..offset + op.len()].copy_from_slice(op);
+            match result.get_mut(offset..offset + op.len()) {
+                Some(it) => it.copy_from_slice(op),
+                None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+            }
         }
         Ok(result)
     }
@@ -1671,6 +1761,11 @@ impl Evaluator<'_> {
     }
 
     fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<Option<(usize, usize)>> {
+        if let Some(layout) = self.layout_cache.borrow().get(ty) {
+            return Ok(layout
+                .is_sized()
+                .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize)));
+        }
         if let DefWithBodyId::VariantId(f) = locals.body.owner {
             if let Some((adt, _)) = ty.as_adt() {
                 if AdtId::from(f.parent) == adt {
@@ -1731,16 +1826,15 @@ impl Evaluator<'_> {
     }
 
     fn detect_fn_trait(&self, def: FunctionId) -> Option<FnTrait> {
-        use LangItem::*;
-        let ItemContainerId::TraitId(parent) = self.db.lookup_intern_function(def).container else {
-            return None;
-        };
-        let l = self.db.lang_attr(parent.into())?;
-        match l {
-            FnOnce => Some(FnTrait::FnOnce),
-            FnMut => Some(FnTrait::FnMut),
-            Fn => Some(FnTrait::Fn),
-            _ => None,
+        let def = Some(def);
+        if def == self.cached_fn_trait_func {
+            Some(FnTrait::Fn)
+        } else if def == self.cached_fn_mut_trait_func {
+            Some(FnTrait::FnMut)
+        } else if def == self.cached_fn_once_trait_func {
+            Some(FnTrait::FnOnce)
+        } else {
+            None
         }
     }
 
@@ -1796,6 +1890,17 @@ impl Evaluator<'_> {
                         }
                     }
                 }
+                chalk_ir::TyKind::Array(inner, len) => {
+                    let len = match try_const_usize(this.db, &len) {
+                        Some(it) => it as usize,
+                        None => not_supported!("non evaluatable array len in patching addresses"),
+                    };
+                    let size = this.size_of_sized(inner, locals, "inner of array")?;
+                    for i in 0..len {
+                        let offset = i * size;
+                        rec(this, &bytes[offset..offset + size], inner, locals, mm)?;
+                    }
+                }
                 chalk_ir::TyKind::Tuple(_, subst) => {
                     let layout = this.layout(ty)?;
                     for (id, ty) in subst.iter(Interner).enumerate() {
@@ -1904,10 +2009,31 @@ impl Evaluator<'_> {
                 AdtId::UnionId(_) => (),
                 AdtId::EnumId(_) => (),
             },
+            TyKind::Tuple(_, subst) => {
+                for (id, ty) in subst.iter(Interner).enumerate() {
+                    let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
+                    let offset = layout.fields.offset(id).bytes_usize();
+                    self.patch_addresses(patch_map, old_vtable, addr.offset(offset), ty, locals)?;
+                }
+            }
+            TyKind::Array(inner, len) => {
+                let len = match try_const_usize(self.db, &len) {
+                    Some(it) => it as usize,
+                    None => not_supported!("non evaluatable array len in patching addresses"),
+                };
+                let size = self.size_of_sized(inner, locals, "inner of array")?;
+                for i in 0..len {
+                    self.patch_addresses(
+                        patch_map,
+                        old_vtable,
+                        addr.offset(i * size),
+                        inner,
+                        locals,
+                    )?;
+                }
+            }
             TyKind::AssociatedType(_, _)
             | TyKind::Scalar(_)
-            | TyKind::Tuple(_, _)
-            | TyKind::Array(_, _)
             | TyKind::Slice(_)
             | TyKind::Raw(_, _)
             | TyKind::OpaqueType(_, _)
@@ -2051,6 +2177,40 @@ impl Evaluator<'_> {
         }
     }
 
+    fn get_mir_or_dyn_index(
+        &self,
+        def: FunctionId,
+        generic_args: Substitution,
+        locals: &Locals,
+        span: MirSpan,
+    ) -> Result<MirOrDynIndex> {
+        let pair = (def, generic_args);
+        if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) {
+            return Ok(r.clone());
+        }
+        let (def, generic_args) = pair;
+        let r = if let Some(self_ty_idx) =
+            is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone())
+        {
+            MirOrDynIndex::Dyn(self_ty_idx)
+        } else {
+            let (imp, generic_args) =
+                self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args.clone());
+            let mir_body = self
+                .db
+                .monomorphized_mir_body(imp.into(), generic_args, self.trait_env.clone())
+                .map_err(|e| {
+                    MirEvalError::InFunction(
+                        Box::new(MirEvalError::MirLowerError(imp, e)),
+                        vec![(Either::Left(imp), span, locals.body.owner)],
+                    )
+                })?;
+            MirOrDynIndex::Mir(mir_body)
+        };
+        self.mir_or_dyn_index_cache.borrow_mut().insert((def, generic_args), r.clone());
+        Ok(r)
+    }
+
     fn exec_fn_with_args(
         &mut self,
         def: FunctionId,
@@ -2072,93 +2232,76 @@ impl Evaluator<'_> {
             return Ok(None);
         }
         let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval));
-        if let Some(self_ty_idx) =
-            is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone())
-        {
-            // In the layout of current possible receiver, which at the moment of writing this code is one of
-            // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers,
-            // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on
-            // the type.
-            let first_arg = arg_bytes.clone().next().unwrap();
-            let first_arg = first_arg.get(self)?;
-            let ty =
-                self.vtable_map.ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?;
-            let mut args_for_target = args.to_vec();
-            args_for_target[0] = IntervalAndTy {
-                interval: args_for_target[0].interval.slice(0..self.ptr_size()),
-                ty: ty.clone(),
-            };
-            let ty = GenericArgData::Ty(ty.clone()).intern(Interner);
-            let generics_for_target = Substitution::from_iter(
-                Interner,
-                generic_args.iter(Interner).enumerate().map(|(i, it)| {
-                    if i == self_ty_idx {
-                        &ty
-                    } else {
-                        it
-                    }
-                }),
-            );
-            return self.exec_fn_with_args(
-                def,
-                &args_for_target,
-                generics_for_target,
+        match self.get_mir_or_dyn_index(def, generic_args.clone(), locals, span)? {
+            MirOrDynIndex::Dyn(self_ty_idx) => {
+                // In the layout of current possible receiver, which at the moment of writing this code is one of
+                // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers,
+                // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on
+                // the type.
+                let first_arg = arg_bytes.clone().next().unwrap();
+                let first_arg = first_arg.get(self)?;
+                let ty = self
+                    .vtable_map
+                    .ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?;
+                let mut args_for_target = args.to_vec();
+                args_for_target[0] = IntervalAndTy {
+                    interval: args_for_target[0].interval.slice(0..self.ptr_size()),
+                    ty: ty.clone(),
+                };
+                let ty = GenericArgData::Ty(ty.clone()).intern(Interner);
+                let generics_for_target = Substitution::from_iter(
+                    Interner,
+                    generic_args.iter(Interner).enumerate().map(|(i, it)| {
+                        if i == self_ty_idx {
+                            &ty
+                        } else {
+                            it
+                        }
+                    }),
+                );
+                return self.exec_fn_with_args(
+                    def,
+                    &args_for_target,
+                    generics_for_target,
+                    locals,
+                    destination,
+                    target_bb,
+                    span,
+                );
+            }
+            MirOrDynIndex::Mir(body) => self.exec_looked_up_function(
+                body,
                 locals,
+                def,
+                arg_bytes,
+                span,
                 destination,
                 target_bb,
-                span,
-            );
+            ),
         }
-        let (imp, generic_args) =
-            self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args);
-        self.exec_looked_up_function(
-            generic_args,
-            locals,
-            imp,
-            arg_bytes,
-            span,
-            destination,
-            target_bb,
-        )
     }
 
     fn exec_looked_up_function(
         &mut self,
-        generic_args: Substitution,
+        mir_body: Arc<MirBody>,
         locals: &Locals,
-        imp: FunctionId,
+        def: FunctionId,
         arg_bytes: impl Iterator<Item = IntervalOrOwned>,
         span: MirSpan,
         destination: Interval,
         target_bb: Option<BasicBlockId>,
     ) -> Result<Option<StackFrame>> {
-        let def = imp.into();
-        let mir_body = self
-            .db
-            .monomorphized_mir_body(def, generic_args, self.trait_env.clone())
-            .map_err(|e| {
-                MirEvalError::InFunction(
-                    Box::new(MirEvalError::MirLowerError(imp, e)),
-                    vec![(Either::Left(imp), span, locals.body.owner)],
-                )
-            })?;
         Ok(if let Some(target_bb) = target_bb {
             let (mut locals, prev_stack_ptr) =
-                self.create_locals_for_body(mir_body.clone(), Some(destination))?;
+                self.create_locals_for_body(&mir_body, Some(destination))?;
             self.fill_locals_for_body(&mir_body, &mut locals, arg_bytes.into_iter())?;
             let span = (span, locals.body.owner);
-            Some(StackFrame {
-                body: mir_body,
-                locals,
-                destination: Some(target_bb),
-                prev_stack_ptr,
-                span,
-            })
+            Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span })
         } else {
             let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| {
                 MirEvalError::InFunction(
                     Box::new(e),
-                    vec![(Either::Left(imp), span, locals.body.owner)],
+                    vec![(Either::Left(def), span, locals.body.owner)],
                 )
             })?;
             destination.write_from_bytes(self, &result)?;
@@ -2330,16 +2473,15 @@ impl Evaluator<'_> {
             // we can ignore drop in them.
             return Ok(());
         };
-        let (impl_drop_candidate, subst) = self.db.lookup_impl_method(
-            self.trait_env.clone(),
-            drop_fn,
-            Substitution::from1(Interner, ty.clone()),
-        );
-        if impl_drop_candidate != drop_fn {
+
+        let generic_args = Substitution::from1(Interner, ty.clone());
+        if let Ok(MirOrDynIndex::Mir(body)) =
+            self.get_mir_or_dyn_index(drop_fn, generic_args, locals, span)
+        {
             self.exec_looked_up_function(
-                subst,
+                body,
                 locals,
-                impl_drop_candidate,
+                drop_fn,
                 [IntervalOrOwned::Owned(addr.to_bytes())].into_iter(),
                 span,
                 Interval { addr: Address::Invalid(0), size: 0 },
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 9ad6087cad9..b2e29fd34b5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -36,6 +36,9 @@ impl Evaluator<'_> {
         destination: Interval,
         span: MirSpan,
     ) -> Result<bool> {
+        if self.not_special_fn_cache.borrow().contains(&def) {
+            return Ok(false);
+        }
         let function_data = self.db.function_data(def);
         let is_intrinsic = match &function_data.abi {
             Some(abi) => *abi == Interned::new_str("rust-intrinsic"),
@@ -124,9 +127,88 @@ impl Evaluator<'_> {
             destination.write_from_bytes(self, &result)?;
             return Ok(true);
         }
+        if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container {
+            if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
+                let [self_ty] = generic_args.as_slice(Interner) else {
+                    not_supported!("wrong generic arg count for clone");
+                };
+                let Some(self_ty) = self_ty.ty(Interner) else {
+                    not_supported!("wrong generic arg kind for clone");
+                };
+                // Clone has special impls for tuples and function pointers
+                if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
+                    self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
+                    return Ok(true);
+                }
+                // Return early to prevent caching clone as non special fn.
+                return Ok(false);
+            }
+        }
+        self.not_special_fn_cache.borrow_mut().insert(def);
         Ok(false)
     }
 
+    /// Clone has special impls for tuples and function pointers
+    fn exec_clone(
+        &mut self,
+        def: FunctionId,
+        args: &[IntervalAndTy],
+        self_ty: Ty,
+        locals: &Locals,
+        destination: Interval,
+        span: MirSpan,
+    ) -> Result<()> {
+        match self_ty.kind(Interner) {
+            TyKind::Function(_) => {
+                let [arg] = args else {
+                    not_supported!("wrong arg count for clone");
+                };
+                let addr = Address::from_bytes(arg.get(self)?)?;
+                return destination
+                    .write_from_interval(self, Interval { addr, size: destination.size });
+            }
+            TyKind::Tuple(_, subst) => {
+                let [arg] = args else {
+                    not_supported!("wrong arg count for clone");
+                };
+                let addr = Address::from_bytes(arg.get(self)?)?;
+                let layout = self.layout(&self_ty)?;
+                for (i, ty) in subst.iter(Interner).enumerate() {
+                    let ty = ty.assert_ty_ref(Interner);
+                    let size = self.layout(ty)?.size.bytes_usize();
+                    let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
+                    let arg = IntervalAndTy {
+                        interval: Interval { addr: tmp, size: self.ptr_size() },
+                        ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
+                            .intern(Interner),
+                    };
+                    let offset = layout.fields.offset(i).bytes_usize();
+                    self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
+                    self.exec_clone(
+                        def,
+                        &[arg],
+                        ty.clone(),
+                        locals,
+                        destination.slice(offset..offset + size),
+                        span,
+                    )?;
+                }
+            }
+            _ => {
+                self.exec_fn_with_args(
+                    def,
+                    args,
+                    Substitution::from1(Interner, self_ty),
+                    locals,
+                    destination,
+                    None,
+                    span,
+                )?;
+            }
+        }
+        Ok(())
+    }
+
     fn exec_alloc_fn(
         &mut self,
         alloc_fn: &str,
@@ -618,12 +700,15 @@ impl Evaluator<'_> {
                 else {
                     return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
                 };
-                let Ok(ty_name) = ty.display_source_code(
+                let ty_name = match ty.display_source_code(
                     self.db,
                     locals.body.owner.module(self.db.upcast()),
                     true,
-                ) else {
-                    not_supported!("fail in generating type_name using source code display");
+                ) {
+                    Ok(ty_name) => ty_name,
+                    // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to
+                    // render full paths.
+                    Err(_) => ty.display(self.db).to_string(),
                 };
                 let len = ty_name.len();
                 let addr = self.heap_allocate(len, 1)?;
@@ -679,7 +764,22 @@ impl Evaluator<'_> {
                 let ans = lhs.wrapping_add(rhs);
                 destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
             }
-            "wrapping_sub" | "unchecked_sub" | "ptr_offset_from_unsigned" | "ptr_offset_from" => {
+            "ptr_offset_from_unsigned" | "ptr_offset_from" => {
+                let [lhs, rhs] = args else {
+                    return Err(MirEvalError::TypeError("wrapping_sub args are not provided"));
+                };
+                let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false));
+                let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false));
+                let ans = lhs.wrapping_sub(rhs);
+                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                else {
+                    return Err(MirEvalError::TypeError("ptr_offset_from generic arg is not provided"));
+                };
+                let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128;
+                let ans = ans / size;
+                destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
+            }
+            "wrapping_sub" | "unchecked_sub" => {
                 let [lhs, rhs] = args else {
                     return Err(MirEvalError::TypeError("wrapping_sub args are not provided"));
                 };
@@ -1057,7 +1157,14 @@ impl Evaluator<'_> {
         _span: MirSpan,
     ) -> Result<()> {
         // We are a single threaded runtime with no UB checking and no optimization, so
-        // we can implement these as normal functions.
+        // we can implement atomic intrinsics as normal functions.
+
+        if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
+            return Ok(());
+        }
+
+        // The rest of atomic intrinsics have exactly one generic arg
+
         let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
             return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided"));
         };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 93f4b699147..46165cf3d69 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -183,6 +183,50 @@ fn main() {
 }
 
 #[test]
+fn drop_struct_field() {
+    check_pass(
+        r#"
+//- minicore: drop, add, option, cell, builtin_impls
+
+use core::cell::Cell;
+
+fn should_not_reach() {
+    _ // FIXME: replace this function with panic when that works
+}
+
+struct X<'a>(&'a Cell<i32>);
+impl<'a> Drop for X<'a> {
+    fn drop(&mut self) {
+        self.0.set(self.0.get() + 1)
+    }
+}
+
+struct Tuple<'a>(X<'a>, X<'a>, X<'a>);
+
+fn main() {
+    let s = Cell::new(0);
+    {
+        let x0 = X(&s);
+        let xt = Tuple(x0, X(&s), X(&s));
+        let x1 = xt.1;
+        if s.get() != 0 {
+            should_not_reach();
+        }
+        drop(xt.0);
+        if s.get() != 1 {
+            should_not_reach();
+        }
+    }
+    // FIXME: this should be 3
+    if s.get() != 2 {
+        should_not_reach();
+    }
+}
+"#,
+    );
+}
+
+#[test]
 fn drop_in_place() {
     check_pass(
         r#"
@@ -614,6 +658,50 @@ fn main() {
 }
 
 #[test]
+fn self_with_capital_s() {
+    check_pass(
+        r#"
+//- minicore: fn, add, copy
+
+struct S1;
+
+impl S1 {
+    fn f() {
+        Self;
+    }
+}
+
+struct S2 {
+    f1: i32,
+}
+
+impl S2 {
+    fn f() {
+        Self { f1: 5 };
+    }
+}
+
+struct S3(i32);
+
+impl S3 {
+    fn f() {
+        Self(2);
+        Self;
+        let this = Self;
+        this(2);
+    }
+}
+
+fn main() {
+    S1::f();
+    S2::f();
+    S3::f();
+}
+        "#,
+    );
+}
+
+#[test]
 fn syscalls() {
     check_pass(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 9f25175a3a9..718df8331e2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -486,13 +486,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         );
                         Ok(Some(current))
                     }
-                    ValueNs::FunctionId(_) | ValueNs::StructId(_) => {
+                    ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::ImplSelf(_) => {
                         // It's probably a unit struct or a zero sized function, so no action is needed.
                         Ok(Some(current))
                     }
-                    it => {
-                        not_supported!("unknown name {it:?} in value name space");
-                    }
                 }
             }
             Expr::If { condition, then_branch, else_branch } => {
@@ -585,36 +582,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     Ok(())
                 })
             }
-            Expr::While { condition, body, label } => {
-                self.lower_loop(current, place, *label, expr_id.into(), |this, begin| {
-                    let scope = this.push_drop_scope();
-                    let Some((discr, to_switch)) =
-                        this.lower_expr_to_some_operand(*condition, begin)?
-                    else {
-                        return Ok(());
-                    };
-                    let fail_cond = this.new_basic_block();
-                    let after_cond = this.new_basic_block();
-                    this.set_terminator(
-                        to_switch,
-                        TerminatorKind::SwitchInt {
-                            discr,
-                            targets: SwitchTargets::static_if(1, after_cond, fail_cond),
-                        },
-                        expr_id.into(),
-                    );
-                    let fail_cond = this.drop_until_scope(this.drop_scopes.len() - 1, fail_cond);
-                    let end = this.current_loop_end()?;
-                    this.set_goto(fail_cond, end, expr_id.into());
-                    if let Some((_, block)) = this.lower_expr_as_place(after_cond, *body, true)? {
-                        let block = scope.pop_and_drop(this, block);
-                        this.set_goto(block, begin, expr_id.into());
-                    } else {
-                        scope.pop_assume_dropped(this);
-                    }
-                    Ok(())
-                })
-            }
             Expr::Call { callee, args, .. } => {
                 if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) {
                     let ty = chalk_ir::TyKind::FnDef(
@@ -660,6 +627,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
                             expr_id.into(),
                         )
                     }
+                    TyKind::Closure(_, _) => {
+                        not_supported!(
+                            "method resolution not emitted for closure (Are Fn traits available?)"
+                        );
+                    }
                     TyKind::Error => {
                         return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id))
                     }
@@ -1026,18 +998,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         self.push_assignment(current, lhs_place, r_value, expr_id.into());
                         return Ok(Some(current));
                     } else {
-                        let Some((lhs_place, current)) =
-                            self.lower_expr_as_place(current, *lhs, false)?
-                        else {
-                            return Ok(None);
-                        };
-                        let Some((rhs_op, current)) =
-                            self.lower_expr_to_some_operand(*rhs, current)?
-                        else {
-                            return Ok(None);
-                        };
-                        self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into());
-                        return Ok(Some(current));
+                        return self.lower_assignment(current, *lhs, *rhs, expr_id.into());
                     }
                 }
                 let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)?
@@ -1283,6 +1244,30 @@ impl<'ctx> MirLowerCtx<'ctx> {
         }
     }
 
+    fn lower_assignment(
+        &mut self,
+        current: BasicBlockId,
+        lhs: ExprId,
+        rhs: ExprId,
+        span: MirSpan,
+    ) -> Result<Option<BasicBlockId>> {
+        let Some((rhs_op, current)) =
+            self.lower_expr_to_some_operand(rhs, current)?
+        else {
+            return Ok(None);
+        };
+        if matches!(&self.body.exprs[lhs], Expr::Underscore) {
+            return Ok(Some(current));
+        }
+        let Some((lhs_place, current)) =
+            self.lower_expr_as_place(current, lhs, false)?
+        else {
+            return Ok(None);
+        };
+        self.push_assignment(current, lhs_place, rhs_op.into(), span);
+        Ok(Some(current))
+    }
+
     fn placeholder_subst(&mut self) -> Substitution {
         let placeholder_subst = match self.owner.as_generic_def_id() {
             Some(it) => TyBuilder::placeholder_subst(self.db, it),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index 425432479e8..e75b037e38d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -227,3 +227,22 @@ fn f(a: impl Foo<i8, Assoc<i16> = i32>) {
         "#,
     );
 }
+
+#[test]
+fn fn_def_is_shown_as_fn_ptr() {
+    check_types_source_code(
+        r#"
+fn foo(_: i32) -> i64 { 42 }
+struct S<T>(T);
+enum E { A(usize) }
+fn test() {
+    let f = foo;
+      //^ fn(i32) -> i64
+    let f = S::<i8>;
+      //^ fn(i8) -> S<i8>
+    let f = E::A;
+      //^ fn(usize) -> E
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index b71c457f015..1e6e946a13f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -209,6 +209,8 @@ fn expr_macro_def_expanded_in_various_places() {
             104..105 '_': IntoIterator::Item<isize>
             117..119 '{}': ()
             124..134 '|| spam!()': impl Fn() -> isize
+            140..156 'while ...!() {}': !
+            140..156 'while ...!() {}': ()
             140..156 'while ...!() {}': ()
             154..156 '{}': ()
             161..174 'break spam!()': !
@@ -300,6 +302,8 @@ fn expr_macro_rules_expanded_in_various_places() {
             118..119 '_': IntoIterator::Item<isize>
             131..133 '{}': ()
             138..148 '|| spam!()': impl Fn() -> isize
+            154..170 'while ...!() {}': !
+            154..170 'while ...!() {}': ()
             154..170 'while ...!() {}': ()
             168..170 '{}': ()
             175..188 'break spam!()': !
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
index 59046c0435a..5d809b82392 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
@@ -412,17 +412,23 @@ fn diverging_expression_3_break() {
             355..654 '{     ...; }; }': ()
             398..399 'x': u32
             407..433 '{ whil...; }; }': u32
+            409..430 'while ...eak; }': !
+            409..430 'while ...eak; }': ()
             409..430 'while ...eak; }': ()
             415..419 'true': bool
             420..430 '{ break; }': ()
             422..427 'break': !
             537..538 'x': u32
             546..564 '{ whil... {}; }': u32
+            548..561 'while true {}': !
+            548..561 'while true {}': ()
             548..561 'while true {}': ()
             554..558 'true': bool
             559..561 '{}': ()
             615..616 'x': u32
             624..651 '{ whil...; }; }': u32
+            626..648 'while ...urn; }': !
+            626..648 'while ...urn; }': ()
             626..648 'while ...urn; }': ()
             632..636 'true': bool
             637..648 '{ return; }': ()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 8b95110233f..6ea059065e9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -1267,6 +1267,8 @@ fn test() {
         "#,
         expect![[r#"
             10..59 '{     ...   } }': ()
+            16..57 'while ...     }': !
+            16..57 'while ...     }': ()
             16..57 'while ...     }': ()
             22..30 '{ true }': bool
             24..28 'true': bool
@@ -1978,3 +1980,23 @@ fn x(a: [i32; 4]) {
         "#,
     );
 }
+
+#[test]
+fn dont_unify_on_casts() {
+    // #15246
+    check_types(
+        r#"
+fn unify(_: [bool; 1]) {}
+fn casted(_: *const bool) {}
+fn default<T>() -> T { loop {} }
+
+fn test() {
+    let foo = default();
+      //^^^ [bool; 1]
+
+    casted(&foo as *const _);
+    unify(foo);
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index a0ff628435f..2ad7946c8ac 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3513,7 +3513,6 @@ fn func() {
     );
 }
 
-// FIXME
 #[test]
 fn castable_to() {
     check_infer(
@@ -3538,10 +3537,10 @@ fn func() {
             120..122 '{}': ()
             138..184 '{     ...0]>; }': ()
             148..149 'x': Box<[i32; 0]>
-            152..160 'Box::new': fn new<[{unknown}; 0]>([{unknown}; 0]) -> Box<[{unknown}; 0]>
-            152..164 'Box::new([])': Box<[{unknown}; 0]>
+            152..160 'Box::new': fn new<[i32; 0]>([i32; 0]) -> Box<[i32; 0]>
+            152..164 'Box::new([])': Box<[i32; 0]>
             152..181 'Box::n...2; 0]>': Box<[i32; 0]>
-            161..163 '[]': [{unknown}; 0]
+            161..163 '[]': [i32; 0]
         "#]],
     );
 }
@@ -3578,6 +3577,21 @@ fn f<T>(t: Ark<T>) {
 }
 
 #[test]
+fn ref_to_array_to_ptr_cast() {
+    check_types(
+        r#"
+fn default<T>() -> T { loop {} }
+fn foo() {
+    let arr = [default()];
+      //^^^ [i32; 1]
+    let ref_to_arr = &arr;
+    let casted = ref_to_arr as *const i32;
+}
+"#,
+    );
+}
+
+#[test]
 fn const_dependent_on_local() {
     check_types(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index cf8db2a5a24..0f2fb2c8118 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -12,9 +12,9 @@ use hir_ty::db::HirDatabase;
 use syntax::{ast, AstNode};
 
 use crate::{
-    Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam,
-    Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias, TypeParam, Union,
-    Variant,
+    Adt, AssocItem, Const, ConstParam, Enum, ExternCrateDecl, Field, Function, GenericParam, Impl,
+    LifetimeParam, Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias,
+    TypeParam, Union, Variant,
 };
 
 pub trait HasAttrs {
@@ -120,6 +120,39 @@ impl HasAttrs for AssocItem {
     }
 }
 
+impl HasAttrs for ExternCrateDecl {
+    fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
+        let def = AttrDefId::ExternCrateId(self.into());
+        db.attrs_with_owner(def)
+    }
+    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+        let crate_docs = self.resolved_crate(db)?.root_module().attrs(db).docs().map(String::from);
+        let def = AttrDefId::ExternCrateId(self.into());
+        let decl_docs = db.attrs(def).docs().map(String::from);
+        match (decl_docs, crate_docs) {
+            (None, None) => None,
+            (Some(decl_docs), None) => Some(decl_docs),
+            (None, Some(crate_docs)) => Some(crate_docs),
+            (Some(mut decl_docs), Some(crate_docs)) => {
+                decl_docs.push('\n');
+                decl_docs.push('\n');
+                decl_docs += &crate_docs;
+                Some(decl_docs)
+            }
+        }
+        .map(Documentation::new)
+    }
+    fn resolve_doc_path(
+        self,
+        db: &dyn HirDatabase,
+        link: &str,
+        ns: Option<Namespace>,
+    ) -> Option<ModuleDef> {
+        let def = AttrDefId::ExternCrateId(self.into());
+        resolve_doc_path(db, def, link, ns).map(ModuleDef::from)
+    }
+}
+
 /// Resolves the item `link` points to in the scope of `def`.
 fn resolve_doc_path(
     db: &dyn HirDatabase,
@@ -140,6 +173,7 @@ fn resolve_doc_path(
         AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
         AttrDefId::ImplId(it) => it.resolver(db.upcast()),
         AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
+        AttrDefId::UseId(it) => it.resolver(db.upcast()),
         AttrDefId::MacroId(it) => it.resolver(db.upcast()),
         AttrDefId::ExternCrateId(it) => it.resolver(db.upcast()),
         AttrDefId::GenericParamId(it) => match it {
diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs
index f3a0608944b..936581bfe32 100644
--- a/src/tools/rust-analyzer/crates/hir/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/db.rs
@@ -10,8 +10,3 @@ pub use hir_expand::db::{
     MacroExpandQuery, ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery,
 };
 pub use hir_ty::db::*;
-
-#[test]
-fn hir_database_is_object_safe() {
-    fn _assert_object_safe(_: &dyn HirDatabase) {}
-}
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 4de9c872ad6..9dfb98e459b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -18,9 +18,9 @@ use hir_ty::{
 };
 
 use crate::{
-    Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, Field, Function, GenericParam,
-    HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, Trait, TraitAlias,
-    TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
+    Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, Field,
+    Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct,
+    Trait, TraitAlias, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
 };
 
 impl HirDisplay for Function {
@@ -238,6 +238,18 @@ impl HirDisplay for Type {
     }
 }
 
+impl HirDisplay for ExternCrateDecl {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
+        f.write_str("extern crate ")?;
+        write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
+        if let Some(alias) = self.alias(f.db) {
+            write!(f, " as {alias}",)?;
+        }
+        Ok(())
+    }
+}
+
 impl HirDisplay for GenericParam {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         match self {
diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
index de23902199f..fc4bbffdb83 100644
--- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
@@ -15,7 +15,7 @@ use crate::{
 };
 
 macro_rules! from_id {
-    ($(($id:path, $ty:path)),*) => {$(
+    ($(($id:path, $ty:path)),* $(,)?) => {$(
         impl From<$id> for $ty {
             fn from(id: $id) -> $ty {
                 $ty { id }
@@ -47,7 +47,8 @@ from_id![
     (hir_def::TypeParamId, crate::TypeParam),
     (hir_def::ConstParamId, crate::ConstParam),
     (hir_def::LifetimeParamId, crate::LifetimeParam),
-    (hir_def::MacroId, crate::Macro)
+    (hir_def::MacroId, crate::Macro),
+    (hir_def::ExternCrateId, crate::ExternCrateDecl),
 ];
 
 impl From<AdtId> for Adt {
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 b46a3856d45..31cf8ba3364 100644
--- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs
@@ -11,9 +11,9 @@ use hir_expand::{HirFileId, InFile};
 use syntax::ast;
 
 use crate::{
-    db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
-    LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam,
-    Union, Variant,
+    db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
+    LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias,
+    TypeOrConstParam, Union, Variant,
 };
 
 pub trait HasSource {
@@ -207,3 +207,11 @@ impl HasSource for LocalSource {
         Some(self.source)
     }
 }
+
+impl HasSource for ExternCrateDecl {
+    type Ast = ast::ExternCrate;
+
+    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index b094bb7a068..bf041b61f2f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -48,14 +48,15 @@ use hir_def::{
     layout::{self, ReprOptions, TargetDataLayout},
     macro_id_to_def_id,
     nameres::{self, diagnostics::DefDiagnostic},
+    path::ImportAlias,
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
     src::HasSource as _,
-    AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
-    EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId,
-    LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId,
-    StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId,
-    UnionId,
+    AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId,
+    EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, HasModule, ImplId,
+    InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup,
+    MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
+    TypeOrConstParamId, TypeParamId, UnionId,
 };
 use hir_expand::{name::name, MacroCallKind};
 use hir_ty::{
@@ -200,9 +201,8 @@ impl Crate {
         db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id })
     }
 
-    pub fn root_module(self, db: &dyn HirDatabase) -> Module {
-        let def_map = db.crate_def_map(self.id);
-        Module { id: def_map.crate_root().into() }
+    pub fn root_module(self) -> Module {
+        Module { id: CrateRootModuleId::from(self.id).into() }
     }
 
     pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
@@ -247,7 +247,7 @@ impl Crate {
     /// Try to get the root URL of the documentation of a crate.
     pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
         // Look for #![doc(html_root_url = "...")]
-        let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
+        let attrs = db.attrs(AttrDefId::ModuleId(self.root_module().into()));
         let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
         doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
     }
@@ -2129,6 +2129,47 @@ impl HasVisibility for Function {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ExternCrateDecl {
+    pub(crate) id: ExternCrateId,
+}
+
+impl ExternCrateDecl {
+    pub fn module(self, db: &dyn HirDatabase) -> Module {
+        self.id.module(db.upcast()).into()
+    }
+
+    pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> {
+        db.extern_crate_decl_data(self.id).crate_id.map(Into::into)
+    }
+
+    pub fn name(self, db: &dyn HirDatabase) -> Name {
+        db.extern_crate_decl_data(self.id).name.clone()
+    }
+
+    pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> {
+        db.extern_crate_decl_data(self.id).alias.clone()
+    }
+
+    /// Returns the name under which this crate is made accessible, taking `_` into account.
+    pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> {
+        let extern_crate_decl_data = db.extern_crate_decl_data(self.id);
+        match &extern_crate_decl_data.alias {
+            Some(ImportAlias::Underscore) => None,
+            Some(ImportAlias::Alias(alias)) => Some(alias.clone()),
+            None => Some(extern_crate_decl_data.name.clone()),
+        }
+    }
+}
+
+impl HasVisibility for ExternCrateDecl {
+    fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
+        db.extern_crate_decl_data(self.id)
+            .visibility
+            .resolve(db.upcast(), &self.id.resolver(db.upcast()))
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InTypeConst {
     pub(crate) id: InTypeConstId,
 }
@@ -4715,6 +4756,12 @@ pub trait HasContainer {
     fn container(&self, db: &dyn HirDatabase) -> ItemContainer;
 }
 
+impl HasContainer for ExternCrateDecl {
+    fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+        container_id_to_hir(self.id.lookup(db.upcast()).container.into())
+    }
+}
+
 impl HasContainer for Module {
     fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
         // FIXME: handle block expressions as modules (their parent is in a different DefMap)
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 39a3e1c4489..e99d2984c36 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -15,11 +15,7 @@ use hir_def::{
     type_ref::Mutability,
     AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
 };
-use hir_expand::{
-    db::ExpandDatabase,
-    name::{known, AsName},
-    ExpansionInfo, MacroCallId,
-};
+use hir_expand::{db::ExpandDatabase, name::AsName, ExpansionInfo, MacroCallId};
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{smallvec, SmallVec};
@@ -439,10 +435,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_path(path)
     }
 
-    pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
-        self.imp.resolve_extern_crate(extern_crate)
-    }
-
     pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
         self.imp.resolve_variant(record_lit).map(VariantDef::from)
     }
@@ -1242,18 +1234,6 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(path.syntax())?.resolve_path(self.db, path)
     }
 
-    fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
-        let krate = self.scope(extern_crate.syntax())?.krate();
-        let name = extern_crate.name_ref()?.as_name();
-        if name == known::SELF_PARAM {
-            return Some(krate);
-        }
-        krate
-            .dependencies(self.db)
-            .into_iter()
-            .find_map(|dep| (dep.name == name).then_some(dep.krate))
-    }
-
     fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
         self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
     }
@@ -1603,6 +1583,7 @@ to_def_impls![
     (crate::Local, ast::SelfParam, self_param_to_def),
     (crate::Label, ast::Label, label_to_def),
     (crate::Adt, ast::Adt, adt_to_def),
+    (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def),
 ];
 
 fn find_root(node: &SyntaxNode) -> SyntaxNode {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index b971ca62387..aabda365560 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -93,9 +93,9 @@ use hir_def::{
         DynMap,
     },
     hir::{BindingId, LabelId},
-    AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId,
-    GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId,
-    TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
+    AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId,
+    FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId,
+    StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, VariantId,
 };
 use hir_expand::{attrs::AttrId, name::AsName, HirFileId, MacroCallId};
 use rustc_hash::FxHashMap;
@@ -203,6 +203,16 @@ impl SourceToDefCtx<'_, '_> {
     ) -> Option<EnumVariantId> {
         self.to_def(src, keys::VARIANT)
     }
+    pub(super) fn extern_crate_to_def(
+        &mut self,
+        src: InFile<ast::ExternCrate>,
+    ) -> Option<ExternCrateId> {
+        self.to_def(src, keys::EXTERN_CRATE)
+    }
+    #[allow(dead_code)]
+    pub(super) fn use_to_def(&mut self, src: InFile<ast::Use>) -> Option<UseId> {
+        self.to_def(src, keys::USE)
+    }
     pub(super) fn adt_to_def(
         &mut self,
         InFile { file_id, value }: InFile<ast::Adt>,
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 d07c6372628..6aca716bb60 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
@@ -3,7 +3,10 @@ use syntax::ast::{self, make, AstNode};
 
 use crate::{
     assist_context::{AssistContext, Assists},
-    utils::{add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, DefaultMethods},
+    utils::{
+        add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, DefaultMethods,
+        IgnoreAssocItems,
+    },
     AssistId, AssistKind,
 };
 
@@ -43,6 +46,7 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext<'_
         acc,
         ctx,
         DefaultMethods::No,
+        IgnoreAssocItems::DocHiddenAttrPresent,
         "add_impl_missing_members",
         "Implement missing members",
     )
@@ -87,6 +91,7 @@ pub(crate) fn add_missing_default_members(
         acc,
         ctx,
         DefaultMethods::Only,
+        IgnoreAssocItems::DocHiddenAttrPresent,
         "add_impl_default_members",
         "Implement default members",
     )
@@ -96,6 +101,7 @@ fn add_missing_impl_members_inner(
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
     mode: DefaultMethods,
+    ignore_items: IgnoreAssocItems,
     assist_id: &'static str,
     label: &'static str,
 ) -> Option<()> {
@@ -115,10 +121,21 @@ fn add_missing_impl_members_inner(
     let trait_ref = impl_.trait_ref(ctx.db())?;
     let trait_ = trait_ref.trait_();
 
+    let mut ign_item = ignore_items;
+
+    if let IgnoreAssocItems::DocHiddenAttrPresent = ignore_items {
+        // Relax condition for local crates.
+        let db = ctx.db();
+        if trait_.module(db).krate().origin(db).is_local() {
+            ign_item = IgnoreAssocItems::No;
+        }
+    }
+
     let missing_items = filter_assoc_items(
         &ctx.sema,
         &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def),
         mode,
+        ign_item,
     );
 
     if missing_items.is_empty() {
@@ -1966,4 +1983,169 @@ impl AnotherTrait<i32> for () {
 "#,
         );
     }
+
+    #[test]
+    fn doc_hidden_default_impls_ignored() {
+        // doc(hidden) attr is ignored trait and impl both belong to the local crate.
+        check_assist(
+            add_missing_default_members,
+            r#"
+struct Foo;
+trait Trait {
+    #[doc(hidden)]
+    fn func_with_default_impl() -> u32 {
+        42
+    }
+    fn another_default_impl() -> u32 {
+        43
+    }
+}
+impl Tra$0it for Foo {}"#,
+            r#"
+struct Foo;
+trait Trait {
+    #[doc(hidden)]
+    fn func_with_default_impl() -> u32 {
+        42
+    }
+    fn another_default_impl() -> u32 {
+        43
+    }
+}
+impl Trait for Foo {
+    $0fn func_with_default_impl() -> u32 {
+        42
+    }
+
+    fn another_default_impl() -> u32 {
+        43
+    }
+}"#,
+        )
+    }
+
+    #[test]
+    fn doc_hidden_default_impls_lang_crates() {
+        // Not applicable because Eq has a single method and this has a #[doc(hidden)] attr set.
+        check_assist_not_applicable(
+            add_missing_default_members,
+            r#"
+//- minicore: eq
+use core::cmp::Eq;
+struct Foo;
+impl E$0q for Foo { /* $0 */ }
+"#,
+        )
+    }
+
+    #[test]
+    fn doc_hidden_default_impls_lib_crates() {
+        check_assist(
+            add_missing_default_members,
+            r#"
+    //- /main.rs crate:a deps:b
+    struct B;
+    impl b::Exte$0rnTrait for B {}
+    //- /lib.rs crate:b new_source_root:library
+    pub trait ExternTrait {
+        #[doc(hidden)]
+        fn hidden_default() -> Option<()> {
+            todo!()
+        }
+
+        fn unhidden_default() -> Option<()> {
+            todo!()
+        }
+
+        fn unhidden_nondefault() -> Option<()>;
+    }
+                "#,
+            r#"
+    struct B;
+    impl b::ExternTrait for B {
+        $0fn unhidden_default() -> Option<()> {
+            todo!()
+        }
+    }
+    "#,
+        )
+    }
+
+    #[test]
+    fn doc_hidden_default_impls_local_crates() {
+        check_assist(
+            add_missing_default_members,
+            r#"
+trait LocalTrait {
+    #[doc(hidden)]
+    fn no_skip_default() -> Option<()> {
+        todo!()
+    }
+    fn no_skip_default_2() -> Option<()> {
+        todo!()
+    }
+}
+
+struct B;
+impl Loc$0alTrait for B {}
+            "#,
+            r#"
+trait LocalTrait {
+    #[doc(hidden)]
+    fn no_skip_default() -> Option<()> {
+        todo!()
+    }
+    fn no_skip_default_2() -> Option<()> {
+        todo!()
+    }
+}
+
+struct B;
+impl LocalTrait for B {
+    $0fn no_skip_default() -> Option<()> {
+        todo!()
+    }
+
+    fn no_skip_default_2() -> Option<()> {
+        todo!()
+    }
+}
+            "#,
+        )
+    }
+
+    #[test]
+    fn doc_hidden_default_impls_workspace_crates() {
+        check_assist(
+            add_missing_default_members,
+            r#"
+//- /lib.rs crate:b new_source_root:local
+trait LocalTrait {
+    #[doc(hidden)]
+    fn no_skip_default() -> Option<()> {
+        todo!()
+    }
+    fn no_skip_default_2() -> Option<()> {
+        todo!()
+    }
+}
+
+//- /main.rs crate:a deps:b
+struct B;
+impl b::Loc$0alTrait for B {}
+            "#,
+            r#"
+struct B;
+impl b::LocalTrait for B {
+    $0fn no_skip_default() -> Option<()> {
+        todo!()
+    }
+
+    fn no_skip_default_2() -> Option<()> {
+        todo!()
+    }
+}
+            "#,
+        )
+    }
 }
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 ac0b74ee8e7..3b162d7c4d8 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
@@ -37,9 +37,9 @@ use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let match_expr = ctx.find_node_at_offset_with_descend::<ast::MatchExpr>()?;
     let match_arm_list = match_expr.match_arm_list()?;
-    let target_range = ctx.sema.original_range(match_expr.syntax()).range;
+    let arm_list_range = ctx.sema.original_range_opt(match_arm_list.syntax())?;
 
-    if let None = cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list) {
+    if cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list).is_none() {
         let arm_list_range = ctx.sema.original_range(match_arm_list.syntax()).range;
         let cursor_in_range = arm_list_range.contains_range(ctx.selection_trimmed());
         if cursor_in_range {
@@ -198,7 +198,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
     acc.add(
         AssistId("add_missing_match_arms", AssistKind::QuickFix),
         "Fill match arms",
-        target_range,
+        ctx.sema.original_range(match_expr.syntax()).range,
         |edit| {
             let new_match_arm_list = match_arm_list.clone_for_update();
 
@@ -262,9 +262,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             // Just replace the element that the original range came from
             let old_place = {
                 // Find the original element
-                let old_file_range = ctx.sema.original_range(match_arm_list.syntax());
-                let file = ctx.sema.parse(old_file_range.file_id);
-                let old_place = file.syntax().covering_element(old_file_range.range);
+                let file = ctx.sema.parse(arm_list_range.file_id);
+                let old_place = file.syntax().covering_element(arm_list_range.range);
 
                 // Make `old_place` mut
                 match old_place {
@@ -1922,4 +1921,24 @@ fn foo(t: E) {
 }"#,
         );
     }
+
+    #[test]
+    fn not_applicable_when_match_arm_list_cannot_be_upmapped() {
+        check_assist_not_applicable(
+            add_missing_match_arms,
+            r#"
+macro_rules! foo {
+    ($($t:tt)*) => {
+        $($t)* {}
+    }
+}
+
+enum E { A }
+
+fn main() {
+    foo!(match E::A$0);
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
index acf82e4b257..36f68d17677 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs
@@ -42,7 +42,9 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     let name_ref = ast::NameRef::cast(ident.parent()?)?;
     let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
         NameRefClass::Definition(def) => def,
-        NameRefClass::FieldShorthand { .. } => return None,
+        NameRefClass::FieldShorthand { .. } | NameRefClass::ExternCrateShorthand { .. } => {
+            return None
+        }
     };
     let fun = match def {
         Definition::Function(it) => it,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
index b1b0f587cd3..6a5b11f5425 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
@@ -1,3 +1,6 @@
+use hir::Semantics;
+use ide_db::RootDatabase;
+use stdx::format_to;
 use syntax::ast::{self, AstNode};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -24,6 +27,7 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
 ) -> Option<()> {
+    use ArmBodyExpression::*;
     let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
     let match_arm_list = match_expr.match_arm_list()?;
     let mut arms = match_arm_list.arms();
@@ -33,21 +37,20 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
         cov_mark::hit!(non_two_arm_match);
         return None;
     }
-    let first_arm_expr = first_arm.expr();
-    let second_arm_expr = second_arm.expr();
+    let first_arm_expr = first_arm.expr()?;
+    let second_arm_expr = second_arm.expr()?;
+    let first_arm_body = is_bool_literal_expr(&ctx.sema, &first_arm_expr)?;
+    let second_arm_body = is_bool_literal_expr(&ctx.sema, &second_arm_expr)?;
 
-    let invert_matches = if is_bool_literal_expr(&first_arm_expr, true)
-        && is_bool_literal_expr(&second_arm_expr, false)
-    {
-        false
-    } else if is_bool_literal_expr(&first_arm_expr, false)
-        && is_bool_literal_expr(&second_arm_expr, true)
-    {
-        true
-    } else {
+    if !matches!(
+        (&first_arm_body, &second_arm_body),
+        (Literal(true), Literal(false))
+            | (Literal(false), Literal(true))
+            | (Expression(_), Literal(false))
+    ) {
         cov_mark::hit!(non_invert_bool_literal_arms);
         return None;
-    };
+    }
 
     let target_range = ctx.sema.original_range(match_expr.syntax()).range;
     let expr = match_expr.expr()?;
@@ -59,28 +62,55 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
         |builder| {
             let mut arm_str = String::new();
             if let Some(pat) = &first_arm.pat() {
-                arm_str += &pat.to_string();
+                format_to!(arm_str, "{pat}");
             }
             if let Some(guard) = &first_arm.guard() {
                 arm_str += &format!(" {guard}");
             }
-            if invert_matches {
-                builder.replace(target_range, format!("!matches!({expr}, {arm_str})"));
-            } else {
-                builder.replace(target_range, format!("matches!({expr}, {arm_str})"));
-            }
+
+            let replace_with = match (first_arm_body, second_arm_body) {
+                (Literal(true), Literal(false)) => {
+                    format!("matches!({expr}, {arm_str})")
+                }
+                (Literal(false), Literal(true)) => {
+                    format!("!matches!({expr}, {arm_str})")
+                }
+                (Expression(body_expr), Literal(false)) => {
+                    arm_str.push_str(match &first_arm.guard() {
+                        Some(_) => " && ",
+                        _ => " if ",
+                    });
+                    format!("matches!({expr}, {arm_str}{body_expr})")
+                }
+                _ => {
+                    unreachable!()
+                }
+            };
+            builder.replace(target_range, replace_with);
         },
     )
 }
 
-fn is_bool_literal_expr(expr: &Option<ast::Expr>, expect_bool: bool) -> bool {
-    if let Some(ast::Expr::Literal(lit)) = expr {
+enum ArmBodyExpression {
+    Literal(bool),
+    Expression(ast::Expr),
+}
+
+fn is_bool_literal_expr(
+    sema: &Semantics<'_, RootDatabase>,
+    expr: &ast::Expr,
+) -> Option<ArmBodyExpression> {
+    if let ast::Expr::Literal(lit) = expr {
         if let ast::LiteralKind::Bool(b) = lit.kind() {
-            return b == expect_bool;
+            return Some(ArmBodyExpression::Literal(b));
         }
     }
 
-    return false;
+    if !sema.type_of_expr(expr)?.original.is_bool() {
+        return None;
+    }
+
+    Some(ArmBodyExpression::Expression(expr.clone()))
 }
 
 #[cfg(test)]
@@ -122,21 +152,6 @@ fn foo(a: Option<u32>) -> bool {
     }
 
     #[test]
-    fn not_applicable_non_bool_literal_arms() {
-        cov_mark::check!(non_invert_bool_literal_arms);
-        check_assist_not_applicable(
-            convert_two_arm_bool_match_to_matches_macro,
-            r#"
-fn foo(a: Option<u32>) -> bool {
-    match a$0 {
-        Some(val) => val == 3,
-        _ => false
-    }
-}
-        "#,
-        );
-    }
-    #[test]
     fn not_applicable_both_false_arms() {
         cov_mark::check!(non_invert_bool_literal_arms);
         check_assist_not_applicable(
@@ -291,4 +306,40 @@ fn main() {
     }",
         );
     }
+
+    #[test]
+    fn convert_non_literal_bool() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn main() {
+    match 0$0 {
+        a @ 0..15 => a == 0,
+        _ => false,
+    }
+}
+"#,
+            r#"
+fn main() {
+    matches!(0, a @ 0..15 if a == 0)
+}
+"#,
+        );
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn main() {
+    match 0$0 {
+        a @ 0..15 if thing() => a == 0,
+        _ => false,
+    }
+}
+"#,
+            r#"
+fn main() {
+    matches!(0, a @ 0..15 if thing() && a == 0)
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index ea71d165e6a..f30ca2552d3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -114,7 +114,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
     let usages = ctx.sema.to_def(&ident_pat).map(|def| {
         Definition::Local(def)
             .usages(&ctx.sema)
-            .in_scope(SearchScope::single_file(ctx.file_id()))
+            .in_scope(&SearchScope::single_file(ctx.file_id()))
             .all()
     });
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
index 3aff5c9144f..9beb616d99b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -120,7 +120,7 @@ fn find_parent_and_path(
 
 fn def_is_referenced_in(def: Definition, ctx: &AssistContext<'_>) -> bool {
     let search_scope = SearchScope::single_file(ctx.file_id());
-    def.usages(&ctx.sema).in_scope(search_scope).at_least_one()
+    def.usages(&ctx.sema).in_scope(&search_scope).at_least_one()
 }
 
 #[derive(Debug, Clone)]
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 e9db38aca0f..b8b781ea48d 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
@@ -384,7 +384,7 @@ impl LocalUsages {
         Self(
             Definition::Local(var)
                 .usages(&ctx.sema)
-                .in_scope(SearchScope::single_file(ctx.file_id()))
+                .in_scope(&SearchScope::single_file(ctx.file_id()))
                 .all(),
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
index de37f5f130f..6839c5820dc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
@@ -478,7 +478,7 @@ impl Module {
         let selection_range = ctx.selection_trimmed();
         let curr_file_id = ctx.file_id();
         let search_scope = SearchScope::single_file(curr_file_id);
-        let usage_res = def.usages(&ctx.sema).in_scope(search_scope).all();
+        let usage_res = def.usages(&ctx.sema).in_scope(&search_scope).all();
         let file = ctx.sema.parse(curr_file_id);
 
         let mut exists_inside_sel = false;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
index 860372941f7..7e4f140a28f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
@@ -15,6 +15,7 @@ use crate::{
 // Generates default implementation from new method.
 //
 // ```
+// # //- minicore: default
 // struct Example { _inner: () }
 //
 // impl Example {
@@ -54,6 +55,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
     }
 
     let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
+    let self_ty = impl_.self_ty()?;
     if is_default_implemented(ctx, &impl_) {
         cov_mark::hit!(default_block_is_already_present);
         cov_mark::hit!(struct_in_module_with_default);
@@ -70,15 +72,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
             let default_code = "    fn default() -> Self {
         Self::new()
     }";
-            let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code);
+            let code = generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code);
             builder.insert(insert_location.end(), code);
         },
     )
 }
 
 // FIXME: based on from utils::generate_impl_text_inner
-fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
-    let impl_ty = impl_.self_ty().unwrap();
+fn generate_trait_impl_text_from_impl(
+    impl_: &ast::Impl,
+    self_ty: ast::Type,
+    trait_text: &str,
+    code: &str,
+) -> String {
     let generic_params = impl_.generic_param_list().map(|generic_params| {
         let lifetime_params =
             generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
@@ -109,7 +115,7 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code:
     if let Some(generic_params) = &generic_params {
         format_to!(buf, "{generic_params}")
     }
-    format_to!(buf, " {trait_text} for {impl_ty}");
+    format_to!(buf, " {trait_text} for {self_ty}");
 
     match impl_.where_clause() {
         Some(where_clause) => {
@@ -136,7 +142,9 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool {
     let default = FamousDefs(&ctx.sema, krate).core_default_Default();
     let default_trait = match default {
         Some(value) => value,
-        None => return false,
+        // Return `true` to avoid providing the assist because it makes no sense
+        // to impl `Default` when it's missing.
+        None => return true,
     };
 
     ty.impls_trait(db, default_trait, &[])
@@ -480,6 +488,7 @@ impl Example {
         check_assist_not_applicable(
             generate_default_from_new,
             r#"
+//- minicore: default
 struct Example { _inner: () }
 
 impl Example {
@@ -655,4 +664,23 @@ mod test {
 "#,
         );
     }
+
+    #[test]
+    fn not_applicable_when_default_lang_item_is_missing() {
+        check_assist_not_applicable(
+            generate_default_from_new,
+            r#"
+struct S;
+impl S {
+    fn new$0() -> Self {}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_for_missing_self_ty() {
+        // Regression test for #15398.
+        check_assist_not_applicable(generate_default_from_new, "impl { fn new$0() -> Self {} }");
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 185f47184d4..f4fa6a74c6b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -213,7 +213,9 @@ impl Struct {
             //     continue;
             // }
             let signature = delegee.signature(db);
-            let delegate = generate_impl(ctx, self, &field.ty, &field.name, delegee);
+            let Some(delegate) = generate_impl(ctx, self, &field.ty, &field.name, delegee) else {
+                continue;
+            };
 
             acc.add_group(
                 &GroupLabel("Delegate trait impl for field...".to_owned()),
@@ -237,7 +239,7 @@ fn generate_impl(
     field_ty: &ast::Type,
     field_name: &String,
     delegee: &Delegee,
-) -> ast::Impl {
+) -> Option<ast::Impl> {
     let delegate: ast::Impl;
     let source: ast::Impl;
     let genpar: Option<ast::GenericParamList>;
@@ -247,7 +249,7 @@ fn generate_impl(
 
     match delegee {
         Delegee::Bound(delegee) => {
-            let in_file = ctx.sema.source(delegee.0.to_owned()).unwrap();
+            let in_file = ctx.sema.source(delegee.0.to_owned())?;
             let source: ast::Trait = in_file.value;
 
             delegate = make::impl_trait(
@@ -293,15 +295,15 @@ fn generate_impl(
                 None => {}
             };
 
-            let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap();
-            let source = ctx.sema.scope(source.syntax()).unwrap();
+            let target = ctx.sema.scope(strukt.strukt.syntax())?;
+            let source = ctx.sema.scope(source.syntax())?;
 
             let transform =
                 PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone());
             transform.apply(&delegate.syntax());
         }
         Delegee::Impls(delegee) => {
-            let in_file = ctx.sema.source(delegee.1.to_owned()).unwrap();
+            let in_file = ctx.sema.source(delegee.1.to_owned())?;
             source = in_file.value;
             delegate = make::impl_trait(
                 delegee.0.is_unsafe(db),
@@ -341,8 +343,8 @@ fn generate_impl(
                     }
                 });
 
-            let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap();
-            let source = ctx.sema.scope(source.syntax()).unwrap();
+            let target = ctx.sema.scope(strukt.strukt.syntax())?;
+            let source = ctx.sema.scope(source.syntax())?;
 
             let transform =
                 PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone());
@@ -350,7 +352,7 @@ fn generate_impl(
         }
     }
 
-    delegate
+    Some(delegate)
 }
 
 fn process_assoc_item(
@@ -359,19 +361,19 @@ fn process_assoc_item(
     base_name: &str,
 ) -> Option<ast::AssocItem> {
     match item {
-        AssocItem::Const(c) => Some(const_assoc_item(c, qual_path_ty)),
-        AssocItem::Fn(f) => Some(func_assoc_item(f, qual_path_ty, base_name)),
+        AssocItem::Const(c) => const_assoc_item(c, qual_path_ty),
+        AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name),
         AssocItem::MacroCall(_) => {
             // FIXME : Handle MacroCall case.
-            // return Some(macro_assoc_item(mac, qual_path_ty));
+            // macro_assoc_item(mac, qual_path_ty)
             None
         }
-        AssocItem::TypeAlias(ta) => Some(ty_assoc_item(ta, qual_path_ty)),
+        AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty),
     }
 }
 
-fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> AssocItem {
-    let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str());
+fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> {
+    let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
 
     // We want rhs of the const assignment to be a qualified path
     // The general case for const assigment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`)
@@ -380,19 +382,19 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> AssocI
     // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it.
     // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap());
     let qualpath = qualpath(qual_path_ty, path_expr_segment);
-    let inner = make::item_const(
-        item.visibility(),
-        item.name().unwrap(),
-        item.ty().unwrap(),
-        make::expr_path(qualpath),
-    )
-    .clone_for_update();
+    let inner =
+        make::item_const(item.visibility(), item.name()?, item.ty()?, make::expr_path(qualpath))
+            .clone_for_update();
 
-    AssocItem::Const(inner)
+    Some(AssocItem::Const(inner))
 }
 
-fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -> AssocItem {
-    let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str());
+fn func_assoc_item(
+    item: syntax::ast::Fn,
+    qual_path_ty: Path,
+    base_name: &str,
+) -> Option<AssocItem> {
+    let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
     let qualpath = qualpath(qual_path_ty, path_expr_segment);
 
     let call = match item.param_list() {
@@ -415,7 +417,7 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -
                 if param_count > 0 {
                     // Add SelfParam and a TOKEN::COMMA
                     ted::insert_all(
-                        Position::after(args.l_paren_token().unwrap()),
+                        Position::after(args.l_paren_token()?),
                         vec![
                             NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
                             NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)),
@@ -425,7 +427,7 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -
                 } else {
                     // Add SelfParam only
                     ted::insert(
-                        Position::after(args.l_paren_token().unwrap()),
+                        Position::after(args.l_paren_token()?),
                         NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()),
                     );
                 }
@@ -444,10 +446,10 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -
     let body = make::block_expr(vec![], Some(call)).clone_for_update();
     let func = make::fn_(
         item.visibility(),
-        item.name().unwrap(),
+        item.name()?,
         item.generic_param_list(),
         item.where_clause(),
-        item.param_list().unwrap(),
+        item.param_list()?,
         body,
         item.ret_type(),
         item.async_token().is_some(),
@@ -456,14 +458,14 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -
     )
     .clone_for_update();
 
-    AssocItem::Fn(func.indent(edit::IndentLevel(1)).clone_for_update())
+    Some(AssocItem::Fn(func.indent(edit::IndentLevel(1)).clone_for_update()))
 }
 
-fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> AssocItem {
-    let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str());
+fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> {
+    let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str());
     let qualpath = qualpath(qual_path_ty, path_expr_segment);
     let ty = make::ty_path(qualpath);
-    let ident = item.name().unwrap().to_string();
+    let ident = item.name()?.to_string();
 
     let alias = make::ty_alias(
         ident.as_str(),
@@ -474,7 +476,7 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> AssocItem
     )
     .clone_for_update();
 
-    AssocItem::TypeAlias(alias)
+    Some(AssocItem::TypeAlias(alias))
 }
 
 fn qualpath(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path {
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 8085572497a..5b13e01b133 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
@@ -1878,7 +1878,6 @@ where
 
     #[test]
     fn add_function_with_fn_arg() {
-        // FIXME: The argument in `bar` is wrong.
         check_assist(
             generate_function,
             r"
@@ -1899,7 +1898,7 @@ fn foo() {
     bar(Baz::new);
 }
 
-fn bar(new: fn) ${0:-> _} {
+fn bar(new: fn() -> Baz) ${0:-> _} {
     todo!()
 }
 ",
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 67036029f5e..ffab58509b1 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
@@ -80,7 +80,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
     let is_recursive_fn = usages
         .clone()
-        .in_scope(SearchScope::file_range(FileRange {
+        .in_scope(&SearchScope::file_range(FileRange {
             file_id: def_file,
             range: func_body.syntax().text_range(),
         }))
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
index 5aa8e56f562..5d956b1a5e8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
@@ -37,11 +37,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?;
     let expanded = insert_ws_into(ctx.sema.expand(&unexpanded)?.clone_for_update());
-
     let text_range = unexpanded.syntax().text_range();
 
     acc.add(
-        AssistId("inline_macro", AssistKind::RefactorRewrite),
+        AssistId("inline_macro", AssistKind::RefactorInline),
         format!("Inline macro"),
         text_range,
         |builder| builder.replace(text_range, expanded.to_string()),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
index e1849eb71d5..22d536b5afc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs
@@ -82,17 +82,19 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         return None;
     }
 
-    let usages =
-        Definition::Const(def).usages(&ctx.sema).in_scope(SearchScope::file_range(FileRange {
-            file_id: ctx.file_id(),
-            range: parent_fn.syntax().text_range(),
-        }));
-
     acc.add(
         AssistId("move_const_to_impl", crate::AssistKind::RefactorRewrite),
         "Move const to impl block",
         const_.syntax().text_range(),
         |builder| {
+            let usages = Definition::Const(def)
+                .usages(&ctx.sema)
+                .in_scope(&SearchScope::file_range(FileRange {
+                    file_id: ctx.file_id(),
+                    range: parent_fn.syntax().text_range(),
+                }))
+                .all();
+
             let range_to_delete = match const_.syntax().next_sibling_or_token() {
                 Some(s) if matches!(s.kind(), SyntaxKind::WHITESPACE) => {
                     // Remove following whitespaces too.
@@ -103,7 +105,7 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             builder.delete(range_to_delete);
 
             let const_ref = format!("Self::{}", name.display(ctx.db()));
-            for range in usages.all().file_ranges().map(|it| it.range) {
+            for range in usages.file_ranges().map(|it| it.range) {
                 builder.replace(range, const_ref.clone());
             }
 
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
new file mode 100644
index 00000000000..dd4839351fb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -0,0 +1,739 @@
+use std::collections::{hash_map::Entry, HashMap};
+
+use hir::{InFile, Module, ModuleSource};
+use ide_db::{
+    base_db::FileRange,
+    defs::Definition,
+    search::{FileReference, ReferenceCategory, SearchScope},
+    RootDatabase,
+};
+use syntax::{ast, AstNode};
+use text_edit::TextRange;
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: remove_unused_imports
+//
+// Removes any use statements in the current selection that are unused.
+//
+// ```
+// struct X();
+// mod foo {
+//     use super::X$0;
+// }
+// ```
+// ->
+// ```
+// struct X();
+// mod foo {
+// }
+// ```
+pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    // First, grab the uses that intersect with the current selection.
+    let selected_el = match ctx.covering_element() {
+        syntax::NodeOrToken::Node(n) => n,
+        syntax::NodeOrToken::Token(t) => t.parent()?,
+    };
+
+    // This applies to all uses that are selected, or are ancestors of our selection.
+    let uses_up = selected_el.ancestors().skip(1).filter_map(ast::Use::cast);
+    let uses_down = selected_el
+        .descendants()
+        .filter(|x| x.text_range().intersect(ctx.selection_trimmed()).is_some())
+        .filter_map(ast::Use::cast);
+    let uses = uses_up.chain(uses_down).collect::<Vec<_>>();
+
+    // Maps use nodes to the scope that we should search through to find
+    let mut search_scopes = HashMap::<Module, Vec<SearchScope>>::new();
+
+    // iterator over all unused use trees
+    let mut unused = uses
+        .into_iter()
+        .flat_map(|u| u.syntax().descendants().filter_map(ast::UseTree::cast))
+        .filter(|u| u.use_tree_list().is_none())
+        .filter_map(|u| {
+            // Find any uses trees that are unused
+
+            let use_module = ctx.sema.scope(&u.syntax()).map(|s| s.module())?;
+            let scope = match search_scopes.entry(use_module) {
+                Entry::Occupied(o) => o.into_mut(),
+                Entry::Vacant(v) => v.insert(module_search_scope(ctx.db(), use_module)),
+            };
+
+            // Gets the path associated with this use tree. If there isn't one, then ignore this use tree.
+            let path = if let Some(path) = u.path() {
+                path
+            } else if u.star_token().is_some() {
+                // This case maps to the situation where the * token is braced.
+                // In this case, the parent use tree's path is the one we should use to resolve the glob.
+                match u.syntax().ancestors().skip(1).find_map(ast::UseTree::cast) {
+                    Some(parent_u) if parent_u.path().is_some() => parent_u.path().unwrap(),
+                    _ => return None,
+                }
+            } else {
+                return None;
+            };
+
+            // Get the actual definition associated with this use item.
+            let res = match ctx.sema.resolve_path(&path) {
+                Some(x) => x,
+                None => {
+                    return None;
+                }
+            };
+
+            let def = match res {
+                hir::PathResolution::Def(d) => Definition::from(d),
+                _ => return None,
+            };
+
+            if u.star_token().is_some() {
+                // Check if any of the children of this module are used
+                let def_mod = match def {
+                    Definition::Module(module) => module,
+                    _ => return None,
+                };
+
+                if !def_mod
+                    .scope(ctx.db(), Some(use_module))
+                    .iter()
+                    .filter_map(|(_, x)| match x {
+                        hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)),
+                        _ => None,
+                    })
+                    .any(|d| used_once_in_scope(ctx, d, scope))
+                {
+                    return Some(u);
+                }
+            } else if let Definition::Trait(ref t) = def {
+                // If the trait or any item is used.
+                if !std::iter::once(def)
+                    .chain(t.items(ctx.db()).into_iter().map(Definition::from))
+                    .any(|d| used_once_in_scope(ctx, d, scope))
+                {
+                    return Some(u);
+                }
+            } else {
+                if !used_once_in_scope(ctx, def, &scope) {
+                    return Some(u);
+                }
+            }
+
+            None
+        })
+        .peekable();
+
+    // Peek so we terminate early if an unused use is found. Only do the rest of the work if the user selects the assist.
+    if unused.peek().is_some() {
+        acc.add(
+            AssistId("remove_unused_imports", AssistKind::QuickFix),
+            "Remove all the unused imports",
+            selected_el.text_range(),
+            |builder| {
+                let unused: Vec<ast::UseTree> = unused.map(|x| builder.make_mut(x)).collect();
+                for node in unused {
+                    node.remove_recursive();
+                }
+            },
+        )
+    } else {
+        None
+    }
+}
+
+fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<SearchScope>) -> bool {
+    let mut found = false;
+
+    for scope in scopes {
+        let mut search_non_import = |_, r: FileReference| {
+            // The import itself is a use; we must skip that.
+            if r.category != Some(ReferenceCategory::Import) {
+                found = true;
+                true
+            } else {
+                false
+            }
+        };
+        def.usages(&ctx.sema).in_scope(scope).search(&mut search_non_import);
+        if found {
+            break;
+        }
+    }
+
+    found
+}
+
+/// Build a search scope spanning the given module but none of its submodules.
+fn module_search_scope(db: &RootDatabase, module: hir::Module) -> Vec<SearchScope> {
+    let (file_id, range) = {
+        let InFile { file_id, value } = module.definition_source(db);
+        if let Some((file_id, call_source)) = file_id.original_call_node(db) {
+            (file_id, Some(call_source.text_range()))
+        } else {
+            (
+                file_id.original_file(db),
+                match value {
+                    ModuleSource::SourceFile(_) => None,
+                    ModuleSource::Module(it) => Some(it.syntax().text_range()),
+                    ModuleSource::BlockExpr(it) => Some(it.syntax().text_range()),
+                },
+            )
+        }
+    };
+
+    fn split_at_subrange(first: TextRange, second: TextRange) -> (TextRange, Option<TextRange>) {
+        let intersect = first.intersect(second);
+        if let Some(intersect) = intersect {
+            let start_range = TextRange::new(first.start(), intersect.start());
+
+            if intersect.end() < first.end() {
+                (start_range, Some(TextRange::new(intersect.end(), first.end())))
+            } else {
+                (start_range, None)
+            }
+        } else {
+            (first, None)
+        }
+    }
+
+    let mut scopes = Vec::new();
+    if let Some(range) = range {
+        let mut ranges = vec![range];
+
+        for child in module.children(db) {
+            let rng = match child.definition_source(db).value {
+                ModuleSource::SourceFile(_) => continue,
+                ModuleSource::Module(it) => it.syntax().text_range(),
+                ModuleSource::BlockExpr(_) => continue,
+            };
+            let mut new_ranges = Vec::new();
+            for old_range in ranges.iter_mut() {
+                let split = split_at_subrange(old_range.clone(), rng);
+                *old_range = split.0;
+                new_ranges.extend(split.1);
+            }
+
+            ranges.append(&mut new_ranges);
+        }
+
+        for range in ranges {
+            scopes.push(SearchScope::file_range(FileRange { file_id, range }));
+        }
+    } else {
+        scopes.push(SearchScope::single_file(file_id));
+    }
+
+    scopes
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn remove_unused() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+    $0use super::X;
+    use super::Y;$0
+}
+"#,
+            r#"
+struct X();
+struct Y();
+mod z {
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unused_is_precise() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+mod z {
+$0use super::X;$0
+
+fn w() {
+    struct X();
+    let x = X();
+}
+}
+"#,
+            r#"
+struct X();
+mod z {
+
+fn w() {
+    struct X();
+    let x = X();
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_name_use_is_use() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+struct X();
+trait Y {
+    fn f();
+}
+
+impl Y for X {
+    fn f() {}
+}
+mod z {
+$0use super::X;
+use super::Y;$0
+
+fn w() {
+    X::f();
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_item_use_is_use() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+struct X();
+trait Y {
+    fn f(self);
+}
+
+impl Y for X {
+    fn f(self) {}
+}
+mod z {
+$0use super::X;
+use super::Y;$0
+
+fn w() {
+    let x = X();
+    x.f();
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn ranamed_trait_item_use_is_use() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+struct X();
+trait Y {
+    fn f(self);
+}
+
+impl Y for X {
+    fn f(self) {}
+}
+mod z {
+$0use super::X;
+use super::Y as Z;$0
+
+fn w() {
+    let x = X();
+    x.f();
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn ranamed_underscore_trait_item_use_is_use() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+struct X();
+trait Y {
+    fn f(self);
+}
+
+impl Y for X {
+    fn f(self) {}
+}
+mod z {
+$0use super::X;
+use super::Y as _;$0
+
+fn w() {
+    let x = X();
+    x.f();
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn dont_remove_used() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+$0use super::X;
+use super::Y;$0
+
+fn w() {
+    let x = X();
+    let y = Y();
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unused_in_braces() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+    $0use super::{X, Y};$0
+
+    fn w() {
+        let x = X();
+    }
+}
+"#,
+            r#"
+struct X();
+struct Y();
+mod z {
+    use super::{X};
+
+    fn w() {
+        let x = X();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unused_under_cursor() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+mod z {
+    use super::X$0;
+}
+"#,
+            r#"
+struct X();
+mod z {
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_multi_use_block() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+$0mod y {
+    use super::X;
+}
+mod z {
+    use super::X;
+}$0
+"#,
+            r#"
+struct X();
+mod y {
+}
+mod z {
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_nested() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+mod y {
+    struct Y();
+    mod z {
+        use crate::{X, y::Y}$0;
+        fn f() {
+            let x = X();
+        }
+    }
+}
+"#,
+            r#"
+struct X();
+mod y {
+    struct Y();
+    mod z {
+        use crate::{X};
+        fn f() {
+            let x = X();
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_nested_first_item() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+mod y {
+    struct Y();
+    mod z {
+        use crate::{X, y::Y}$0;
+        fn f() {
+            let y = Y();
+        }
+    }
+}
+"#,
+            r#"
+struct X();
+mod y {
+    struct Y();
+    mod z {
+        use crate::{y::Y};
+        fn f() {
+            let y = Y();
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_nested_all_unused() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+mod y {
+    struct Y();
+    mod z {
+        use crate::{X, y::Y}$0;
+    }
+}
+"#,
+            r#"
+struct X();
+mod y {
+    struct Y();
+    mod z {
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unused_glob() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+    use super::*$0;
+}
+"#,
+            r#"
+struct X();
+struct Y();
+mod z {
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unused_braced_glob() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+    use super::{*}$0;
+}
+"#,
+            r#"
+struct X();
+struct Y();
+mod z {
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn dont_remove_used_glob() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+    use super::*$0;
+
+    fn f() {
+        let x = X();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn only_remove_from_selection() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+struct Y();
+mod z {
+    $0use super::X;$0
+    use super::Y;
+}
+mod w {
+    use super::Y;
+}
+"#,
+            r#"
+struct X();
+struct Y();
+mod z {
+    use super::Y;
+}
+mod w {
+    use super::Y;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_several_files() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+//- /foo.rs
+pub struct X();
+pub struct Y();
+
+//- /main.rs
+$0use foo::X;
+use foo::Y;
+$0
+mod foo;
+mod z {
+    use crate::foo::X;
+}
+"#,
+            r#"
+
+mod foo;
+mod z {
+    use crate::foo::X;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn use_in_submodule_doesnt_count() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+struct X();
+mod z {
+    use super::X$0;
+
+    mod w {
+        use crate::X;
+
+        fn f() {
+            let x = X();
+        }
+    }
+}
+"#,
+            r#"
+struct X();
+mod z {
+
+    mod w {
+        use crate::X;
+
+        fn f() {
+            let x = X();
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn use_in_submodule_file_doesnt_count() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+//- /z/foo.rs
+use crate::X;
+fn f() {
+    let x = X();
+}
+
+//- /main.rs
+pub struct X();
+
+mod z {
+    use crate::X$0;
+    mod foo;
+}
+"#,
+            r#"
+pub struct X();
+
+mod z {
+    mod foo;
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index c03bc2f41d5..ac45581b7b4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -10,7 +10,7 @@ use crate::{
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
     utils::{
         add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
-        generate_trait_impl_text, render_snippet, Cursor, DefaultMethods,
+        generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, IgnoreAssocItems,
     },
     AssistId, AssistKind,
 };
@@ -172,7 +172,17 @@ fn impl_def_from_trait(
 ) -> Option<(ast::Impl, ast::AssocItem)> {
     let trait_ = trait_?;
     let target_scope = sema.scope(annotated_name.syntax())?;
-    let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No);
+
+    // Keep assoc items of local crates even if they have #[doc(hidden)] attr.
+    let ignore_items = if trait_.module(sema.db).krate().origin(sema.db).is_local() {
+        IgnoreAssocItems::No
+    } else {
+        IgnoreAssocItems::DocHiddenAttrPresent
+    };
+
+    let trait_items =
+        filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No, ignore_items);
+
     if trait_items.is_empty() {
         return None;
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index e7b62d49bb8..c7c0be4c7d4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -157,7 +157,7 @@ fn find_usages(
     file_id: FileId,
 ) -> UsageSearchResult {
     let file_range = FileRange { file_id, range: fn_.syntax().text_range() };
-    type_param_def.usages(sema).in_scope(SearchScope::file_range(file_range)).all()
+    type_param_def.usages(sema).in_scope(&SearchScope::file_range(file_range)).all()
 }
 
 fn check_valid_usages(usages: &UsageSearchResult, param_list_range: TextRange) -> bool {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index a82f1f9dd8b..2ebb5ef9b19 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -184,6 +184,7 @@ mod handlers {
     mod raw_string;
     mod remove_dbg;
     mod remove_mut;
+    mod remove_unused_imports;
     mod remove_unused_param;
     mod remove_parentheses;
     mod reorder_fields;
@@ -294,6 +295,7 @@ mod handlers {
             raw_string::make_usual_string,
             raw_string::remove_hash,
             remove_mut::remove_mut,
+            remove_unused_imports::remove_unused_imports,
             remove_unused_param::remove_unused_param,
             remove_parentheses::remove_parentheses,
             reorder_fields::reorder_fields,
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 344f2bfcce1..cc3e251a8f2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -132,8 +132,13 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
             .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
             .expect("Assist did not contain any source changes");
         let mut actual = before;
-        if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
+        if let Some((source_file_edit, snippet_edit)) =
+            source_change.get_source_and_snippet_edit(file_id)
+        {
             source_file_edit.apply(&mut actual);
+            if let Some(snippet_edit) = snippet_edit {
+                snippet_edit.apply(&mut actual);
+            }
         }
         actual
     };
@@ -191,9 +196,12 @@ fn check_with_config(
                 && source_change.file_system_edits.len() == 0;
 
             let mut buf = String::new();
-            for (file_id, edit) in source_change.source_file_edits {
+            for (file_id, (edit, snippet_edit)) in source_change.source_file_edits {
                 let mut text = db.file_text(file_id).as_ref().to_owned();
                 edit.apply(&mut text);
+                if let Some(snippet_edit) = snippet_edit {
+                    snippet_edit.apply(&mut text);
+                }
                 if !skip_header {
                     let sr = db.file_source_root(file_id);
                     let sr = db.source_root(sr);
@@ -485,18 +493,21 @@ pub fn test_some_range(a: int) -> bool {
                         source_file_edits: {
                             FileId(
                                 0,
-                            ): TextEdit {
-                                indels: [
-                                    Indel {
-                                        insert: "let $0var_name = 5;\n    ",
-                                        delete: 45..45,
-                                    },
-                                    Indel {
-                                        insert: "var_name",
-                                        delete: 59..60,
-                                    },
-                                ],
-                            },
+                            ): (
+                                TextEdit {
+                                    indels: [
+                                        Indel {
+                                            insert: "let $0var_name = 5;\n    ",
+                                            delete: 45..45,
+                                        },
+                                        Indel {
+                                            insert: "var_name",
+                                            delete: 59..60,
+                                        },
+                                    ],
+                                },
+                                None,
+                            ),
                         },
                         file_system_edits: [],
                         is_snippet: true,
@@ -544,18 +555,21 @@ pub fn test_some_range(a: int) -> bool {
                         source_file_edits: {
                             FileId(
                                 0,
-                            ): TextEdit {
-                                indels: [
-                                    Indel {
-                                        insert: "let $0var_name = 5;\n    ",
-                                        delete: 45..45,
-                                    },
-                                    Indel {
-                                        insert: "var_name",
-                                        delete: 59..60,
-                                    },
-                                ],
-                            },
+                            ): (
+                                TextEdit {
+                                    indels: [
+                                        Indel {
+                                            insert: "let $0var_name = 5;\n    ",
+                                            delete: 45..45,
+                                        },
+                                        Indel {
+                                            insert: "var_name",
+                                            delete: 59..60,
+                                        },
+                                    ],
+                                },
+                                None,
+                            ),
                         },
                         file_system_edits: [],
                         is_snippet: true,
@@ -581,18 +595,21 @@ pub fn test_some_range(a: int) -> bool {
                         source_file_edits: {
                             FileId(
                                 0,
-                            ): TextEdit {
-                                indels: [
-                                    Indel {
-                                        insert: "fun_name()",
-                                        delete: 59..60,
-                                    },
-                                    Indel {
-                                        insert: "\n\nfn $0fun_name() -> i32 {\n    5\n}",
-                                        delete: 110..110,
-                                    },
-                                ],
-                            },
+                            ): (
+                                TextEdit {
+                                    indels: [
+                                        Indel {
+                                            insert: "fun_name()",
+                                            delete: 59..60,
+                                        },
+                                        Indel {
+                                            insert: "\n\nfn $0fun_name() -> i32 {\n    5\n}",
+                                            delete: 110..110,
+                                        },
+                                    ],
+                                },
+                                None,
+                            ),
                         },
                         file_system_edits: [],
                         is_snippet: true,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 4d47a199b7c..6eadc3dbcbc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -952,6 +952,7 @@ fn doctest_generate_default_from_new() {
     check_doc_test(
         "generate_default_from_new",
         r#####"
+//- minicore: default
 struct Example { _inner: () }
 
 impl Example {
@@ -2234,6 +2235,24 @@ fn main() {
 }
 
 #[test]
+fn doctest_remove_unused_imports() {
+    check_doc_test(
+        "remove_unused_imports",
+        r#####"
+struct X();
+mod foo {
+    use super::X$0;
+}
+"#####,
+        r#####"
+struct X();
+mod foo {
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_remove_unused_param() {
     check_doc_test(
         "remove_unused_param",
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 03d8553506f..a262570d94e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -3,7 +3,7 @@
 use std::ops;
 
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
-use hir::{db::HirDatabase, HirDisplay, InFile, Semantics};
+use hir::{db::HirDatabase, HasAttrs as HirHasAttrs, HirDisplay, InFile, Semantics};
 use ide_db::{
     famous_defs::FamousDefs, path_transform::PathTransform,
     syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, SnippetCap,
@@ -84,6 +84,12 @@ pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
     })
 }
 
+#[derive(Clone, Copy, PartialEq)]
+pub enum IgnoreAssocItems {
+    DocHiddenAttrPresent,
+    No,
+}
+
 #[derive(Copy, Clone, PartialEq)]
 pub enum DefaultMethods {
     Only,
@@ -94,11 +100,16 @@ pub fn filter_assoc_items(
     sema: &Semantics<'_, RootDatabase>,
     items: &[hir::AssocItem],
     default_methods: DefaultMethods,
+    ignore_items: IgnoreAssocItems,
 ) -> Vec<InFile<ast::AssocItem>> {
     return items
         .iter()
-        // Note: This throws away items with no source.
         .copied()
+        .filter(|assoc_item| {
+            !(ignore_items == IgnoreAssocItems::DocHiddenAttrPresent
+                && assoc_item.attrs(sema.db).has_doc_hidden())
+        })
+        // Note: This throws away items with no source.
         .filter_map(|assoc_item| {
             let item = match assoc_item {
                 hir::AssocItem::Function(it) => sema.source(it)?.map(ast::AssocItem::Fn),
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 e850f7bfdf3..0309952c29a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -427,9 +427,26 @@ impl Builder {
         let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
 
         if !self.doc_aliases.is_empty() {
-            let doc_aliases = self.doc_aliases.into_iter().join(", ");
+            let doc_aliases = self.doc_aliases.iter().join(", ");
             label = SmolStr::from(format!("{label} (alias {doc_aliases})"));
-            lookup = SmolStr::from(format!("{lookup} {doc_aliases}"));
+            let lookup_doc_aliases = self
+                .doc_aliases
+                .iter()
+                // Don't include aliases in `lookup` that aren't valid identifiers as including
+                // them results in weird completion filtering behavior e.g. `Partial>` matching
+                // `PartialOrd` because it has an alias of ">".
+                .filter(|alias| {
+                    let mut chars = alias.chars();
+                    chars.next().is_some_and(char::is_alphabetic)
+                        && chars.all(|c| c.is_alphanumeric() || c == '_')
+                })
+                // Deliberately concatenated without separators as adding separators e.g.
+                // `alias1, alias2` results in LSP clients continuing to display the completion even
+                // after typing a comma or space.
+                .join("");
+            if !lookup_doc_aliases.is_empty() {
+                lookup = SmolStr::from(format!("{lookup}{lookup_doc_aliases}"));
+            }
         }
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index 3824720839e..e80a289049f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1280,3 +1280,26 @@ fn here_we_go() {
         "#]],
     );
 }
+
+#[test]
+fn completion_filtering_excludes_non_identifier_doc_aliases() {
+    check_edit(
+        "PartialOrdcmporder",
+        r#"
+#[doc(alias = ">")]
+#[doc(alias = "cmp")]
+#[doc(alias = "order")]
+trait PartialOrd {}
+
+struct Foo<T: Partial$0
+"#,
+        r#"
+#[doc(alias = ">")]
+#[doc(alias = "cmp")]
+#[doc(alias = "order")]
+trait PartialOrd {}
+
+struct Foo<T: PartialOrd
+"#,
+    );
+}
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 760834bfafc..5e4562d9c58 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -7,10 +7,10 @@
 
 use arrayvec::ArrayVec;
 use hir::{
-    Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field,
-    Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, Module, ModuleDef, Name,
-    PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant,
-    Visibility,
+    Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper,
+    ExternCrateDecl, Field, Function, GenericParam, HasVisibility, Impl, Label, Local, Macro,
+    Module, ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias,
+    TypeAlias, Variant, Visibility,
 };
 use stdx::impl_from;
 use syntax::{
@@ -42,6 +42,7 @@ pub enum Definition {
     DeriveHelper(DeriveHelper),
     BuiltinAttr(BuiltinAttr),
     ToolModule(ToolModule),
+    ExternCrateDecl(ExternCrateDecl),
 }
 
 impl Definition {
@@ -73,6 +74,7 @@ impl Definition {
             Definition::Local(it) => it.module(db),
             Definition::GenericParam(it) => it.module(db),
             Definition::Label(it) => it.module(db),
+            Definition::ExternCrateDecl(it) => it.module(db),
             Definition::DeriveHelper(it) => it.derive().module(db),
             Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => {
                 return None
@@ -93,6 +95,7 @@ impl Definition {
             Definition::TraitAlias(it) => it.visibility(db),
             Definition::TypeAlias(it) => it.visibility(db),
             Definition::Variant(it) => it.visibility(db),
+            Definition::ExternCrateDecl(it) => it.visibility(db),
             Definition::BuiltinType(_) => Visibility::Public,
             Definition::Macro(_) => return None,
             Definition::BuiltinAttr(_)
@@ -127,6 +130,7 @@ impl Definition {
             Definition::BuiltinAttr(_) => return None, // FIXME
             Definition::ToolModule(_) => return None,  // FIXME
             Definition::DeriveHelper(it) => it.name(db),
+            Definition::ExternCrateDecl(it) => return it.alias_or_name(db),
         };
         Some(name)
     }
@@ -196,6 +200,10 @@ impl IdentClass {
                 res.push(Definition::Local(local_ref));
                 res.push(Definition::Field(field_ref));
             }
+            IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
+                res.push(Definition::ExternCrateDecl(decl));
+                res.push(Definition::Module(krate.root_module()));
+            }
             IdentClass::Operator(
                 OperatorClass::Await(func)
                 | OperatorClass::Prefix(func)
@@ -222,6 +230,10 @@ impl IdentClass {
                 res.push(Definition::Local(local_ref));
                 res.push(Definition::Field(field_ref));
             }
+            IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => {
+                res.push(Definition::ExternCrateDecl(decl));
+                res.push(Definition::Module(krate.root_module()));
+            }
             IdentClass::Operator(_) => (),
         }
         res
@@ -310,6 +322,7 @@ impl NameClass {
                 ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)),
                 ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)),
                 ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)),
+                ast::Item::ExternCrate(it) => Definition::ExternCrateDecl(sema.to_def(&it)?),
                 _ => return None,
             };
             Some(definition)
@@ -346,10 +359,8 @@ impl NameClass {
                 let path = use_tree.path()?;
                 sema.resolve_path(&path).map(Definition::from)
             } else {
-                let extern_crate = rename.syntax().parent().and_then(ast::ExternCrate::cast)?;
-                let krate = sema.resolve_extern_crate(&extern_crate)?;
-                let root_module = krate.root_module(sema.db);
-                Some(Definition::Module(root_module))
+                sema.to_def(&rename.syntax().parent().and_then(ast::ExternCrate::cast)?)
+                    .map(Definition::ExternCrateDecl)
             }
         }
     }
@@ -427,7 +438,19 @@ impl OperatorClass {
 #[derive(Debug)]
 pub enum NameRefClass {
     Definition(Definition),
-    FieldShorthand { local_ref: Local, field_ref: Field },
+    FieldShorthand {
+        local_ref: Local,
+        field_ref: Field,
+    },
+    /// The specific situation where we have an extern crate decl without a rename
+    /// Here we have both a declaration and a reference.
+    /// ```rs
+    /// extern crate foo;
+    /// ```
+    ExternCrateShorthand {
+        decl: ExternCrateDecl,
+        krate: Crate,
+    },
 }
 
 impl NameRefClass {
@@ -513,10 +536,14 @@ impl NameRefClass {
                     }
                     None
                 },
-                ast::ExternCrate(extern_crate) => {
-                    let krate = sema.resolve_extern_crate(&extern_crate)?;
-                    let root_module = krate.root_module(sema.db);
-                    Some(NameRefClass::Definition(Definition::Module(root_module)))
+                ast::ExternCrate(extern_crate_ast) => {
+                    let extern_crate = sema.to_def(&extern_crate_ast)?;
+                    let krate = extern_crate.resolved_crate(sema.db)?;
+                    Some(if extern_crate_ast.rename().is_some() {
+                        NameRefClass::Definition(Definition::Module(krate.root_module()))
+                    } else {
+                        NameRefClass::ExternCrateShorthand { krate, decl: extern_crate }
+                    })
                 },
                 _ => None
             }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index c8341fed1c7..b63dde2c21e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -167,7 +167,7 @@ impl FamousDefs<'_, '_> {
             lang_crate => lang_crate,
         };
         let std_crate = self.find_lang_crate(lang_crate)?;
-        let mut module = std_crate.root_module(db);
+        let mut module = std_crate.root_module();
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index e488300b41c..49b37024a5e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -931,22 +931,6 @@ $ cat $(find -name '*.s')
 "##,
     },
     Lint {
-        label: "abi_thiscall",
-        description: r##"# `abi_thiscall`
-
-The tracking issue for this feature is: [#42202]
-
-[#42202]: https://github.com/rust-lang/rust/issues/42202
-
-------------------------
-
-The MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++
-instance methods by default; it is identical to the usual (C) calling
-convention on x86 Windows except that the first parameter of the method,
-the `this` pointer, is passed in the ECX register.
-"##,
-    },
-    Lint {
         label: "allocator_api",
         description: r##"# `allocator_api`
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 52a23b4b8f3..aa0bb7cce69 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -82,8 +82,9 @@ impl Definition {
     }
 
     /// Textual range of the identifier which will change when renaming this
-    /// `Definition`. Note that some definitions, like builtin types, can't be
-    /// renamed.
+    /// `Definition`. Note that builtin types can't be
+    /// renamed and extern crate names will report its range, though a rename will introduce
+    /// an alias instead.
     pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange> {
         let res = match self {
             Definition::Macro(mac) => {
@@ -146,6 +147,16 @@ impl Definition {
                 let lifetime = src.value.lifetime()?;
                 src.with_value(lifetime.syntax()).original_file_range_opt(sema.db)
             }
+            Definition::ExternCrateDecl(it) => {
+                let src = it.source(sema.db)?;
+                if let Some(rename) = src.value.rename() {
+                    let name = rename.name()?;
+                    src.with_value(name.syntax()).original_file_range_opt(sema.db)
+                } else {
+                    let name = src.value.name_ref()?;
+                    src.with_value(name.syntax()).original_file_range_opt(sema.db)
+                }
+            }
             Definition::BuiltinType(_) => return None,
             Definition::SelfType(_) => return None,
             Definition::BuiltinAttr(_) => return None,
@@ -526,6 +537,9 @@ fn source_edit_from_def(
             TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
             new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(),
         ),
+        Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => {
+            (TextRange::empty(range.end()), format!(" as {new_name}"))
+        }
         _ => (range, new_name.to_owned()),
     };
     edit.replace(range, new_name);
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 f3c0f79c589..d5abd099126 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -127,7 +127,7 @@ impl SearchScope {
     }
 
     /// Build a search scope spanning the given module and all its submodules.
-    fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
+    pub fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
         let mut entries = IntMap::default();
 
         let (file_id, range) = {
@@ -329,7 +329,7 @@ impl Definition {
 pub struct FindUsages<'a> {
     def: Definition,
     sema: &'a Semantics<'a, RootDatabase>,
-    scope: Option<SearchScope>,
+    scope: Option<&'a SearchScope>,
     /// 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
@@ -338,7 +338,7 @@ pub struct FindUsages<'a> {
     search_self_mod: bool,
 }
 
-impl FindUsages<'_> {
+impl<'a> FindUsages<'a> {
     /// Enable searching for `Self` when the definition is a type or `self` for modules.
     pub fn include_self_refs(mut self) -> Self {
         self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
@@ -347,12 +347,12 @@ impl FindUsages<'_> {
     }
 
     /// Limit the search to a given [`SearchScope`].
-    pub fn in_scope(self, scope: SearchScope) -> Self {
+    pub fn in_scope(self, scope: &'a SearchScope) -> Self {
         self.set_scope(Some(scope))
     }
 
     /// Limit the search to a given [`SearchScope`].
-    pub fn set_scope(mut self, scope: Option<SearchScope>) -> Self {
+    pub fn set_scope(mut self, scope: Option<&'a SearchScope>) -> Self {
         assert!(self.scope.is_none());
         self.scope = scope;
         self
@@ -376,7 +376,7 @@ impl FindUsages<'_> {
         res
     }
 
-    fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) {
+    pub fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) {
         let _p = profile::span("FindUsages:search");
         let sema = self.sema;
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index fad0ca51a02..39763479c65 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -7,17 +7,17 @@ use std::{collections::hash_map::Entry, iter, mem};
 
 use crate::SnippetCap;
 use base_db::{AnchoredPathBuf, FileId};
+use itertools::Itertools;
 use nohash_hasher::IntMap;
 use stdx::never;
 use syntax::{
-    algo, ast, ted, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
-    TextSize,
+    algo, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
 };
 use text_edit::{TextEdit, TextEditBuilder};
 
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
-    pub source_file_edits: IntMap<FileId, TextEdit>,
+    pub source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>,
     pub file_system_edits: Vec<FileSystemEdit>,
     pub is_snippet: bool,
 }
@@ -26,7 +26,7 @@ impl SourceChange {
     /// Creates a new SourceChange with the given label
     /// from the edits.
     pub fn from_edits(
-        source_file_edits: IntMap<FileId, TextEdit>,
+        source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>,
         file_system_edits: Vec<FileSystemEdit>,
     ) -> Self {
         SourceChange { source_file_edits, file_system_edits, is_snippet: false }
@@ -34,7 +34,7 @@ impl SourceChange {
 
     pub fn from_text_edit(file_id: FileId, edit: TextEdit) -> Self {
         SourceChange {
-            source_file_edits: iter::once((file_id, edit)).collect(),
+            source_file_edits: iter::once((file_id, (edit, None))).collect(),
             ..Default::default()
         }
     }
@@ -42,12 +42,31 @@ impl SourceChange {
     /// Inserts a [`TextEdit`] for the given [`FileId`]. This properly handles merging existing
     /// edits for a file if some already exist.
     pub fn insert_source_edit(&mut self, file_id: FileId, edit: TextEdit) {
+        self.insert_source_and_snippet_edit(file_id, edit, None)
+    }
+
+    /// Inserts a [`TextEdit`] and potentially a [`SnippetEdit`] for the given [`FileId`].
+    /// This properly handles merging existing edits for a file if some already exist.
+    pub fn insert_source_and_snippet_edit(
+        &mut self,
+        file_id: FileId,
+        edit: TextEdit,
+        snippet_edit: Option<SnippetEdit>,
+    ) {
         match self.source_file_edits.entry(file_id) {
             Entry::Occupied(mut entry) => {
-                never!(entry.get_mut().union(edit).is_err(), "overlapping edits for same file");
+                let value = entry.get_mut();
+                never!(value.0.union(edit).is_err(), "overlapping edits for same file");
+                never!(
+                    value.1.is_some() && snippet_edit.is_some(),
+                    "overlapping snippet edits for same file"
+                );
+                if value.1.is_none() {
+                    value.1 = snippet_edit;
+                }
             }
             Entry::Vacant(entry) => {
-                entry.insert(edit);
+                entry.insert((edit, snippet_edit));
             }
         }
     }
@@ -56,7 +75,10 @@ impl SourceChange {
         self.file_system_edits.push(edit);
     }
 
-    pub fn get_source_edit(&self, file_id: FileId) -> Option<&TextEdit> {
+    pub fn get_source_and_snippet_edit(
+        &self,
+        file_id: FileId,
+    ) -> Option<&(TextEdit, Option<SnippetEdit>)> {
         self.source_file_edits.get(&file_id)
     }
 
@@ -70,7 +92,18 @@ impl SourceChange {
 
 impl Extend<(FileId, TextEdit)> for SourceChange {
     fn extend<T: IntoIterator<Item = (FileId, TextEdit)>>(&mut self, iter: T) {
-        iter.into_iter().for_each(|(file_id, edit)| self.insert_source_edit(file_id, edit));
+        self.extend(iter.into_iter().map(|(file_id, edit)| (file_id, (edit, None))))
+    }
+}
+
+impl Extend<(FileId, (TextEdit, Option<SnippetEdit>))> for SourceChange {
+    fn extend<T: IntoIterator<Item = (FileId, (TextEdit, Option<SnippetEdit>))>>(
+        &mut self,
+        iter: T,
+    ) {
+        iter.into_iter().for_each(|(file_id, (edit, snippet_edit))| {
+            self.insert_source_and_snippet_edit(file_id, edit, snippet_edit)
+        });
     }
 }
 
@@ -82,6 +115,8 @@ impl Extend<FileSystemEdit> for SourceChange {
 
 impl From<IntMap<FileId, TextEdit>> for SourceChange {
     fn from(source_file_edits: IntMap<FileId, TextEdit>) -> SourceChange {
+        let source_file_edits =
+            source_file_edits.into_iter().map(|(file_id, edit)| (file_id, (edit, None))).collect();
         SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
     }
 }
@@ -94,6 +129,65 @@ impl FromIterator<(FileId, TextEdit)> for SourceChange {
     }
 }
 
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct SnippetEdit(Vec<(u32, TextRange)>);
+
+impl SnippetEdit {
+    pub fn new(snippets: Vec<Snippet>) -> Self {
+        let mut snippet_ranges = snippets
+            .into_iter()
+            .zip(1..)
+            .with_position()
+            .map(|pos| {
+                let (snippet, index) = match pos {
+                    itertools::Position::First(it) | itertools::Position::Middle(it) => it,
+                    // last/only snippet gets index 0
+                    itertools::Position::Last((snippet, _))
+                    | itertools::Position::Only((snippet, _)) => (snippet, 0),
+                };
+
+                let range = match snippet {
+                    Snippet::Tabstop(pos) => TextRange::empty(pos),
+                    Snippet::Placeholder(range) => range,
+                };
+                (index, range)
+            })
+            .collect_vec();
+
+        snippet_ranges.sort_by_key(|(_, range)| range.start());
+
+        // Ensure that none of the ranges overlap
+        let disjoint_ranges = snippet_ranges
+            .iter()
+            .zip(snippet_ranges.iter().skip(1))
+            .all(|((_, left), (_, right))| left.end() <= right.start() || left == right);
+        stdx::always!(disjoint_ranges);
+
+        SnippetEdit(snippet_ranges)
+    }
+
+    /// Inserts all of the snippets into the given text.
+    pub fn apply(&self, text: &mut String) {
+        // Start from the back so that we don't have to adjust ranges
+        for (index, range) in self.0.iter().rev() {
+            if range.is_empty() {
+                // is a tabstop
+                text.insert_str(range.start().into(), &format!("${index}"));
+            } else {
+                // is a placeholder
+                text.insert(range.end().into(), '}');
+                text.insert_str(range.start().into(), &format!("${{{index}:"));
+            }
+        }
+    }
+
+    /// Gets the underlying snippet index + text range
+    /// Tabstops are represented by an empty range, and placeholders use the range that they were given
+    pub fn into_edit_ranges(self) -> Vec<(u32, TextRange)> {
+        self.0
+    }
+}
+
 pub struct SourceChangeBuilder {
     pub edit: TextEditBuilder,
     pub file_id: FileId,
@@ -152,24 +246,19 @@ impl SourceChangeBuilder {
     }
 
     fn commit(&mut self) {
-        // Render snippets first so that they get bundled into the tree diff
-        if let Some(mut snippets) = self.snippet_builder.take() {
-            // Last snippet always has stop index 0
-            let last_stop = snippets.places.pop().unwrap();
-            last_stop.place(0);
-
-            for (index, stop) in snippets.places.into_iter().enumerate() {
-                stop.place(index + 1)
-            }
-        }
+        let snippet_edit = self.snippet_builder.take().map(|builder| {
+            SnippetEdit::new(
+                builder.places.into_iter().map(PlaceSnippet::finalize_position).collect_vec(),
+            )
+        });
 
         if let Some(tm) = self.mutated_tree.take() {
-            algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit)
+            algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
         }
 
         let edit = mem::take(&mut self.edit).finish();
-        if !edit.is_empty() {
-            self.source_change.insert_source_edit(self.file_id, edit);
+        if !edit.is_empty() || snippet_edit.is_some() {
+            self.source_change.insert_source_and_snippet_edit(self.file_id, edit, snippet_edit);
         }
     }
 
@@ -275,6 +364,16 @@ impl SourceChangeBuilder {
 
     pub fn finish(mut self) -> SourceChange {
         self.commit();
+
+        // Only one file can have snippet edits
+        stdx::never!(self
+            .source_change
+            .source_file_edits
+            .iter()
+            .filter(|(_, (_, snippet_edit))| snippet_edit.is_some())
+            .at_most_one()
+            .is_err());
+
         mem::take(&mut self.source_change)
     }
 }
@@ -296,6 +395,13 @@ impl From<FileSystemEdit> for SourceChange {
     }
 }
 
+pub enum Snippet {
+    /// A tabstop snippet (e.g. `$0`).
+    Tabstop(TextSize),
+    /// A placeholder snippet (e.g. `${0:placeholder}`).
+    Placeholder(TextRange),
+}
+
 enum PlaceSnippet {
     /// Place a tabstop before an element
     Before(SyntaxElement),
@@ -306,57 +412,11 @@ enum PlaceSnippet {
 }
 
 impl PlaceSnippet {
-    /// Places the snippet before or over an element with the given tab stop index
-    fn place(self, order: usize) {
-        // ensure the target element is still attached
-        match &self {
-            PlaceSnippet::Before(element)
-            | PlaceSnippet::After(element)
-            | PlaceSnippet::Over(element) => {
-                // element should still be in the tree, but if it isn't
-                // then it's okay to just ignore this place
-                if stdx::never!(element.parent().is_none()) {
-                    return;
-                }
-            }
-        }
-
+    fn finalize_position(self) -> Snippet {
         match self {
-            PlaceSnippet::Before(element) => {
-                ted::insert_raw(ted::Position::before(&element), Self::make_tab_stop(order));
-            }
-            PlaceSnippet::After(element) => {
-                ted::insert_raw(ted::Position::after(&element), Self::make_tab_stop(order));
-            }
-            PlaceSnippet::Over(element) => {
-                let position = ted::Position::before(&element);
-                element.detach();
-
-                let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}"))
-                    .syntax_node()
-                    .clone_for_update();
-
-                let placeholder =
-                    snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap();
-                ted::replace(placeholder.syntax(), element);
-
-                ted::insert_raw(position, snippet);
-            }
+            PlaceSnippet::Before(it) => Snippet::Tabstop(it.text_range().start()),
+            PlaceSnippet::After(it) => Snippet::Tabstop(it.text_range().end()),
+            PlaceSnippet::Over(it) => Snippet::Placeholder(it.text_range()),
         }
     }
-
-    fn make_tab_stop(order: usize) -> SyntaxNode {
-        let stop = ast::SourceFile::parse(&format!("stop!(${order})"))
-            .syntax_node()
-            .descendants()
-            .find_map(ast::TokenTree::cast)
-            .unwrap()
-            .syntax()
-            .clone_for_update();
-
-        stop.first_token().unwrap().detach();
-        stop.last_token().unwrap().detach();
-
-        stop
-    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index 937e2f96642..f54cdd63bbb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -51,6 +51,9 @@ macro_rules! compile_error { () => {} }
 
   compile_error!("compile_error macro works");
 //^^^^^^^^^^^^^ error: compile_error macro works
+
+  compile_error! { "compile_error macro braced works" }
+//^^^^^^^^^^^^^ error: compile_error macro braced works
             "#,
         );
     }
@@ -77,7 +80,7 @@ macro_rules! m {
 
 fn f() {
     m!();
-  //^^^^ error: unresolved macro `$crate::private::concat!`
+  //^^^^ error: unresolved macro $crate::private::concat
 }
 
 //- /core.rs crate:core
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 bb0e36ff3a1..acc31cd117a 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
@@ -208,7 +208,7 @@ fn get_default_constructor(
     }
 
     let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate();
-    let module = krate.root_module(ctx.sema.db);
+    let module = krate.root_module();
 
     // Look for a ::new() associated function
     let has_new_func = ty
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index 4ac9d0a9fb7..ee0e0354906 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -49,8 +49,11 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
         let file_id = *source_change.source_file_edits.keys().next().unwrap();
         let mut actual = db.file_text(file_id).to_string();
 
-        for edit in source_change.source_file_edits.values() {
+        for (edit, snippet_edit) in source_change.source_file_edits.values() {
             edit.apply(&mut actual);
+            if let Some(snippet_edit) = snippet_edit {
+                snippet_edit.apply(&mut actual);
+            }
         }
         actual
     };
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 96c193bd539..ca76d0a87b9 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
@@ -121,7 +121,7 @@ impl MatchFinder<'_> {
         // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two
         // lookups in the case of a cache hit.
         if usage_cache.find(&definition).is_none() {
-            let usages = definition.usages(&self.sema).in_scope(self.search_scope()).all();
+            let usages = definition.usages(&self.sema).in_scope(&self.search_scope()).all();
             usage_cache.usages.push((definition, usages));
             return &usage_cache.usages.last().unwrap().1;
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index c90ba212535..d240127f376 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -153,6 +153,9 @@ pub(crate) fn external_docs(
                 NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
                     Definition::Field(field_ref)
                 }
+                NameRefClass::ExternCrateShorthand { decl, .. } => {
+                    Definition::ExternCrateDecl(decl)
+                }
             },
             ast::Name(name) => match NameClass::classify(sema, &name)? {
                 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
@@ -209,6 +212,7 @@ pub(crate) fn resolve_doc_path_for_def(
         Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
         Definition::Field(it) => it.resolve_doc_path(db, link, ns),
         Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
+        Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
         Definition::BuiltinAttr(_)
         | Definition::ToolModule(_)
         | Definition::BuiltinType(_)
@@ -617,6 +621,9 @@ fn filename_and_frag_for_def(
             // FIXME fragment numbering
             return Some((adt, file, Some(String::from("impl"))));
         }
+        Definition::ExternCrateDecl(it) => {
+            format!("{}/index.html", it.name(db).display(db.upcast()))
+        }
         Definition::Local(_)
         | Definition::GenericParam(_)
         | Definition::Label(_)
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index e70bc2ec541..c39c696cfd9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -37,11 +37,15 @@ pub(crate) fn goto_declaration(
                 match parent {
                     ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
                         NameRefClass::Definition(it) => Some(it),
-                        NameRefClass::FieldShorthand { field_ref, .. } => return field_ref.try_to_nav(db),
+                        NameRefClass::FieldShorthand { field_ref, .. } =>
+                            return field_ref.try_to_nav(db),
+                        NameRefClass::ExternCrateShorthand { decl, .. } =>
+                            return decl.try_to_nav(db),
                     },
                     ast::Name(name) => match NameClass::classify(&sema, &name)? {
                         NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it),
-                        NameClass::PatFieldShorthand { field_ref, .. } => return field_ref.try_to_nav(db),
+                        NameClass::PatFieldShorthand { field_ref, .. } =>
+                            return field_ref.try_to_nav(db),
                     },
                     _ => None
                 }
@@ -53,6 +57,7 @@ pub(crate) fn goto_declaration(
                 Definition::Const(c) => c.as_assoc_item(db),
                 Definition::TypeAlias(ta) => ta.as_assoc_item(db),
                 Definition::Function(f) => f.as_assoc_item(db),
+                Definition::ExternCrateDecl(it) => return it.try_to_nav(db),
                 _ => None,
             }?;
 
@@ -211,4 +216,30 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn goto_decl_for_extern_crate() {
+        check(
+            r#"
+//- /main.rs crate:main deps:std
+extern crate std$0;
+         /// ^^^
+//- /std/lib.rs crate:std
+// empty
+"#,
+        )
+    }
+
+    #[test]
+    fn goto_decl_for_renamed_extern_crate() {
+        check(
+            r#"
+//- /main.rs crate:main deps:std
+extern crate std as abc$0;
+                /// ^^^
+//- /std/lib.rs crate:std
+// empty
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 4e641357e37..21471ab2a03 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -1,6 +1,9 @@
 use std::mem::discriminant;
 
-use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav};
+use crate::{
+    doc_links::token_as_doc_comment, navigation_target::ToNav, FilePosition, NavigationTarget,
+    RangeInfo, TryToNav,
+};
 use hir::{AsAssocItem, AssocItem, Semantics};
 use ide_db::{
     base_db::{AnchoredPath, FileId, FileLoader},
@@ -73,6 +76,13 @@ pub(crate) fn goto_definition(
                     .definitions()
                     .into_iter()
                     .flat_map(|def| {
+                        if let Definition::ExternCrateDecl(crate_def) = def {
+                            return crate_def
+                                .resolved_crate(db)
+                                .map(|it| it.root_module().to_nav(sema.db))
+                                .into_iter()
+                                .collect();
+                        }
                         try_filter_trait_item_definition(sema, &def)
                             .unwrap_or_else(|| def_to_nav(sema.db, def))
                     })
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 a1a119629a9..37166bdbd0c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -34,54 +34,50 @@ pub(crate) fn goto_implementation(
             _ => 0,
         })?;
     let range = original_token.text_range();
-    let navs = sema
-        .descend_into_macros(original_token)
-        .into_iter()
-        .filter_map(|token| token.parent().and_then(ast::NameLike::cast))
-        .filter_map(|node| match &node {
-            ast::NameLike::Name(name) => {
-                NameClass::classify(&sema, name).map(|class| match class {
-                    NameClass::Definition(it) | NameClass::ConstReference(it) => it,
-                    NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
-                        Definition::Local(local_def)
+    let navs =
+        sema.descend_into_macros(original_token)
+            .into_iter()
+            .filter_map(|token| token.parent().and_then(ast::NameLike::cast))
+            .filter_map(|node| match &node {
+                ast::NameLike::Name(name) => {
+                    NameClass::classify(&sema, name).and_then(|class| match class {
+                        NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it),
+                        NameClass::PatFieldShorthand { .. } => None,
+                    })
+                }
+                ast::NameLike::NameRef(name_ref) => NameRefClass::classify(&sema, name_ref)
+                    .and_then(|class| match class {
+                        NameRefClass::Definition(def) => Some(def),
+                        NameRefClass::FieldShorthand { .. }
+                        | NameRefClass::ExternCrateShorthand { .. } => None,
+                    }),
+                ast::NameLike::Lifetime(_) => None,
+            })
+            .unique()
+            .filter_map(|def| {
+                let navs = match def {
+                    Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
+                    Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
+                    Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
+                    Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)),
+                    Definition::Function(f) => {
+                        let assoc = f.as_assoc_item(sema.db)?;
+                        let name = assoc.name(sema.db)?;
+                        let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+                        impls_for_trait_item(&sema, trait_, name)
                     }
-                })
-            }
-            ast::NameLike::NameRef(name_ref) => {
-                NameRefClass::classify(&sema, name_ref).map(|class| match class {
-                    NameRefClass::Definition(def) => def,
-                    NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
-                        Definition::Local(local_ref)
+                    Definition::Const(c) => {
+                        let assoc = c.as_assoc_item(sema.db)?;
+                        let name = assoc.name(sema.db)?;
+                        let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+                        impls_for_trait_item(&sema, trait_, name)
                     }
-                })
-            }
-            ast::NameLike::Lifetime(_) => None,
-        })
-        .unique()
-        .filter_map(|def| {
-            let navs = match def {
-                Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
-                Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
-                Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
-                Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)),
-                Definition::Function(f) => {
-                    let assoc = f.as_assoc_item(sema.db)?;
-                    let name = assoc.name(sema.db)?;
-                    let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
-                    impls_for_trait_item(&sema, trait_, name)
-                }
-                Definition::Const(c) => {
-                    let assoc = c.as_assoc_item(sema.db)?;
-                    let name = assoc.name(sema.db)?;
-                    let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
-                    impls_for_trait_item(&sema, trait_, name)
-                }
-                _ => return None,
-            };
-            Some(navs)
-        })
-        .flatten()
-        .collect();
+                    _ => return None,
+                };
+                Some(navs)
+            })
+            .flatten()
+            .collect();
 
     Some(RangeInfo { range, info: navs })
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 7e545491f8e..43e89a334bf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -100,10 +100,7 @@ fn highlight_closure_captures(
             .flat_map(|local| {
                 let usages = Definition::Local(local)
                     .usages(sema)
-                    .set_scope(Some(SearchScope::file_range(FileRange {
-                        file_id,
-                        range: search_range,
-                    })))
+                    .in_scope(&SearchScope::file_range(FileRange { file_id, range: search_range }))
                     .include_self_refs()
                     .all()
                     .references
@@ -139,7 +136,7 @@ fn highlight_references(
         .iter()
         .filter_map(|&d| {
             d.usages(sema)
-                .set_scope(Some(SearchScope::single_file(file_id)))
+                .in_scope(&SearchScope::single_file(file_id))
                 .include_self_refs()
                 .all()
                 .references
@@ -183,7 +180,7 @@ fn highlight_references(
                         .filter_map(|item| {
                             Definition::from(item)
                                 .usages(sema)
-                                .set_scope(Some(SearchScope::file_range(FileRange {
+                                .set_scope(Some(&SearchScope::file_range(FileRange {
                                     file_id,
                                     range: trait_item_use_scope.text_range(),
                                 })))
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 5ef6ac94807..40659e6c263 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -9,7 +9,7 @@ use either::Either;
 use hir::{db::DefDatabase, HasSource, LangItem, Semantics};
 use ide_db::{
     base_db::FileRange,
-    defs::{Definition, IdentClass, OperatorClass},
+    defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
     FxIndexSet, RootDatabase,
@@ -186,7 +186,20 @@ fn hover_simple(
                         // rendering poll is very confusing
                         return None;
                     }
-                    Some(class.definitions().into_iter().zip(iter::once(node).cycle()))
+                    if let IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
+                        decl,
+                        ..
+                    }) = class
+                    {
+                        return Some(vec![(Definition::ExternCrateDecl(decl), node)]);
+                    }
+                    Some(
+                        class
+                            .definitions()
+                            .into_iter()
+                            .zip(iter::once(node).cycle())
+                            .collect::<Vec<_>>(),
+                    )
                 })
                 .flatten()
                 .unique_by(|&(def, _)| def)
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 ef33386a7e9..a33a6ee1816 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -257,7 +257,7 @@ pub(super) fn keyword(
     let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent);
 
     let doc_owner = find_std_module(&famous_defs, &keyword_mod)?;
-    let docs = doc_owner.attrs(sema.db).docs()?;
+    let docs = doc_owner.docs(sema.db)?;
     let markup = process_markup(
         sema.db,
         Definition::Module(doc_owner),
@@ -472,6 +472,7 @@ pub(super) fn definition(
         }
         Definition::GenericParam(it) => label_and_docs(db, it),
         Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db).display(db))),
+        Definition::ExternCrateDecl(it) => label_and_docs(db, it),
         // FIXME: We should be able to show more info about these
         Definition::BuiltinAttr(it) => return render_builtin_attr(db, it),
         Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))),
@@ -620,7 +621,7 @@ where
     D: HasAttrs + HirDisplay,
 {
     let label = def.display(db).to_string();
-    let docs = def.attrs(db).docs();
+    let docs = def.docs(db);
     (label, docs)
 }
 
@@ -645,7 +646,7 @@ where
     ) {
         format_to!(label, "{layout}");
     }
-    let docs = def.attrs(db).docs();
+    let docs = def.docs(db);
     (label, docs)
 }
 
@@ -677,7 +678,7 @@ where
     ) {
         format_to!(label, "{layout}");
     }
-    let docs = def.attrs(db).docs();
+    let docs = def.docs(db);
     (label, docs)
 }
 
@@ -696,7 +697,7 @@ where
     } else {
         def.display(db).to_string()
     };
-    let docs = def.attrs(db).docs();
+    let docs = def.docs(db);
     (label, docs)
 }
 
@@ -727,14 +728,14 @@ fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Optio
     // std exposes prim_{} modules with docstrings on the root to document the builtins
     let primitive_mod = format!("prim_{}", builtin.name().display(famous_defs.0.db));
     let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
-    let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
+    let docs = doc_owner.docs(famous_defs.0.db)?;
     markup(Some(docs.into()), builtin.name().display(famous_defs.0.db).to_string(), None)
 }
 
 fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
     let db = famous_defs.0.db;
     let std_crate = famous_defs.std()?;
-    let std_root_module = std_crate.root_module(db);
+    let std_root_module = std_crate.root_module();
     std_root_module.children(db).find(|module| {
         module.name(db).map_or(false, |module| module.display(db).to_string() == name)
     })
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 00e21433daa..ddc71dffa8a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -1616,6 +1616,9 @@ fn test_hover_extern_crate() {
     check(
         r#"
 //- /main.rs crate:main deps:std
+//! Crate docs
+
+/// Decl docs!
 extern crate st$0d;
 //- /std/lib.rs crate:std
 //! Standard library for this test
@@ -1624,23 +1627,32 @@ extern crate st$0d;
 //! abc123
 "#,
         expect![[r#"
-                *std*
+            *std*
 
-                ```rust
-                extern crate std
-                ```
+            ```rust
+            main
+            ```
 
-                ---
+            ```rust
+            extern crate std
+            ```
+
+            ---
 
-                Standard library for this test
+            Decl docs!
 
-                Printed?
-                abc123
-            "#]],
+            Standard library for this test
+
+            Printed?
+            abc123
+        "#]],
     );
     check(
         r#"
 //- /main.rs crate:main deps:std
+//! Crate docs
+
+/// Decl docs!
 extern crate std as ab$0c;
 //- /std/lib.rs crate:std
 //! Standard library for this test
@@ -1649,19 +1661,25 @@ extern crate std as ab$0c;
 //! abc123
 "#,
         expect![[r#"
-                *abc*
+            *abc*
 
-                ```rust
-                extern crate std
-                ```
+            ```rust
+            main
+            ```
 
-                ---
+            ```rust
+            extern crate std as abc
+            ```
 
-                Standard library for this test
+            ---
 
-                Printed?
-                abc123
-            "#]],
+            Decl docs!
+
+            Standard library for this test
+
+            Printed?
+            abc123
+        "#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 0ad4c6c47e6..bf77d55d58e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -127,7 +127,7 @@ pub use ide_db::{
     label::Label,
     line_index::{LineCol, LineIndex},
     search::{ReferenceCategory, SearchScope},
-    source_change::{FileSystemEdit, SourceChange},
+    source_change::{FileSystemEdit, SnippetEdit, SourceChange},
     symbol_index::Query,
     RootDatabase, SymbolKind,
 };
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index d486a794e13..17f3771b1a5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -177,6 +177,17 @@ pub(crate) fn def_to_moniker(
         });
     }
 
+    // Qualify locals/parameters by their parent definition name.
+    if let Definition::Local(it) = def {
+        let parent_name = it.parent(db).name(db);
+        if let Some(name) = parent_name {
+            description.push(MonikerDescriptor {
+                name: name.display(db).to_string(),
+                desc: MonikerDescriptorKind::Method,
+            });
+        }
+    }
+
     let name_desc = match def {
         // These are handled by top-level guard (for performance).
         Definition::GenericParam(_)
@@ -247,6 +258,10 @@ pub(crate) fn def_to_moniker(
             name: s.name(db).display(db).to_string(),
             desc: MonikerDescriptorKind::Meta,
         },
+        Definition::ExternCrateDecl(m) => MonikerDescriptor {
+            name: m.name(db).display(db).to_string(),
+            desc: MonikerDescriptorKind::Namespace,
+        },
     };
 
     description.push(name_desc);
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index c7abecb4f1e..d1479dd1e58 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -102,7 +102,7 @@ impl NavigationTarget {
                 full_range,
                 SymbolKind::Module,
             );
-            res.docs = module.attrs(db).docs();
+            res.docs = module.docs(db);
             res.description = Some(module.display(db).to_string());
             return res;
         }
@@ -217,6 +217,7 @@ impl TryToNav for Definition {
             Definition::Trait(it) => it.try_to_nav(db),
             Definition::TraitAlias(it) => it.try_to_nav(db),
             Definition::TypeAlias(it) => it.try_to_nav(db),
+            Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?),
             Definition::BuiltinType(_) => None,
             Definition::ToolModule(_) => None,
             Definition::BuiltinAttr(_) => None,
@@ -375,6 +376,30 @@ impl TryToNav for hir::Impl {
     }
 }
 
+impl TryToNav for hir::ExternCrateDecl {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let src = self.source(db)?;
+        let InFile { file_id, value } = src;
+        let focus = value
+            .rename()
+            .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right));
+        let (file_id, full_range, focus_range) =
+            orig_range_with_focus(db, file_id, value.syntax(), focus);
+        let mut res = NavigationTarget::from_syntax(
+            file_id,
+            self.alias_or_name(db).unwrap_or_else(|| self.name(db)).to_smol_str(),
+            focus_range,
+            full_range,
+            SymbolKind::Module,
+        );
+
+        res.docs = self.docs(db);
+        res.description = Some(self.display(db).to_string());
+        res.container_name = container_name(db, *self);
+        Some(res)
+    }
+}
+
 impl TryToNav for hir::Field {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let src = self.source(db)?;
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index fdc5261ac38..813f9ed943f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -74,7 +74,7 @@ pub(crate) fn find_all_refs(
                 }
             });
             let mut usages =
-                def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
+                def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all();
 
             if literal_search {
                 retain_adt_literal_usages(&mut usages, def, sema);
@@ -137,6 +137,9 @@ pub(crate) fn find_defs<'a>(
                             NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
                                 Definition::Local(local_ref)
                             }
+                            NameRefClass::ExternCrateShorthand { decl, .. } => {
+                                Definition::ExternCrateDecl(decl)
+                            }
                         }
                     }
                     ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? {
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index e10c4638102..dae8e71e8a0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -145,7 +145,14 @@ fn find_definitions(
                     if name
                         .syntax()
                         .parent()
-                        .map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
+                        .map_or(false, |it| ast::Rename::can_cast(it.kind()))
+                        // FIXME: uncomment this once we resolve to usages to extern crate declarations
+                        // && name
+                        //     .syntax()
+                        //     .ancestors()
+                        //     .nth(2)
+                        //     .map_or(true, |it| !ast::ExternCrate::can_cast(it.kind()))
+                        =>
                 {
                     bail!("Renaming aliases is currently unsupported")
                 }
@@ -165,7 +172,12 @@ fn find_definitions(
                             NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
                                 Definition::Local(local_ref)
                             }
+                            NameRefClass::ExternCrateShorthand { decl, .. } => {
+                                Definition::ExternCrateDecl(decl)
+                            }
                         })
+                        // FIXME: uncomment this once we resolve to usages to extern crate declarations
+                        .filter(|def| !matches!(def, Definition::ExternCrateDecl(..)))
                         .ok_or_else(|| format_err!("No references found at position"))
                         .and_then(|def| {
                             // if the name differs from the definitions name it has to be an alias
@@ -367,7 +379,7 @@ mod tests {
                 let mut file_id: Option<FileId> = None;
                 for edit in source_change.source_file_edits {
                     file_id = Some(edit.0);
-                    for indel in edit.1.into_iter() {
+                    for indel in edit.1 .0.into_iter() {
                         text_edit_builder.replace(indel.delete, indel.insert);
                     }
                 }
@@ -895,14 +907,17 @@ mod foo$0;
                     source_file_edits: {
                         FileId(
                             1,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "foo2",
-                                    delete: 4..7,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "foo2",
+                                        delete: 4..7,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -944,24 +959,30 @@ use crate::foo$0::FooContent;
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "quux",
-                                    delete: 8..11,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "quux",
+                                        delete: 8..11,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                         FileId(
                             2,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "quux",
-                                    delete: 11..14,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "quux",
+                                        delete: 11..14,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -997,14 +1018,17 @@ mod fo$0o;
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "foo2",
-                                    delete: 4..7,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "foo2",
+                                        delete: 4..7,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveDir {
@@ -1047,14 +1071,17 @@ mod outer { mod fo$0o; }
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "bar",
-                                    delete: 16..19,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "bar",
+                                        delete: 16..19,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -1120,24 +1147,30 @@ pub mod foo$0;
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "foo2",
-                                    delete: 27..30,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "foo2",
+                                        delete: 27..30,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                         FileId(
                             1,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "foo2",
-                                    delete: 8..11,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "foo2",
+                                        delete: 8..11,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -1187,14 +1220,17 @@ mod quux;
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "foo2",
-                                    delete: 4..7,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "foo2",
+                                        delete: 4..7,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -1325,18 +1361,21 @@ pub fn baz() {}
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "r#fn",
-                                    delete: 4..7,
-                                },
-                                Indel {
-                                    insert: "r#fn",
-                                    delete: 22..25,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "r#fn",
+                                        delete: 4..7,
+                                    },
+                                    Indel {
+                                        insert: "r#fn",
+                                        delete: 22..25,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -1395,18 +1434,21 @@ pub fn baz() {}
                     source_file_edits: {
                         FileId(
                             0,
-                        ): TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "foo",
-                                    delete: 4..8,
-                                },
-                                Indel {
-                                    insert: "foo",
-                                    delete: 23..27,
-                                },
-                            ],
-                        },
+                        ): (
+                            TextEdit {
+                                indels: [
+                                    Indel {
+                                        insert: "foo",
+                                        delete: 4..8,
+                                    },
+                                    Indel {
+                                        insert: "foo",
+                                        delete: 23..27,
+                                    },
+                                ],
+                            },
+                            None,
+                        ),
                     },
                     file_system_edits: [
                         MoveFile {
@@ -2487,4 +2529,109 @@ fn main() {
 ",
         )
     }
+
+    #[test]
+    fn extern_crate() {
+        check_prepare(
+            r"
+//- /lib.rs crate:main deps:foo
+extern crate foo$0;
+use foo as qux;
+//- /foo.rs crate:foo
+",
+            expect![[r#"No references found at position"#]],
+        );
+        // FIXME: replace above check_prepare with this once we resolve to usages to extern crate declarations
+        //         check(
+        //             "bar",
+        //             r"
+        // //- /lib.rs crate:main deps:foo
+        // extern crate foo$0;
+        // use foo as qux;
+        // //- /foo.rs crate:foo
+        // ",
+        //             r"
+        // extern crate foo as bar;
+        // use bar as qux;
+        // ",
+        //         );
+    }
+
+    #[test]
+    fn extern_crate_rename() {
+        check_prepare(
+            r"
+//- /lib.rs crate:main deps:foo
+extern crate foo as qux$0;
+use qux as frob;
+//- /foo.rs crate:foo
+",
+            expect!["Renaming aliases is currently unsupported"],
+        );
+        // FIXME: replace above check_prepare with this once we resolve to usages to extern crate
+        // declarations
+        //         check(
+        //             "bar",
+        //             r"
+        // //- /lib.rs crate:main deps:foo
+        // extern crate foo as qux$0;
+        // use qux as frob;
+        // //- /foo.rs crate:foo
+        // ",
+        //             r"
+        // extern crate foo as bar;
+        // use bar as frob;
+        // ",
+        //         );
+    }
+
+    #[test]
+    fn extern_crate_self() {
+        check_prepare(
+            r"
+extern crate self$0;
+use self as qux;
+",
+            expect!["No references found at position"],
+        );
+        // FIXME: replace above check_prepare with this once we resolve to usages to extern crate declarations
+        //         check(
+        //             "bar",
+        //             r"
+        // extern crate self$0;
+        // use self as qux;
+        // ",
+        //             r"
+        // extern crate self as bar;
+        // use self as qux;
+        // ",
+        //         );
+    }
+
+    #[test]
+    fn extern_crate_self_rename() {
+        check_prepare(
+            r"
+//- /lib.rs crate:main deps:foo
+extern crate self as qux$0;
+use qux as frob;
+//- /foo.rs crate:foo
+",
+            expect!["Renaming aliases is currently unsupported"],
+        );
+        // FIXME: replace above check_prepare with this once we resolve to usages to extern crate declarations
+        //         check(
+        //             "bar",
+        //             r"
+        // //- /lib.rs crate:main deps:foo
+        // extern crate self as qux$0;
+        // use qux as frob;
+        // //- /foo.rs crate:foo
+        // ",
+        //             r"
+        // extern crate self as bar;
+        // use bar as frob;
+        // ",
+        //         );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 9fa0e6449b8..5f87a78551d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -232,7 +232,7 @@ fn find_related_tests(
     for def in defs {
         let defs = def
             .usages(sema)
-            .set_scope(search_scope.clone())
+            .set_scope(search_scope.as_ref())
             .all()
             .references
             .into_values()
@@ -309,7 +309,7 @@ pub(crate) fn runnable_fn(
 ) -> Option<Runnable> {
     let name = def.name(sema.db).to_smol_str();
 
-    let root = def.module(sema.db).krate().root_module(sema.db);
+    let root = def.module(sema.db).krate().root_module();
 
     let kind = if name == "main" && def.module(sema.db) == root {
         RunnableKind::Bin
diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
index deaf3c9c416..d8d81869a2f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
@@ -126,14 +126,17 @@ mod tests {
                         source_file_edits: {
                             FileId(
                                 0,
-                            ): TextEdit {
-                                indels: [
-                                    Indel {
-                                        insert: "3",
-                                        delete: 33..34,
-                                    },
-                                ],
-                            },
+                            ): (
+                                TextEdit {
+                                    indels: [
+                                        Indel {
+                                            insert: "3",
+                                            delete: 33..34,
+                                        },
+                                    ],
+                                },
+                                None,
+                            ),
                         },
                         file_system_edits: [],
                         is_snippet: false,
@@ -163,24 +166,30 @@ mod tests {
                         source_file_edits: {
                             FileId(
                                 0,
-                            ): TextEdit {
-                                indels: [
-                                    Indel {
-                                        insert: "3",
-                                        delete: 33..34,
-                                    },
-                                ],
-                            },
+                            ): (
+                                TextEdit {
+                                    indels: [
+                                        Indel {
+                                            insert: "3",
+                                            delete: 33..34,
+                                        },
+                                    ],
+                                },
+                                None,
+                            ),
                             FileId(
                                 1,
-                            ): TextEdit {
-                                indels: [
-                                    Indel {
-                                        insert: "3",
-                                        delete: 11..12,
-                                    },
-                                ],
-                            },
+                            ): (
+                                TextEdit {
+                                    indels: [
+                                        Indel {
+                                            insert: "3",
+                                            delete: 11..12,
+                                        },
+                                    ],
+                                },
+                                None,
+                            ),
                         },
                         file_system_edits: [],
                         is_snippet: false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 59e8300dcdb..d8696198d3b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -88,7 +88,7 @@ pub struct StaticIndexedFile {
 
 fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
     let mut worklist: Vec<_> =
-        Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
+        Crate::all(db).into_iter().map(|krate| krate.root_module()).collect();
     let mut modules = Vec::new();
 
     while let Some(module) = worklist.pop() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 3c40246a69d..8e96bfa01ad 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -269,7 +269,26 @@ fn highlight_name_ref(
 
             h
         }
-        NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(),
+        NameRefClass::FieldShorthand { field_ref, .. } => {
+            highlight_def(sema, krate, field_ref.into())
+        }
+        NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => {
+            let mut h = HlTag::Symbol(SymbolKind::Module).into();
+
+            if resolved_krate != krate {
+                h |= HlMod::Library
+            }
+            let is_public = decl.visibility(db) == hir::Visibility::Public;
+            if is_public {
+                h |= HlMod::Public
+            }
+            let is_from_builtin_crate = resolved_krate.is_builtin(db);
+            if is_from_builtin_crate {
+                h |= HlMod::DefaultLibrary;
+            }
+            h |= HlMod::CrateRoot;
+            h
+        }
     };
 
     h.tag = match name_ref.token_kind() {
@@ -474,6 +493,14 @@ fn highlight_def(
             }
             h
         }
+        Definition::ExternCrateDecl(extern_crate) => {
+            let mut highlight =
+                Highlight::new(HlTag::Symbol(SymbolKind::Module)) | HlMod::CrateRoot;
+            if extern_crate.alias(db).is_none() {
+                highlight |= HlMod::Library;
+            }
+            highlight
+        }
         Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)),
         Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)),
         Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)),
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 901df147d32..2657a641482 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -288,7 +288,7 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri
 
 fn module_def_to_hl_tag(def: Definition) -> HlTag {
     let symbol = match def {
-        Definition::Module(_) => SymbolKind::Module,
+        Definition::Module(_) | Definition::ExternCrateDecl(_) => SymbolKind::Module,
         Definition::Function(_) => SymbolKind::Function,
         Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct,
         Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index b15f7bca72b..88a008796b3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -44,5 +44,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span>
-<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root default_library declaration library">abc</span><span class="semicolon">;</span>
+<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root declaration">abc</span><span class="semicolon">;</span>
+<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="unresolved_reference">unresolved</span> <span class="keyword">as</span> <span class="module crate_root declaration">definitely_unresolved</span><span class="semicolon">;</span>
 </code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
index fd3b39855e2..2043752bc74 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
@@ -43,7 +43,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span>
+<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root">self</span><span class="semicolon">;</span>
 
 <span class="keyword">use</span> <span class="keyword crate_root public">crate</span><span class="semicolon">;</span>
 <span class="keyword">use</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index c5fcec75680..06b66b302ae 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -90,8 +90,18 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</span>
 <span class="brace">}</span>
 
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">concat</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">include</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
+<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span>
+
+<span class="macro">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="unresolved_reference">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, {}!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-<span class="brace">}</span></code></pre>
\ No newline at end of file
+<span class="brace">}</span>
+</code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index dcac8eb7368..3ac8aa9cc9d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -178,5 +178,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"mov eax, </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">backslash</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="none macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="none macro">toho</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="none macro">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="none macro">toho</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index 696aa590025..8749d355c85 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -48,6 +48,7 @@ fn macros() {
     check_highlighting(
         r#"
 //- proc_macros: mirror
+//- /lib.rs crate:lib
 proc_macros::mirror! {
     {
         ,i32 :x pub
@@ -95,11 +96,23 @@ macro without_args {
     }
 }
 
+#[rustc_builtin_macro]
+macro_rules! concat {}
+#[rustc_builtin_macro]
+macro_rules! include {}
+#[rustc_builtin_macro]
+macro_rules! format_args {}
+
+include!(concat!("foo/", "foo.rs"));
+
 fn main() {
-    println!("Hello, {}!", 92);
+    format_args!("Hello, {}!", 92);
     dont_color_me_braces!();
     noop!(noop!(1));
 }
+//- /foo/foo.rs crate:foo
+mod foo {}
+use self::foo as bar;
 "#,
         expect_file!["./test_data/highlight_macros.html"],
         false,
@@ -791,6 +804,7 @@ fn test_extern_crate() {
 //- /main.rs crate:main deps:std,alloc
 extern crate std;
 extern crate alloc as abc;
+extern crate unresolved as definitely_unresolved;
 //- /std/lib.rs crate:std
 pub struct S;
 //- /alloc/lib.rs crate:alloc
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
index 8e2181e977e..f2d89d3efe5 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
@@ -123,4 +123,14 @@ enum Fragment {
     /// proc-macro delimiter=none. As we later discovered, "none" delimiters are
     /// tricky to handle in the parser, and rustc doesn't handle those either.
     Expr(tt::TokenTree),
+    /// There are roughly two types of paths: paths in expression context, where a
+    /// separator `::` between an identifier and its following generic argument list
+    /// is mandatory, and paths in type context, where `::` can be omitted.
+    ///
+    /// Unlike rustc, we need to transform the parsed fragments back into tokens
+    /// during transcription. When the matched path fragment is a type-context path
+    /// and is trasncribed as an expression-context path, verbatim transcription
+    /// would cause a syntax error. We need to fix it up just before transcribing;
+    /// see `transcriber::fix_up_and_push_path_tt()`.
+    Path(tt::TokenTree),
 }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
index 1a7b7eed295..1471af98b75 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
@@ -742,7 +742,11 @@ fn match_meta_var(
     is_2021: bool,
 ) -> ExpandResult<Option<Fragment>> {
     let fragment = match kind {
-        MetaVarKind::Path => parser::PrefixEntryPoint::Path,
+        MetaVarKind::Path => {
+            return input
+                .expect_fragment(parser::PrefixEntryPoint::Path)
+                .map(|it| it.map(Fragment::Path));
+        }
         MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
         MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop,
         MetaVarKind::Pat => parser::PrefixEntryPoint::Pat,
@@ -771,7 +775,7 @@ fn match_meta_var(
                 .expect_fragment(parser::PrefixEntryPoint::Expr)
                 .map(|tt| tt.map(Fragment::Expr));
         }
-        _ => {
+        MetaVarKind::Ident | MetaVarKind::Tt | MetaVarKind::Lifetime | MetaVarKind::Literal => {
             let tt_result = match kind {
                 MetaVarKind::Ident => input
                     .expect_ident()
@@ -799,7 +803,7 @@ fn match_meta_var(
                         })
                         .map_err(|()| ExpandError::binding_error("expected literal"))
                 }
-                _ => Err(ExpandError::UnexpectedToken),
+                _ => unreachable!(),
             };
             return tt_result.map(|it| Some(Fragment::Tokens(it))).into();
         }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 6161af18587..cdac2f1e3bb 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -400,7 +400,8 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
             }
             buf.push(tt.into())
         }
-        Fragment::Tokens(tt) | Fragment::Expr(tt) => buf.push(tt),
+        Fragment::Path(tt::TokenTree::Subtree(tt)) => fix_up_and_push_path_tt(buf, tt),
+        Fragment::Tokens(tt) | Fragment::Expr(tt) | Fragment::Path(tt) => buf.push(tt),
     }
 }
 
@@ -411,6 +412,45 @@ fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
     }
 }
 
+/// Inserts the path separator `::` between an identifier and its following generic
+/// argument list, and then pushes into the buffer. See [`Fragment::Path`] for why
+/// we need this fixup.
+fn fix_up_and_push_path_tt(buf: &mut Vec<tt::TokenTree>, subtree: tt::Subtree) {
+    stdx::always!(matches!(subtree.delimiter.kind, tt::DelimiterKind::Invisible));
+    let mut prev_was_ident = false;
+    // Note that we only need to fix up the top-level `TokenTree`s because the
+    // context of the paths in the descendant `Subtree`s won't be changed by the
+    // mbe transcription.
+    for tt in subtree.token_trees {
+        if prev_was_ident {
+            // Pedantically, `(T) -> U` in `FnOnce(T) -> U` is treated as a generic
+            // argument list and thus needs `::` between it and `FnOnce`. However in
+            // today's Rust this type of path *semantically* cannot appear as a
+            // top-level expression-context path, so we can safely ignore it.
+            if let tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '<', .. })) = tt {
+                buf.push(
+                    tt::Leaf::Punct(tt::Punct {
+                        char: ':',
+                        spacing: tt::Spacing::Joint,
+                        span: tt::Span::unspecified(),
+                    })
+                    .into(),
+                );
+                buf.push(
+                    tt::Leaf::Punct(tt::Punct {
+                        char: ':',
+                        spacing: tt::Spacing::Alone,
+                        span: tt::Span::unspecified(),
+                    })
+                    .into(),
+                );
+            }
+        }
+        prev_was_ident = matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(_)));
+        buf.push(tt);
+    }
+}
+
 /// Handles `${count(t, depth)}`. `our_depth` is the recursion depth and `count_depth` is the depth
 /// defined by the metavar expression.
 fn count(
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index 665bce474a6..9d886a1c979 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -28,7 +28,6 @@ use crate::{
     tt_iter::TtIter,
 };
 
-// FIXME: we probably should re-think  `token_tree_to_syntax_node` interfaces
 pub use self::tt::{Delimiter, DelimiterKind, Punct};
 pub use ::parser::TopEntryPoint;
 
diff --git a/src/tools/rust-analyzer/crates/mbe/src/token_map.rs b/src/tools/rust-analyzer/crates/mbe/src/token_map.rs
index 9b2df89f9c7..73a27df5dbc 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/token_map.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/token_map.rs
@@ -117,4 +117,8 @@ impl TokenMap {
             TokenTextRange::Delimiter(_) => None,
         })
     }
+
+    pub fn filter(&mut self, id: impl Fn(tt::TokenId) -> bool) {
+        self.entries.retain(|&(tid, _)| id(tid));
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
index a868419821d..333318f53b7 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
@@ -165,6 +165,40 @@ pub(crate) mod entry {
             }
             m.complete(p, ERROR);
         }
+
+        pub(crate) fn eager_macro_input(p: &mut Parser<'_>) {
+            let m = p.start();
+
+            let closing_paren_kind = match p.current() {
+                T!['{'] => T!['}'],
+                T!['('] => T![')'],
+                T!['['] => T![']'],
+                _ => {
+                    p.error("expected `{`, `[`, `(`");
+                    while !p.at(EOF) {
+                        p.bump_any();
+                    }
+                    m.complete(p, ERROR);
+                    return;
+                }
+            };
+            p.bump_any();
+            while !p.at(EOF) && !p.at(closing_paren_kind) {
+                expressions::expr(p);
+                if !p.at(EOF) && !p.at(closing_paren_kind) {
+                    p.expect(T![,]);
+                }
+            }
+            p.expect(closing_paren_kind);
+            if p.at(EOF) {
+                m.complete(p, MACRO_EAGER_INPUT);
+                return;
+            }
+            while !p.at(EOF) {
+                p.bump_any();
+            }
+            m.complete(p, ERROR);
+        }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
index 1c056819f4b..4e850b1f74d 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
@@ -328,9 +328,6 @@ fn macro_rules(p: &mut Parser<'_>, m: Marker) {
     p.bump_remap(T![macro_rules]);
     p.expect(T![!]);
 
-    if p.at(IDENT) {
-        name(p);
-    }
     // Special-case `macro_rules! try`.
     // This is a hack until we do proper edition support
 
@@ -340,6 +337,8 @@ fn macro_rules(p: &mut Parser<'_>, m: Marker) {
         let m = p.start();
         p.bump_remap(IDENT);
         m.complete(p, NAME);
+    } else {
+        name(p);
     }
 
     match p.current() {
diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs
index 1aba1f7674f..c155e8aaf67 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs
@@ -75,6 +75,8 @@ pub enum TopEntryPoint {
     /// Edge case -- macros generally don't expand to attributes, with the
     /// exception of `cfg_attr` which does!
     MetaItem,
+    /// Edge case 2 -- eager macros expand their input to a delimited list of comma separated expressions
+    MacroEagerInput,
 }
 
 impl TopEntryPoint {
@@ -87,6 +89,7 @@ impl TopEntryPoint {
             TopEntryPoint::Type => grammar::entry::top::type_,
             TopEntryPoint::Expr => grammar::entry::top::expr,
             TopEntryPoint::MetaItem => grammar::entry::top::meta_item,
+            TopEntryPoint::MacroEagerInput => grammar::entry::top::eager_macro_input,
         };
         let mut p = parser::Parser::new(input);
         entry_point(&mut p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
index 6e3ae656b02..53cdad64992 100644
--- a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
@@ -223,7 +223,8 @@ fn n_attached_trivias<'a>(
 ) -> usize {
     match kind {
         CONST | ENUM | FN | IMPL | MACRO_CALL | MACRO_DEF | MACRO_RULES | MODULE | RECORD_FIELD
-        | STATIC | STRUCT | TRAIT | TUPLE_FIELD | TYPE_ALIAS | UNION | USE | VARIANT => {
+        | STATIC | STRUCT | TRAIT | TUPLE_FIELD | TYPE_ALIAS | UNION | USE | VARIANT
+        | EXTERN_CRATE => {
             let mut res = 0;
             let mut trivias = trivias.enumerate().peekable();
 
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index a8fbcfacf7e..48f407623d8 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -262,6 +262,7 @@ pub enum SyntaxKind {
     TYPE_BOUND_LIST,
     MACRO_ITEMS,
     MACRO_STMTS,
+    MACRO_EAGER_INPUT,
     #[doc(hidden)]
     __LAST,
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs
index 1980d4c78bb..fe18451d384 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs
@@ -17,7 +17,10 @@ use token_stream::TokenStreamBuilder;
 mod symbol;
 pub use symbol::*;
 
-use std::ops::{Bound, Range};
+use std::{
+    iter,
+    ops::{Bound, Range},
+};
 
 use crate::tt;
 
@@ -80,9 +83,7 @@ impl server::TokenStream for RustAnalyzer {
         stream.is_empty()
     }
     fn from_str(&mut self, src: &str) -> Self::TokenStream {
-        use std::str::FromStr;
-
-        Self::TokenStream::from_str(src).expect("cannot parse string")
+        src.parse().expect("cannot parse string")
     }
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
         stream.to_string()
@@ -101,7 +102,7 @@ impl server::TokenStream for RustAnalyzer {
                     },
                 };
                 let tree = TokenTree::from(group);
-                Self::TokenStream::from_iter(vec![tree])
+                Self::TokenStream::from_iter(iter::once(tree))
             }
 
             bridge::TokenTree::Ident(ident) => {
@@ -111,7 +112,7 @@ impl server::TokenStream for RustAnalyzer {
                 let ident: tt::Ident = tt::Ident { text, span: ident.span };
                 let leaf = tt::Leaf::from(ident);
                 let tree = TokenTree::from(leaf);
-                Self::TokenStream::from_iter(vec![tree])
+                Self::TokenStream::from_iter(iter::once(tree))
             }
 
             bridge::TokenTree::Literal(literal) => {
@@ -123,7 +124,7 @@ impl server::TokenStream for RustAnalyzer {
                 let literal = tt::Literal { text, span: literal.0.span };
                 let leaf = tt::Leaf::from(literal);
                 let tree = TokenTree::from(leaf);
-                Self::TokenStream::from_iter(vec![tree])
+                Self::TokenStream::from_iter(iter::once(tree))
             }
 
             bridge::TokenTree::Punct(p) => {
@@ -134,7 +135,7 @@ impl server::TokenStream for RustAnalyzer {
                 };
                 let leaf = tt::Leaf::from(punct);
                 let tree = TokenTree::from(leaf);
-                Self::TokenStream::from_iter(vec![tree])
+                Self::TokenStream::from_iter(iter::once(tree))
             }
         }
     }
@@ -355,12 +356,12 @@ impl server::Server for RustAnalyzer {
     }
 
     fn intern_symbol(ident: &str) -> Self::Symbol {
-        // FIXME: should be self.interner once the proc-macro api allows is
+        // FIXME: should be `self.interner` once the proc-macro api allows it.
         Symbol::intern(&SYMBOL_INTERNER, &::tt::SmolStr::from(ident))
     }
 
     fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
-        // FIXME: should be self.interner once the proc-macro api allows is
+        // FIXME: should be `self.interner` once the proc-macro api allows it.
         f(symbol.text(&SYMBOL_INTERNER).as_str())
     }
 }
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 33d7b5ed878..f446a7c0596 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
@@ -128,7 +128,7 @@ impl flags::AnalysisStats {
         let mut visited_modules = FxHashSet::default();
         let mut visit_queue = Vec::new();
         for krate in krates {
-            let module = krate.root_module(db);
+            let module = krate.root_module();
             let file_id = module.definition_source_file_id(db);
             let file_id = file_id.original_file(db);
             let source_root = db.file_source_root(file_id);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index 0db5fb4740e..8541be715a9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -80,7 +80,7 @@ impl flags::Diagnostics {
 
 fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
     let mut worklist: Vec<_> =
-        Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect();
+        Crate::all(db).into_iter().map(|krate| krate.root_module()).collect();
     let mut modules = Vec::new();
 
     while let Some(module) = worklist.pop() {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
index b63a266a57a..e1704199151 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
@@ -76,7 +76,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
     let mut worklist: Vec<_> = Crate::all(db)
         .into_iter()
         .filter(|x| x.origin(db).is_local())
-        .map(|krate| krate.root_module(db))
+        .map(|krate| krate.root_module())
         .collect();
     let mut modules = Vec::new();
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 4579aca3021..44337f955e5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -417,6 +417,44 @@ pub mod module {
     }
 
     #[test]
+    fn symbol_for_param() {
+        check_symbol(
+            r#"
+//- /lib.rs crate:main deps:foo
+use foo::example_mod::func;
+fn main() {
+    func(42);
+}
+//- /foo/lib.rs crate:foo@0.1.0,https://a.b/foo.git library
+pub mod example_mod {
+    pub fn func(x$0: usize) {}
+}
+"#,
+            "rust-analyzer cargo foo 0.1.0 example_mod/func().(x)",
+        );
+    }
+
+    #[test]
+    fn symbol_for_closure_param() {
+        check_symbol(
+            r#"
+//- /lib.rs crate:main deps:foo
+use foo::example_mod::func;
+fn main() {
+    func();
+}
+//- /foo/lib.rs crate:foo@0.1.0,https://a.b/foo.git library
+pub mod example_mod {
+    pub fn func() {
+        let f = |x$0: usize| {};
+    }
+}
+"#,
+            "rust-analyzer cargo foo 0.1.0 example_mod/func().(x)",
+        );
+    }
+
+    #[test]
     fn local_symbol_for_local() {
         check_symbol(
             r#"
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index aad74b7466a..5f1f731cffb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -353,7 +353,8 @@ pub(crate) fn handle_on_type_formatting(
     };
 
     // This should be a single-file edit
-    let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap();
+    let (_, (text_edit, snippet_edit)) = edit.source_file_edits.into_iter().next().unwrap();
+    stdx::never!(snippet_edit.is_none(), "on type formatting shouldn't use structured snippets");
 
     let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit);
     Ok(Some(change))
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 18d9151d4aa..0a2bb822475 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,11 @@ impl GlobalState {
         if self.proc_macro_clients.iter().any(|it| it.is_err()) {
             status.health = lsp_ext::Health::Warning;
             message.push_str("Failed to spawn one or more proc-macro servers.\n\n");
+            for err in self.proc_macro_clients.iter() {
+                if let Err(err) = err {
+                    format_to!(message, "- {err}\n");
+                }
+            }
         }
         if !self.config.cargo_autoreload()
             && self.is_quiescent()
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
index 7a89533a5e9..7b32180e3eb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
@@ -10,8 +10,8 @@ use ide::{
     CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
     Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
     InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory,
-    RenameError, Runnable, Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind,
-    TextEdit, TextRange, TextSize,
+    RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind,
+    SymbolKind, TextEdit, TextRange, TextSize,
 };
 use itertools::Itertools;
 use serde_json::to_value;
@@ -22,7 +22,7 @@ use crate::{
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
-    lsp_ext,
+    lsp_ext::{self, SnippetTextEdit},
     lsp_utils::invalid_params_error,
     semantic_tokens::{self, standard_fallback_type},
 };
@@ -885,16 +885,136 @@ fn outside_workspace_annotation_id() -> String {
     String::from("OutsideWorkspace")
 }
 
+fn merge_text_and_snippet_edits(
+    line_index: &LineIndex,
+    edit: TextEdit,
+    snippet_edit: SnippetEdit,
+) -> Vec<SnippetTextEdit> {
+    let mut edits: Vec<SnippetTextEdit> = vec![];
+    let mut snippets = snippet_edit.into_edit_ranges().into_iter().peekable();
+    let mut text_edits = edit.into_iter();
+
+    while let Some(current_indel) = text_edits.next() {
+        let new_range = {
+            let insert_len =
+                TextSize::try_from(current_indel.insert.len()).unwrap_or(TextSize::from(u32::MAX));
+            TextRange::at(current_indel.delete.start(), insert_len)
+        };
+
+        // insert any snippets before the text edit
+        for (snippet_index, snippet_range) in
+            snippets.take_while_ref(|(_, range)| range.end() < new_range.start())
+        {
+            let snippet_range = if !stdx::always!(
+                snippet_range.is_empty(),
+                "placeholder range {:?} is before current text edit range {:?}",
+                snippet_range,
+                new_range
+            ) {
+                // only possible for tabstops, so make sure it's an empty/insert range
+                TextRange::empty(snippet_range.start())
+            } else {
+                snippet_range
+            };
+
+            let range = range(&line_index, snippet_range);
+            let new_text = format!("${snippet_index}");
+
+            edits.push(SnippetTextEdit {
+                range,
+                new_text,
+                insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
+                annotation_id: None,
+            })
+        }
+
+        if snippets.peek().is_some_and(|(_, range)| new_range.intersect(*range).is_some()) {
+            // at least one snippet edit intersects this text edit,
+            // so gather all of the edits that intersect this text edit
+            let mut all_snippets = snippets
+                .take_while_ref(|(_, range)| new_range.intersect(*range).is_some())
+                .collect_vec();
+
+            // ensure all of the ranges are wholly contained inside of the new range
+            all_snippets.retain(|(_, range)| {
+                    stdx::always!(
+                        new_range.contains_range(*range),
+                        "found placeholder range {:?} which wasn't fully inside of text edit's new range {:?}", range, new_range
+                    )
+                });
+
+            let mut text_edit = text_edit(line_index, current_indel);
+
+            // escape out snippet text
+            stdx::replace(&mut text_edit.new_text, '\\', r"\\");
+            stdx::replace(&mut text_edit.new_text, '$', r"\$");
+
+            // ...and apply!
+            for (index, range) in all_snippets.iter().rev() {
+                let start = (range.start() - new_range.start()).into();
+                let end = (range.end() - new_range.start()).into();
+
+                if range.is_empty() {
+                    text_edit.new_text.insert_str(start, &format!("${index}"));
+                } else {
+                    text_edit.new_text.insert(end, '}');
+                    text_edit.new_text.insert_str(start, &format!("${{{index}:"));
+                }
+            }
+
+            edits.push(SnippetTextEdit {
+                range: text_edit.range,
+                new_text: text_edit.new_text,
+                insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
+                annotation_id: None,
+            })
+        } else {
+            // snippet edit was beyond the current one
+            // since it wasn't consumed, it's available for the next pass
+            edits.push(snippet_text_edit(line_index, false, current_indel));
+        }
+    }
+
+    // insert any remaining tabstops
+    edits.extend(snippets.map(|(snippet_index, snippet_range)| {
+        let snippet_range = if !stdx::always!(
+            snippet_range.is_empty(),
+            "found placeholder snippet {:?} without a text edit",
+            snippet_range
+        ) {
+            TextRange::empty(snippet_range.start())
+        } else {
+            snippet_range
+        };
+
+        let range = range(&line_index, snippet_range);
+        let new_text = format!("${snippet_index}");
+
+        SnippetTextEdit {
+            range,
+            new_text,
+            insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
+            annotation_id: None,
+        }
+    }));
+
+    edits
+}
+
 pub(crate) fn snippet_text_document_edit(
     snap: &GlobalStateSnapshot,
     is_snippet: bool,
     file_id: FileId,
     edit: TextEdit,
+    snippet_edit: Option<SnippetEdit>,
 ) -> Cancellable<lsp_ext::SnippetTextDocumentEdit> {
     let text_document = optional_versioned_text_document_identifier(snap, file_id);
     let line_index = snap.file_line_index(file_id)?;
-    let mut edits: Vec<_> =
-        edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect();
+    let mut edits = if let Some(snippet_edit) = snippet_edit {
+        merge_text_and_snippet_edits(&line_index, edit, snippet_edit)
+    } else {
+        edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect()
+    };
 
     if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() {
         for edit in &mut edits {
@@ -974,8 +1094,14 @@ pub(crate) fn snippet_workspace_edit(
         let ops = snippet_text_document_ops(snap, op)?;
         document_changes.extend_from_slice(&ops);
     }
-    for (file_id, edit) in source_change.source_file_edits {
-        let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?;
+    for (file_id, (edit, snippet_edit)) in source_change.source_file_edits {
+        let edit = snippet_text_document_edit(
+            snap,
+            source_change.is_snippet,
+            file_id,
+            edit,
+            snippet_edit,
+        )?;
         document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
     }
     let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit {
@@ -1414,7 +1540,9 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError {
 
 #[cfg(test)]
 mod tests {
+    use expect_test::{expect, Expect};
     use ide::{Analysis, FilePosition};
+    use ide_db::source_change::Snippet;
     use test_utils::extract_offset;
     use triomphe::Arc;
 
@@ -1484,6 +1612,481 @@ fn bar(_: usize) {}
         assert!(!docs.contains("use crate::bar"));
     }
 
+    fn check_rendered_snippets(edit: TextEdit, snippets: SnippetEdit, expect: Expect) {
+        let text = r#"/* place to put all ranges in */"#;
+        let line_index = LineIndex {
+            index: Arc::new(ide::LineIndex::new(text)),
+            endings: LineEndings::Unix,
+            encoding: PositionEncoding::Utf8,
+        };
+
+        let res = merge_text_and_snippet_edits(&line_index, edit, snippets);
+        expect.assert_debug_eq(&res);
+    }
+
+    #[test]
+    fn snippet_rendering_only_tabstops() {
+        let edit = TextEdit::builder().finish();
+        let snippets = SnippetEdit::new(vec![
+            Snippet::Tabstop(0.into()),
+            Snippet::Tabstop(0.into()),
+            Snippet::Tabstop(1.into()),
+            Snippet::Tabstop(1.into()),
+        ]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "$1",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "$2",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 1,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 1,
+                        },
+                    },
+                    new_text: "$3",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 1,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 1,
+                        },
+                    },
+                    new_text: "$0",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_only_text_edits() {
+        let mut edit = TextEdit::builder();
+        edit.insert(0.into(), "abc".to_owned());
+        edit.insert(3.into(), "def".to_owned());
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "abc",
+                    insert_text_format: None,
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 3,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 3,
+                        },
+                    },
+                    new_text: "def",
+                    insert_text_format: None,
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstop_after_text_edit() {
+        let mut edit = TextEdit::builder();
+        edit.insert(0.into(), "abc".to_owned());
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![Snippet::Tabstop(7.into())]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "abc",
+                    insert_text_format: None,
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 7,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 7,
+                        },
+                    },
+                    new_text: "$0",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstops_before_text_edit() {
+        let mut edit = TextEdit::builder();
+        edit.insert(2.into(), "abc".to_owned());
+        let edit = edit.finish();
+        let snippets =
+            SnippetEdit::new(vec![Snippet::Tabstop(0.into()), Snippet::Tabstop(0.into())]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+                [
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 0,
+                                character: 0,
+                            },
+                            end: Position {
+                                line: 0,
+                                character: 0,
+                            },
+                        },
+                        new_text: "$1",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 0,
+                                character: 0,
+                            },
+                            end: Position {
+                                line: 0,
+                                character: 0,
+                            },
+                        },
+                        new_text: "$0",
+                        insert_text_format: Some(
+                            Snippet,
+                        ),
+                        annotation_id: None,
+                    },
+                    SnippetTextEdit {
+                        range: Range {
+                            start: Position {
+                                line: 0,
+                                character: 2,
+                            },
+                            end: Position {
+                                line: 0,
+                                character: 2,
+                            },
+                        },
+                        new_text: "abc",
+                        insert_text_format: None,
+                        annotation_id: None,
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_tabstops_between_text_edits() {
+        let mut edit = TextEdit::builder();
+        edit.insert(0.into(), "abc".to_owned());
+        edit.insert(7.into(), "abc".to_owned());
+        let edit = edit.finish();
+        let snippets =
+            SnippetEdit::new(vec![Snippet::Tabstop(4.into()), Snippet::Tabstop(4.into())]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "abc",
+                    insert_text_format: None,
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 4,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 4,
+                        },
+                    },
+                    new_text: "$1",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 4,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 4,
+                        },
+                    },
+                    new_text: "$0",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 7,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 7,
+                        },
+                    },
+                    new_text: "abc",
+                    insert_text_format: None,
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_multiple_tabstops_in_text_edit() {
+        let mut edit = TextEdit::builder();
+        edit.insert(0.into(), "abcdefghijkl".to_owned());
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![
+            Snippet::Tabstop(0.into()),
+            Snippet::Tabstop(5.into()),
+            Snippet::Tabstop(12.into()),
+        ]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "$1abcde$2fghijkl$0",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_multiple_placeholders_in_text_edit() {
+        let mut edit = TextEdit::builder();
+        edit.insert(0.into(), "abcdefghijkl".to_owned());
+        let edit = edit.finish();
+        let snippets = SnippetEdit::new(vec![
+            Snippet::Placeholder(TextRange::new(0.into(), 3.into())),
+            Snippet::Placeholder(TextRange::new(5.into(), 7.into())),
+            Snippet::Placeholder(TextRange::new(10.into(), 12.into())),
+        ]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "${1:abc}de${2:fg}hij${0:kl}",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
+    #[test]
+    fn snippet_rendering_escape_snippet_bits() {
+        // only needed for snippet formats
+        let mut edit = TextEdit::builder();
+        edit.insert(0.into(), r"abc\def$".to_owned());
+        edit.insert(8.into(), r"ghi\jkl$".to_owned());
+        let edit = edit.finish();
+        let snippets =
+            SnippetEdit::new(vec![Snippet::Placeholder(TextRange::new(0.into(), 3.into()))]);
+
+        check_rendered_snippets(
+            edit,
+            snippets,
+            expect![[r#"
+            [
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 0,
+                        },
+                    },
+                    new_text: "${0:abc}\\\\def\\$",
+                    insert_text_format: Some(
+                        Snippet,
+                    ),
+                    annotation_id: None,
+                },
+                SnippetTextEdit {
+                    range: Range {
+                        start: Position {
+                            line: 0,
+                            character: 8,
+                        },
+                        end: Position {
+                            line: 0,
+                            character: 8,
+                        },
+                    },
+                    new_text: "ghi\\jkl$",
+                    insert_text_format: None,
+                    annotation_id: None,
+                },
+            ]
+        "#]],
+        );
+    }
+
     // `Url` is not able to parse windows paths on unix machines.
     #[test]
     #[cfg(target_os = "windows")]
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index b096c997448..138ddd20897 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -72,6 +72,12 @@ TokenTree =
 MacroItems =
   Item*
 
+MacroEagerInput =
+  '(' (Expr (',' Expr)* ','?)? ')'
+| '{' (Expr (',' Expr)* ','?)? '}'
+| '[' (Expr (',' Expr)* ','?)? ']'
+
+
 MacroStmts =
   statements:Stmt*
   Expr?
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index 606804aea25..a150d9e6c07 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -380,6 +380,26 @@ impl Removable for ast::UseTree {
 }
 
 impl ast::UseTree {
+    /// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty.
+    pub fn remove_recursive(self) {
+        let parent = self.syntax().parent();
+
+        self.remove();
+
+        if let Some(u) = parent.clone().and_then(ast::Use::cast) {
+            if u.use_tree().is_none() {
+                u.remove();
+            }
+        } else if let Some(u) = parent.and_then(ast::UseTreeList::cast) {
+            if u.use_trees().next().is_none() {
+                let parent = u.syntax().parent().and_then(ast::UseTree::cast);
+                if let Some(u) = parent {
+                    u.remove_recursive();
+                }
+            }
+        }
+    }
+
     pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
         match self.use_tree_list() {
             Some(it) => it,
@@ -487,6 +507,22 @@ impl Removable for ast::Use {
                 }
             }
         }
+        let prev_ws = self
+            .syntax()
+            .prev_sibling_or_token()
+            .and_then(|it| it.into_token())
+            .and_then(ast::Whitespace::cast);
+        if let Some(prev_ws) = prev_ws {
+            let ws_text = prev_ws.syntax().text();
+            let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0);
+            let rest = &ws_text[0..prev_newline];
+            if rest.is_empty() {
+                ted::remove(prev_ws.syntax());
+            } else {
+                ted::replace(prev_ws.syntax(), make::tokens::whitespace(rest));
+            }
+        }
+
         ted::remove(self.syntax());
     }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index e520801ea2e..0b27faa535d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -198,6 +198,20 @@ impl ast::HasModuleItem for MacroItems {}
 impl MacroItems {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MacroEagerInput {
+    pub(crate) syntax: SyntaxNode,
+}
+impl MacroEagerInput {
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+    pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
+    pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
+    pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
+    pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct MacroStmts {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1922,6 +1936,17 @@ impl AstNode for MacroItems {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for MacroEagerInput {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EAGER_INPUT }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for MacroStmts {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4360,6 +4385,11 @@ impl std::fmt::Display for MacroItems {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for MacroEagerInput {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for MacroStmts {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index bed240a6d73..4cd668a0cd5 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -172,7 +172,7 @@ impl SourceFile {
 }
 
 impl ast::TokenTree {
-    pub fn reparse_as_expr(self) -> Parse<ast::Expr> {
+    pub fn reparse_as_comma_separated_expr(self) -> Parse<ast::MacroEagerInput> {
         let tokens = self.syntax().descendants_with_tokens().filter_map(NodeOrToken::into_token);
 
         let mut parser_input = parser::Input::default();
@@ -203,7 +203,7 @@ impl ast::TokenTree {
             }
         }
 
-        let parser_output = parser::TopEntryPoint::Expr.parse(&parser_input);
+        let parser_output = parser::TopEntryPoint::MacroEagerInput.parse(&parser_input);
 
         let mut tokens =
             self.syntax().descendants_with_tokens().filter_map(NodeOrToken::into_token);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
index c5783b91a0f..e4db33f1c69 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs
@@ -216,6 +216,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
         // macro related
         "MACRO_ITEMS",
         "MACRO_STMTS",
+        "MACRO_EAGER_INPUT",
     ],
 };
 
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index 1b8d4ba42a5..b5a72bec079 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -65,12 +65,12 @@ pub mod token_id {
     }
     impl TokenTree {
         pub const fn empty() -> Self {
-            Self::Subtree(Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] })
+            Self::Subtree(Subtree::empty())
         }
     }
 
     impl Subtree {
-        pub fn visit_ids(&mut self, f: &impl Fn(TokenId) -> TokenId) {
+        pub fn visit_ids(&mut self, f: &mut impl FnMut(TokenId) -> TokenId) {
             self.delimiter.open = f(self.delimiter.open);
             self.delimiter.close = f(self.delimiter.close);
             self.token_trees.iter_mut().for_each(|tt| match tt {
@@ -122,7 +122,6 @@ impl_from!(Literal<Span>, Punct<Span>, Ident<Span> for Leaf);
 
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Subtree<Span> {
-    // FIXME, this should not be Option
     pub delimiter: Delimiter<Span>,
     pub token_trees: Vec<TokenTree<Span>>,
 }
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 2cf985adabc..5dafd1a4c8c 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -949,6 +949,29 @@ Or it is possible to specify vars more granularly:
 You can use any valid regular expression as a mask.
 Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively.
 
+If needed, you can set different values for different platforms:
+```jsonc
+"rust-analyzer.runnables.extraEnv": [
+    {
+        "platform": "win32", // windows only
+        env: {
+             "APP_DATA": "windows specific data"
+        }
+    },
+    {
+        "platform": ["linux"],
+        "env": {
+             "APP_DATA": "linux data",
+        }
+    },
+    { // for all platforms
+        "env": {
+             "APP_COMMON_DATA": "xxx",
+        }
+    }
+]
+```
+
 ==== Compiler feedback from external commands
 
 Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output.
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 1c94f13d745..20fe781ae9e 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -18,7 +18,7 @@
             "devDependencies": {
                 "@tsconfig/strictest": "^2.0.1",
                 "@types/node": "~16.11.7",
-                "@types/vscode": "~1.78.1",
+                "@types/vscode": "~1.75",
                 "@typescript-eslint/eslint-plugin": "^6.0.0",
                 "@typescript-eslint/parser": "^6.0.0",
                 "@vscode/test-electron": "^2.3.3",
@@ -32,7 +32,7 @@
                 "typescript": "^5.1.6"
             },
             "engines": {
-                "vscode": "^1.78.0"
+                "vscode": "^1.75.0"
             }
         },
         "node_modules/@aashutoshrathi/word-wrap": {
@@ -565,9 +565,9 @@
             "dev": true
         },
         "node_modules/@types/vscode": {
-            "version": "1.78.1",
-            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz",
-            "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==",
+            "version": "1.75.1",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz",
+            "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==",
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index a4897899cab..76d7e91f381 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -26,7 +26,7 @@
         }
     },
     "engines": {
-        "vscode": "^1.78.0"
+        "vscode": "^1.75.0"
     },
     "enabledApiProposals": [],
     "scripts": {
@@ -53,7 +53,7 @@
     "devDependencies": {
         "@tsconfig/strictest": "^2.0.1",
         "@types/node": "~16.11.7",
-        "@types/vscode": "~1.78.1",
+        "@types/vscode": "~1.75",
         "@typescript-eslint/eslint-plugin": "^6.0.0",
         "@typescript-eslint/parser": "^6.0.0",
         "@vscode/test-electron": "^2.3.3",
@@ -328,6 +328,15 @@
                             "items": {
                                 "type": "object",
                                 "properties": {
+                                    "platform": {
+                                        "type": [
+                                            "null",
+                                            "string",
+                                            "array"
+                                        ],
+                                        "default": null,
+                                        "markdownDescription": "Platform(s) filter like \"win32\" or [\"linux\", \"win32\"]. See [process.platform](https://nodejs.org/api/process.html#processplatform) values."
+                                    },
                                     "mask": {
                                         "type": "string",
                                         "description": "Runnable name mask"
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index a047f9659a9..0e64054c11d 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -6,10 +6,12 @@ import type { Env } from "./client";
 import { log } from "./util";
 import { expectNotUndefined, unwrapUndefinable } from "./undefinable";
 
-export type RunnableEnvCfg =
-    | undefined
-    | Record<string, string>
-    | { mask?: string; env: Record<string, string> }[];
+export type RunnableEnvCfgItem = {
+    mask?: string;
+    env: Record<string, string>;
+    platform?: string | string[];
+};
+export type RunnableEnvCfg = undefined | Record<string, string> | RunnableEnvCfgItem[];
 
 export class Config {
     readonly extensionId = "rust-lang.rust-analyzer";
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index ac144cbebb2..16c14ca54f2 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -414,7 +414,7 @@ export class Ctx {
                 statusBar.tooltip.appendText(status.message ?? "Ready");
                 statusBar.color = undefined;
                 statusBar.backgroundColor = undefined;
-                statusBar.command = "rust-analyzer.stopServer";
+                statusBar.command = "rust-analyzer.openLogs";
                 this.dependencies?.refresh();
                 break;
             case "warning":
@@ -442,14 +442,16 @@ export class Ctx {
                 statusBar.tooltip.appendMarkdown(
                     "\n\n[Start server](command:rust-analyzer.startServer)",
                 );
-                statusBar.color = undefined;
-                statusBar.backgroundColor = undefined;
+                statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground");
+                statusBar.backgroundColor = new vscode.ThemeColor(
+                    "statusBarItem.warningBackground",
+                );
                 statusBar.command = "rust-analyzer.startServer";
                 statusBar.text = `$(stop-circle) rust-analyzer`;
                 return;
         }
         if (statusBar.tooltip.value) {
-            statusBar.tooltip.appendText("\n\n");
+            statusBar.tooltip.appendMarkdown("\n\n---\n\n");
         }
         statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)");
         statusBar.tooltip.appendMarkdown(
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index c893d390554..57881803a6a 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -5,7 +5,7 @@ import * as tasks from "./tasks";
 
 import type { CtxInit } from "./ctx";
 import { makeDebugConfig } from "./debug";
-import type { Config, RunnableEnvCfg } from "./config";
+import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
 import { unwrapUndefinable } from "./undefinable";
 
 const quickPickButtons = [
@@ -112,11 +112,21 @@ export function prepareEnv(
     }
 
     Object.assign(env, process.env as { [key: string]: string });
+    const platform = process.platform;
+
+    const checkPlatform = (it: RunnableEnvCfgItem) => {
+        if (it.platform) {
+            const platforms = Array.isArray(it.platform) ? it.platform : [it.platform];
+            return platforms.indexOf(platform) >= 0;
+        }
+        return true;
+    };
 
     if (runnableEnvCfg) {
         if (Array.isArray(runnableEnvCfg)) {
             for (const it of runnableEnvCfg) {
-                if (!it.mask || new RegExp(it.mask).test(runnable.label)) {
+                const masked = !it.mask || new RegExp(it.mask).test(runnable.label);
+                if (masked && checkPlatform(it)) {
                     Object.assign(env, it.env);
                 }
             }
diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml
index a910e012b73..f0cd3539975 100644
--- a/src/tools/rust-analyzer/triagebot.toml
+++ b/src/tools/rust-analyzer/triagebot.toml
@@ -9,3 +9,7 @@ allow-unauthenticated = [
 
 [autolabel."S-waiting-on-review"]
 new_pr = true
+
+[no-merges]
+exclude_labels = ["sync"]
+labels = ["has-merge-commits", "S-waiting-on-author"]
diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
index 5f8eaebf531..67b745373f0 100644
--- a/src/tools/tidy/src/fluent_alphabetical.rs
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -23,7 +23,7 @@ fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) {
                 tidy_error!(
                     bad,
                     "{filename}: message `{}` appears before `{}`, but is alphabetically later than it
-run tidy with `--bless` to sort the file correctly",
+run `./x.py test tidy --bless` to sort the file correctly",
                     name.as_str(),
                     next.as_str()
                 );
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 930b7408390..3414924007b 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
 
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
-const ISSUES_ENTRY_LIMIT: usize = 1893;
+const ISSUES_ENTRY_LIMIT: usize = 1891;
 const ROOT_ENTRY_LIMIT: usize = 866;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/codegen/box-maybe-uninit-llvm14.rs b/tests/codegen/box-maybe-uninit-llvm14.rs
deleted file mode 100644
index c9f88fb3fe4..00000000000
--- a/tests/codegen/box-maybe-uninit-llvm14.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// compile-flags: -O
-
-// Once we're done with llvm 14 and earlier, this test can be deleted.
-
-#![crate_type = "lib"]
-
-use std::mem::MaybeUninit;
-
-// Boxing a `MaybeUninit` value should not copy junk from the stack
-#[no_mangle]
-pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
-    // CHECK-LABEL: @box_uninitialized
-    // CHECK-NOT: store
-    // CHECK-NOT: alloca
-    // CHECK-NOT: memcpy
-    // CHECK-NOT: memset
-    Box::new(MaybeUninit::uninit())
-}
-
-// https://github.com/rust-lang/rust/issues/58201
-#[no_mangle]
-pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
-    // CHECK-LABEL: @box_uninitialized2
-    // CHECK-NOT: store
-    // CHECK-NOT: alloca
-    // CHECK-NOT: memcpy
-    // CHECK-NOT: memset
-    Box::new(MaybeUninit::uninit())
-}
-
-// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
-// from the CHECK-NOT above. We don't check the attributes here because we can't rely
-// on all of them being set until LLVM 15.
-// CHECK: declare {{(dso_local )?}}noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)
diff --git a/tests/codegen/c-variadic-copy.rs b/tests/codegen/cffi/c-variadic-copy.rs
index 4c61c4fcf68..4c61c4fcf68 100644
--- a/tests/codegen/c-variadic-copy.rs
+++ b/tests/codegen/cffi/c-variadic-copy.rs
diff --git a/tests/codegen/c-variadic-opt.rs b/tests/codegen/cffi/c-variadic-opt.rs
index 969dce80f58..969dce80f58 100644
--- a/tests/codegen/c-variadic-opt.rs
+++ b/tests/codegen/cffi/c-variadic-opt.rs
diff --git a/tests/codegen/c-variadic.rs b/tests/codegen/cffi/c-variadic.rs
index cab32652210..cab32652210 100644
--- a/tests/codegen/c-variadic.rs
+++ b/tests/codegen/cffi/c-variadic.rs
diff --git a/tests/codegen/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs
index 93720503480..93720503480 100644
--- a/tests/codegen/ffi-const.rs
+++ b/tests/codegen/cffi/ffi-const.rs
diff --git a/tests/codegen/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
index 099726b2f08..099726b2f08 100644
--- a/tests/codegen/ffi-out-of-bounds-loads.rs
+++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
diff --git a/tests/codegen/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs
index 2ed73581358..2ed73581358 100644
--- a/tests/codegen/ffi-pure.rs
+++ b/tests/codegen/cffi/ffi-pure.rs
diff --git a/tests/codegen/ffi-returns-twice.rs b/tests/codegen/cffi/ffi-returns-twice.rs
index 0fbe03f0bb6..0fbe03f0bb6 100644
--- a/tests/codegen/ffi-returns-twice.rs
+++ b/tests/codegen/cffi/ffi-returns-twice.rs
diff --git a/tests/codegen/enum-bounds-check-derived-idx.rs b/tests/codegen/enum/enum-bounds-check-derived-idx.rs
index aa66c2ed08e..aa66c2ed08e 100644
--- a/tests/codegen/enum-bounds-check-derived-idx.rs
+++ b/tests/codegen/enum/enum-bounds-check-derived-idx.rs
diff --git a/tests/codegen/enum-bounds-check-issue-13926.rs b/tests/codegen/enum/enum-bounds-check-issue-13926.rs
index b26945bc549..b26945bc549 100644
--- a/tests/codegen/enum-bounds-check-issue-13926.rs
+++ b/tests/codegen/enum/enum-bounds-check-issue-13926.rs
diff --git a/tests/codegen/enum-bounds-check-issue-82871.rs b/tests/codegen/enum/enum-bounds-check-issue-82871.rs
index 32fdc4a5f4f..32fdc4a5f4f 100644
--- a/tests/codegen/enum-bounds-check-issue-82871.rs
+++ b/tests/codegen/enum/enum-bounds-check-issue-82871.rs
diff --git a/tests/codegen/enum-bounds-check.rs b/tests/codegen/enum/enum-bounds-check.rs
index 17322d5911b..17322d5911b 100644
--- a/tests/codegen/enum-bounds-check.rs
+++ b/tests/codegen/enum/enum-bounds-check.rs
diff --git a/tests/codegen/enum-debug-clike.rs b/tests/codegen/enum/enum-debug-clike.rs
index 1e369a2c4e6..1e369a2c4e6 100644
--- a/tests/codegen/enum-debug-clike.rs
+++ b/tests/codegen/enum/enum-debug-clike.rs
diff --git a/tests/codegen/enum-debug-niche-2.rs b/tests/codegen/enum/enum-debug-niche-2.rs
index 4b607d50574..4b607d50574 100644
--- a/tests/codegen/enum-debug-niche-2.rs
+++ b/tests/codegen/enum/enum-debug-niche-2.rs
diff --git a/tests/codegen/enum-debug-niche.rs b/tests/codegen/enum/enum-debug-niche.rs
index b718a6854dd..b718a6854dd 100644
--- a/tests/codegen/enum-debug-niche.rs
+++ b/tests/codegen/enum/enum-debug-niche.rs
diff --git a/tests/codegen/enum-debug-tagged.rs b/tests/codegen/enum/enum-debug-tagged.rs
index 095c49ac3ac..095c49ac3ac 100644
--- a/tests/codegen/enum-debug-tagged.rs
+++ b/tests/codegen/enum/enum-debug-tagged.rs
diff --git a/tests/codegen/enum-discriminant-value.rs b/tests/codegen/enum/enum-discriminant-value.rs
index cc14c212002..cc14c212002 100644
--- a/tests/codegen/enum-discriminant-value.rs
+++ b/tests/codegen/enum/enum-discriminant-value.rs
diff --git a/tests/codegen/enum-match.rs b/tests/codegen/enum/enum-match.rs
index 5548cd25147..5548cd25147 100644
--- a/tests/codegen/enum-match.rs
+++ b/tests/codegen/enum/enum-match.rs
diff --git a/tests/codegen/enum-u128.rs b/tests/codegen/enum/enum-u128.rs
index f50d360ac9f..f50d360ac9f 100644
--- a/tests/codegen/enum-u128.rs
+++ b/tests/codegen/enum/enum-u128.rs
diff --git a/tests/codegen/intrinsics/compare_bytes.rs b/tests/codegen/intrinsics/compare_bytes.rs
new file mode 100644
index 00000000000..e69224d818c
--- /dev/null
+++ b/tests/codegen/intrinsics/compare_bytes.rs
@@ -0,0 +1,34 @@
+// revisions: INT32 INT16
+// compile-flags: -O
+// [INT32] ignore-16bit
+// [INT16] only-16bit
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::compare_bytes;
+
+#[no_mangle]
+// CHECK-LABEL: @bytes_cmp(
+pub unsafe fn bytes_cmp(a: *const u8, b: *const u8, n: usize) -> i32 {
+    // INT32: %[[TEMP:.+]] = tail call i32 @memcmp(ptr %a, ptr %b, {{i32|i64}} %n)
+    // INT32-NOT: sext
+    // INT32: ret i32 %[[TEMP]]
+
+    // INT16: %[[TEMP1:.+]] = tail call i16 @memcmp(ptr %a, ptr %b, i16 %n)
+    // INT16: %[[TEMP2:.+]] = sext i16 %[[TEMP1]] to i32
+    // INT16: ret i32 %[[TEMP2]]
+    compare_bytes(a, b, n)
+}
+
+// Ensure that, even though there's an `sext` emitted by the intrinsic,
+// that doesn't end up pessiming checks against zero.
+#[no_mangle]
+// CHECK-LABEL: @bytes_eq(
+pub unsafe fn bytes_eq(a: *const u8, b: *const u8, n: usize) -> bool {
+    // CHECK: call {{.+}} @{{bcmp|memcmp}}(ptr %a, ptr %b, {{i16|i32|i64}} %n)
+    // CHECK-NOT: sext
+    // INT32: icmp eq i32
+    // INT16: icmp eq i16
+    compare_bytes(a, b, n) == 0_i32
+}
diff --git a/tests/codegen/i686-macosx-deployment-target.rs b/tests/codegen/macos/i686-macosx-deployment-target.rs
index 17258a264a5..17258a264a5 100644
--- a/tests/codegen/i686-macosx-deployment-target.rs
+++ b/tests/codegen/macos/i686-macosx-deployment-target.rs
diff --git a/tests/codegen/i686-no-macosx-deployment-target.rs b/tests/codegen/macos/i686-no-macosx-deployment-target.rs
index 043040a95e3..043040a95e3 100644
--- a/tests/codegen/i686-no-macosx-deployment-target.rs
+++ b/tests/codegen/macos/i686-no-macosx-deployment-target.rs
diff --git a/tests/codegen/x86_64-macosx-deployment-target.rs b/tests/codegen/macos/x86_64-macosx-deployment-target.rs
index 8e673d11d98..8e673d11d98 100644
--- a/tests/codegen/x86_64-macosx-deployment-target.rs
+++ b/tests/codegen/macos/x86_64-macosx-deployment-target.rs
diff --git a/tests/codegen/x86_64-no-macosx-deployment-target.rs b/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs
index 25ae6924de0..25ae6924de0 100644
--- a/tests/codegen/x86_64-no-macosx-deployment-target.rs
+++ b/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs
diff --git a/tests/codegen/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs
index e05bbc26e83..e05bbc26e83 100644
--- a/tests/codegen/naked-functions.rs
+++ b/tests/codegen/naked-fn/naked-functions.rs
diff --git a/tests/codegen/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs
index 3c755e49c6d..3c755e49c6d 100644
--- a/tests/codegen/naked-nocoverage.rs
+++ b/tests/codegen/naked-fn/naked-nocoverage.rs
diff --git a/tests/codegen/naked-noinline.rs b/tests/codegen/naked-fn/naked-noinline.rs
index 5cfb500c0ef..5cfb500c0ef 100644
--- a/tests/codegen/naked-noinline.rs
+++ b/tests/codegen/naked-fn/naked-noinline.rs
diff --git a/tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs b/tests/codegen/sanitizer/cfi-add-canonical-jump-tables-flag.rs
index 1ee8bdfc3ab..1ee8bdfc3ab 100644
--- a/tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs
+++ b/tests/codegen/sanitizer/cfi-add-canonical-jump-tables-flag.rs
diff --git a/tests/codegen/sanitizer-cfi-add-enable-split-lto-unit-flag.rs b/tests/codegen/sanitizer/cfi-add-enable-split-lto-unit-flag.rs
index 68c91384b82..68c91384b82 100644
--- a/tests/codegen/sanitizer-cfi-add-enable-split-lto-unit-flag.rs
+++ b/tests/codegen/sanitizer/cfi-add-enable-split-lto-unit-flag.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs
index 2b61c9078fd..a3cd16e3dd5 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-checks-attr-no-sanitize.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs
@@ -8,7 +8,7 @@
 
 #[no_sanitize(cfi)]
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
-    // CHECK-LABEL: sanitizer_cfi_emit_type_checks_attr_no_sanitize::foo
+    // CHECK-LABEL: cfi_emit_type_checks_attr_no_sanitize::foo
     // CHECK:       Function Attrs: {{.*}}
     // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
     // CHECK:       start:
diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks.rs b/tests/codegen/sanitizer/cfi-emit-type-checks.rs
index f0fe5de9f66..f0fe5de9f66 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-checks.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-checks.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs
index 084d8bf803c..084d8bf803c 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-attr-cfi-encoding.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs
index 63e63c5d4aa..da608e180c5 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs
@@ -521,15 +521,15 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { }
 // CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"}
 // CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"}
 // CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"}
-// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"}
-// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"}
-// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"}
-// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"}
-// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"}
-// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"}
-// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"}
-// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"}
-// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME:[0-9]{1,2}[a-z_]{1,99}]]7Struct1Iu3i32EEE"}
+// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32EES1_E"}
+// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]5Enum1Iu3i32EEE"}
+// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]5Enum1Iu3i32EES1_E"}
+// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]5Enum1Iu3i32EES1_S1_E"}
+// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Union1Iu3i32EEE"}
+// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Union1Iu3i32EES1_E"}
+// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Union1Iu3i32EES1_S1_E"}
 // CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"}
 // CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"}
 // CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"}
@@ -560,45 +560,45 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { }
 // CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"}
 // CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"}
 // CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"}
-// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"}
-// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"}
-// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"}
-// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"}
-// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"}
-// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"}
-// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"}
-// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"}
-// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"}
-// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"}
-// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"}
-// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"}
-// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"}
-// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"}
-// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"}
-// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"}
-// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"}
-// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"}
-// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32EE"}
-// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_E"}
-// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_S4_E"}
-// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"}
-// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"}
-// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"}
-// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"}
-// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"}
-// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"}
-// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"}
-// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"}
-// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"}
-// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"}
-// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"}
-// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"}
-// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"}
-// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"}
-// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"}
+// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"}
+// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"}
+// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"}
+// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"}
+// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"}
+// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"}
+// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"}
+// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"}
+// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"}
+// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"}
+// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"}
+// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"}
+// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"}
+// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"}
+// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"}
+// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait1Iu5paramEu6regionEu3i32EE"}
+// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait1Iu5paramEu6regionEu3i32ES4_E"}
+// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait1Iu5paramEu6regionEu3i32ES4_S4_E"}
+// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3i32S_EE"}
+// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3i32S_ES0_E"}
+// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3i32S_ES0_S0_E"}
+// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32ES_EE"}
+// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32ES_ES1_E"}
+// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32ES_ES1_S1_E"}
+// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13QuxIu3i32Lu5usize32EEE"}
+// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13QuxIu3i32Lu5usize32EES2_E"}
+// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13QuxIu3i32Lu5usize32EES2_S2_E"}
+// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"}
+// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"}
+// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"}
+// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3FooE"}
+// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3FooS_E"}
+// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3FooS_S_E"}
 // CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIvEE"}
 // CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIvES_E"}
 // CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"}
-// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarE"}
-// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_E"}
-// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_S_E"}
+// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3BarE"}
+// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3BarS_E"}
+// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3BarS_S_E"}
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs
index d200ed9798a..d200ed9798a 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
index cdefec17a1c..cdefec17a1c 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs
index f360b33ddcf..f360b33ddcf 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi.rs
index 3cb817b212d..3cb817b212d 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi.rs
diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-trait-objects.rs
index b69e57261a8..b69e57261a8 100644
--- a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-trait-objects.rs
diff --git a/tests/codegen/sanitizer-cfi-generalize-pointers.rs b/tests/codegen/sanitizer/cfi-generalize-pointers.rs
index 677ebdb27ec..677ebdb27ec 100644
--- a/tests/codegen/sanitizer-cfi-generalize-pointers.rs
+++ b/tests/codegen/sanitizer/cfi-generalize-pointers.rs
diff --git a/tests/codegen/sanitizer-cfi-normalize-integers.rs b/tests/codegen/sanitizer/cfi-normalize-integers.rs
index aa3913cb8e7..aa3913cb8e7 100644
--- a/tests/codegen/sanitizer-cfi-normalize-integers.rs
+++ b/tests/codegen/sanitizer/cfi-normalize-integers.rs
diff --git a/tests/codegen/sanitizer-kasan-emits-instrumentation.rs b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs
index d6e3f2719df..783bc47b9d0 100644
--- a/tests/codegen/sanitizer-kasan-emits-instrumentation.rs
+++ b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs
@@ -25,7 +25,7 @@ trait Copy {}
 
 impl Copy for u8 {}
 
-// CHECK-LABEL: ; sanitizer_kasan_emits_instrumentation::unsanitized
+// CHECK-LABEL: ; kasan_emits_instrumentation::unsanitized
 // CHECK-NEXT:  ; Function Attrs:
 // CHECK-NOT:   sanitize_address
 // CHECK:       start:
@@ -36,7 +36,7 @@ pub fn unsanitized(b: &mut u8) -> u8 {
     *b
 }
 
-// CHECK-LABEL: ; sanitizer_kasan_emits_instrumentation::sanitized
+// CHECK-LABEL: ; kasan_emits_instrumentation::sanitized
 // CHECK-NEXT:  ; Function Attrs:
 // CHECK:       sanitize_address
 // CHECK:       start:
diff --git a/tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs b/tests/codegen/sanitizer/kcfi-add-kcfi-flag.rs
index c2eb852aec3..c2eb852aec3 100644
--- a/tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs
+++ b/tests/codegen/sanitizer/kcfi-add-kcfi-flag.rs
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs
index bb317e4a2fa..001fc956aaa 100644
--- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs
@@ -20,7 +20,7 @@ impl Copy for i32 {}
 
 #[no_sanitize(kcfi)]
 pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
-    // CHECK-LABEL: sanitizer_kcfi_emit_kcfi_operand_bundle_attr_no_sanitize::foo
+    // CHECK-LABEL: kcfi_emit_kcfi_operand_bundle_attr_no_sanitize::foo
     // CHECK:       Function Attrs: {{.*}}
     // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}}
     // CHECK:       start:
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
index 29e4df3511f..29e4df3511f 100644
--- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
index 84d678a33ba..84d678a33ba 100644
--- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
index 761c37a9e06..761c37a9e06 100644
--- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
index 83cda0ef136..83cda0ef136 100644
--- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs
diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle.rs
index e1d617b5ee1..e1d617b5ee1 100644
--- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle.rs
diff --git a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi-emit-type-metadata-trait-objects.rs
index 7aed137f215..7aed137f215 100644
--- a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer/kcfi-emit-type-metadata-trait-objects.rs
diff --git a/tests/codegen/sanitizer-memory-track-orgins.rs b/tests/codegen/sanitizer/memory-track-origins.rs
index 4bd50508d15..4bd50508d15 100644
--- a/tests/codegen/sanitizer-memory-track-orgins.rs
+++ b/tests/codegen/sanitizer/memory-track-origins.rs
diff --git a/tests/codegen/sanitizer_memtag_attr_check.rs b/tests/codegen/sanitizer/memtag-attr-check.rs
index 2fd362656d4..2fd362656d4 100644
--- a/tests/codegen/sanitizer_memtag_attr_check.rs
+++ b/tests/codegen/sanitizer/memtag-attr-check.rs
diff --git a/tests/codegen/sanitizer-no-sanitize-inlining.rs b/tests/codegen/sanitizer/no-sanitize-inlining.rs
index f4af60baefe..f4af60baefe 100644
--- a/tests/codegen/sanitizer-no-sanitize-inlining.rs
+++ b/tests/codegen/sanitizer/no-sanitize-inlining.rs
diff --git a/tests/codegen/sanitizer-no-sanitize.rs b/tests/codegen/sanitizer/no-sanitize.rs
index fb9d249da03..783b568e279 100644
--- a/tests/codegen/sanitizer-no-sanitize.rs
+++ b/tests/codegen/sanitizer/no-sanitize.rs
@@ -7,7 +7,7 @@
 #![crate_type="lib"]
 #![feature(no_sanitize)]
 
-// CHECK-LABEL: ; sanitizer_no_sanitize::unsanitized
+// CHECK-LABEL: ; no_sanitize::unsanitized
 // CHECK-NEXT:  ; Function Attrs:
 // CHECK-NOT:   sanitize_address
 // CHECK:       start:
@@ -18,7 +18,7 @@ pub fn unsanitized(b: &mut u8) -> u8 {
     *b
 }
 
-// CHECK-LABEL: ; sanitizer_no_sanitize::sanitized
+// CHECK-LABEL: ; no_sanitize::sanitized
 // CHECK-NEXT:  ; Function Attrs:
 // CHECK:       sanitize_address
 // CHECK:       start:
diff --git a/tests/codegen/sanitizer-safestack-attr-check.rs b/tests/codegen/sanitizer/safestack-attr-check.rs
index b73ed00e730..b73ed00e730 100644
--- a/tests/codegen/sanitizer-safestack-attr-check.rs
+++ b/tests/codegen/sanitizer/safestack-attr-check.rs
diff --git a/tests/codegen/sanitizer-recover.rs b/tests/codegen/sanitizer/sanitizer-recover.rs
index 7b00fcf8e1b..7b00fcf8e1b 100644
--- a/tests/codegen/sanitizer-recover.rs
+++ b/tests/codegen/sanitizer/sanitizer-recover.rs
diff --git a/tests/codegen/sanitizer_scs_attr_check.rs b/tests/codegen/sanitizer/scs-attr-check.rs
index a885d911717..a885d911717 100644
--- a/tests/codegen/sanitizer_scs_attr_check.rs
+++ b/tests/codegen/sanitizer/scs-attr-check.rs
diff --git a/tests/codegen/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs
index 3116f9597bc..3116f9597bc 100644
--- a/tests/codegen/simd-wide-sum.rs
+++ b/tests/codegen/simd/simd-wide-sum.rs
diff --git a/tests/codegen/simd_arith_offset.rs b/tests/codegen/simd/simd_arith_offset.rs
index 1ee73de1186..1ee73de1186 100644
--- a/tests/codegen/simd_arith_offset.rs
+++ b/tests/codegen/simd/simd_arith_offset.rs
diff --git a/tests/codegen/swap-simd-types.rs b/tests/codegen/simd/swap-simd-types.rs
index 3472a42b0e6..3472a42b0e6 100644
--- a/tests/codegen/swap-simd-types.rs
+++ b/tests/codegen/simd/swap-simd-types.rs
diff --git a/tests/codegen/unpadded-simd.rs b/tests/codegen/simd/unpadded-simd.rs
index eb44dbd9313..eb44dbd9313 100644
--- a/tests/codegen/unpadded-simd.rs
+++ b/tests/codegen/simd/unpadded-simd.rs
diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
index 7e81367fc5b..0a02755a2cd 100644
--- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
@@ -1,7 +1,7 @@
 // needs-llvm-components: x86
 // compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
-#![feature(no_core, lang_items, c_unwind, abi_thiscall)]
+#![feature(no_core, lang_items, c_unwind)]
 #[lang="sized"]
 trait Sized { }
 
diff --git a/tests/codegen/vec-calloc-llvm14.rs b/tests/codegen/vec-calloc-llvm14.rs
deleted file mode 100644
index 08302796c41..00000000000
--- a/tests/codegen/vec-calloc-llvm14.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-// compile-flags: -O
-// only-x86_64
-// ignore-debug
-
-#![crate_type = "lib"]
-
-// CHECK-LABEL: @vec_zero_bytes
-#[no_mangle]
-pub fn vec_zero_bytes(n: usize) -> Vec<u8> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-    // CHECK-NOT: call {{.*}}llvm.memset
-
-    // CHECK: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-    // CHECK-NOT: call {{.*}}llvm.memset
-
-    // CHECK: ret void
-    vec![0; n]
-}
-
-// CHECK-LABEL: @vec_one_bytes
-#[no_mangle]
-pub fn vec_one_bytes(n: usize) -> Vec<u8> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK: call {{.*}}__rust_alloc(
-    // CHECK: call {{.*}}llvm.memset
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK: ret void
-    vec![1; n]
-}
-
-// CHECK-LABEL: @vec_zero_scalar
-#[no_mangle]
-pub fn vec_zero_scalar(n: usize) -> Vec<i32> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: ret void
-    vec![0; n]
-}
-
-// CHECK-LABEL: @vec_one_scalar
-#[no_mangle]
-pub fn vec_one_scalar(n: usize) -> Vec<i32> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK: call {{.*}}__rust_alloc(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK: ret void
-    vec![1; n]
-}
-
-// CHECK-LABEL: @vec_zero_rgb48
-#[no_mangle]
-pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: ret void
-    vec![[0, 0, 0]; n]
-}
-
-// CHECK-LABEL: @vec_zero_array_16
-#[no_mangle]
-pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: ret void
-    vec![[0_i64; 16]; n]
-}
-
-// CHECK-LABEL: @vec_zero_tuple
-#[no_mangle]
-pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc(
-
-    // CHECK: ret void
-    vec![(0, 0, '\0'); n]
-}
-
-// CHECK-LABEL: @vec_non_zero_tuple
-#[no_mangle]
-pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK: call {{.*}}__rust_alloc(
-
-    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
-    // CHECK-NOT: call {{.*}}reserve
-    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
-
-    // CHECK: ret void
-    vec![(0, 0, 'A'); n]
-}
diff --git a/tests/run-make/pretty-print-with-dep-file/Makefile b/tests/run-make/pretty-print-with-dep-file/Makefile
new file mode 100644
index 00000000000..fa8089eb6a5
--- /dev/null
+++ b/tests/run-make/pretty-print-with-dep-file/Makefile
@@ -0,0 +1,9 @@
+include ../tools.mk
+
+all:
+	$(RUSTC) --emit=dep-info -Zunpretty=expanded with-dep.rs
+	$(CGREP) "with-dep.rs" < $(TMPDIR)/with-dep.d
+	-rm $(TMPDIR)/with-dep.d
+
+	$(RUSTC) --emit=dep-info -Zunpretty=normal with-dep.rs
+	! test -f $(TMPDIR)/with-dep.d
diff --git a/tests/run-make/pretty-print-with-dep-file/with-dep.rs b/tests/run-make/pretty-print-with-dep-file/with-dep.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/pretty-print-with-dep-file/with-dep.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/unknown-mod-stdin/Makefile b/tests/run-make/unknown-mod-stdin/Makefile
new file mode 100644
index 00000000000..c1931765382
--- /dev/null
+++ b/tests/run-make/unknown-mod-stdin/Makefile
@@ -0,0 +1,15 @@
+# ignore-windows
+
+include ../tools.mk
+
+all:
+	echo 'mod unknown;' | $(RUSTC) --crate-type rlib - >$(TMPDIR)/unknown-mod.stdout 2>$(TMPDIR)/unknown-mod.stderr || echo "failed successfully"
+
+# Bless like this: RUSTC_BLESS_TEST=1 ./x.py test tests/run-make/unknown-mod-stdin
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/unknown-mod.stdout unknown-mod.stdout
+	cp "$(TMPDIR)"/unknown-mod.stderr unknown-mod.stderr
+else
+	$(DIFF) unknown-mod.stdout "$(TMPDIR)"/unknown-mod.stdout
+	$(DIFF) unknown-mod.stderr "$(TMPDIR)"/unknown-mod.stderr
+endif
diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr
new file mode 100644
index 00000000000..d7258fe4f68
--- /dev/null
+++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr
@@ -0,0 +1,11 @@
+error[E0583]: file not found for module `unknown`
+ --> <anon>:1:1
+  |
+1 | mod unknown;
+  | ^^^^^^^^^^^^
+  |
+  = help: to create the module `unknown`, create file "unknown.rs" or "unknown/mod.rs"
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0583`.
diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stdout b/tests/run-make/unknown-mod-stdin/unknown-mod.stdout
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stdout
diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml
index 9cec6d2bbe8..f742b3186e5 100644
--- a/tests/rustdoc-gui/scrape-examples-toggle.goml
+++ b/tests/rustdoc-gui/scrape-examples-toggle.goml
@@ -28,18 +28,18 @@ define-function: (
 
 call-function: ("check-color", {
     "theme": "ayu",
-    "toggle_line_color": "rgb(153, 153, 153)",
-    "toggle_line_hover_color": "rgb(197, 197, 197)",
+    "toggle_line_color": "#999",
+    "toggle_line_hover_color": "#c5c5c5",
 })
 call-function: ("check-color", {
     "theme": "dark",
-    "toggle_line_color": "rgb(153, 153, 153)",
-    "toggle_line_hover_color": "rgb(197, 197, 197)",
+    "toggle_line_color": "#999",
+    "toggle_line_hover_color": "#c5c5c5",
 })
 call-function: ("check-color", {
     "theme": "light",
-    "toggle_line_color": "rgb(204, 204, 204)",
-    "toggle_line_hover_color": "rgb(153, 153, 153)",
+    "toggle_line_color": "#ccc",
+    "toggle_line_hover_color": "#999",
 })
 
 // Toggling all docs will close additional examples
diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml
index d21905e90ae..70aeda1769a 100644
--- a/tests/rustdoc-gui/search-error.goml
+++ b/tests/rustdoc-gui/search-error.goml
@@ -20,20 +20,20 @@ call-function: (
     "check-colors",
     {
         "theme": "ayu",
-        "error_background": "rgb(79, 76, 76)",
+        "error_background": "#4f4c4c",
     },
 )
 call-function: (
     "check-colors",
     {
         "theme": "dark",
-        "error_background": "rgb(72, 72, 72)",
+        "error_background": "#484848",
     },
 )
 call-function: (
     "check-colors",
     {
         "theme": "light",
-        "error_background": "rgb(208, 204, 204)",
+        "error_background": "#d0cccc",
     },
 )
diff --git a/tests/ui/abi/stack-protector.rs b/tests/ui/abi/stack-protector.rs
index 24bd2e21943..e94aa816d90 100644
--- a/tests/ui/abi/stack-protector.rs
+++ b/tests/ui/abi/stack-protector.rs
@@ -40,6 +40,8 @@ fn vulnerable_function() {
     // Overwrite the on-stack return address with the address of `malicious_code()`,
     // thereby jumping to that function when returning from `vulnerable_function()`.
     unsafe { fill(stackaddr, bad_code_ptr, 20); }
+    // Capture the address, so the write is not optimized away.
+    std::hint::black_box(stackaddr);
 }
 
 // Use an uninlined function with its own stack frame to make sure that we don't
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index e86a73ea60f..980457eeab5 100644
--- a/tests/ui/abi/unsupported.aarch64.stderr
+++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -1,53 +1,53 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:25:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:27:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:30:1
+  --> $DIR/unsupported.rs:29:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:32:1
+  --> $DIR/unsupported.rs:31:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+  --> $DIR/unsupported.rs:35:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:38:1
+  --> $DIR/unsupported.rs:37:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:40:1
+  --> $DIR/unsupported.rs:39:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:47:1
+  --> $DIR/unsupported.rs:46:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index f7569c8cdd7..450abd94886 100644
--- a/tests/ui/abi/unsupported.arm.stderr
+++ b/tests/ui/abi/unsupported.arm.stderr
@@ -1,47 +1,47 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:25:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:27:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:30:1
+  --> $DIR/unsupported.rs:29:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+  --> $DIR/unsupported.rs:35:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:38:1
+  --> $DIR/unsupported.rs:37:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:40:1
+  --> $DIR/unsupported.rs:39:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:47:1
+  --> $DIR/unsupported.rs:46:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr
index 7ca93516db9..0340382a452 100644
--- a/tests/ui/abi/unsupported.i686.stderr
+++ b/tests/ui/abi/unsupported.i686.stderr
@@ -1,35 +1,35 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:25:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:27:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:30:1
+  --> $DIR/unsupported.rs:29:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:32:1
+  --> $DIR/unsupported.rs:31:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+  --> $DIR/unsupported.rs:35:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:38:1
+  --> $DIR/unsupported.rs:37:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs
index 6427a5695c0..bcd95f1ed4c 100644
--- a/tests/ui/abi/unsupported.rs
+++ b/tests/ui/abi/unsupported.rs
@@ -15,7 +15,6 @@
     abi_ptx,
     abi_msp430_interrupt,
     abi_avr_interrupt,
-    abi_thiscall,
     abi_amdgpu_kernel,
     wasm_abi,
     abi_x86_interrupt
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr
index 26023a4584e..29eed8505b9 100644
--- a/tests/ui/abi/unsupported.x64.stderr
+++ b/tests/ui/abi/unsupported.x64.stderr
@@ -1,47 +1,47 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:25:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:27:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:30:1
+  --> $DIR/unsupported.rs:29:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:32:1
+  --> $DIR/unsupported.rs:31:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:36:1
+  --> $DIR/unsupported.rs:35:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:38:1
+  --> $DIR/unsupported.rs:37:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:43:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:47:1
+  --> $DIR/unsupported.rs:46:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/attributes/macro_export_on_decl_macro.rs b/tests/ui/attributes/macro_export_on_decl_macro.rs
new file mode 100644
index 00000000000..e6fe66ac6c3
--- /dev/null
+++ b/tests/ui/attributes/macro_export_on_decl_macro.rs
@@ -0,0 +1,9 @@
+// Using #[macro_export] on a decl macro has no effect and should warn
+
+#![feature(decl_macro)]
+#![deny(unused)]
+
+#[macro_export] //~ ERROR `#[macro_export]` has no effect on declarative macro definitions
+pub macro foo() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/macro_export_on_decl_macro.stderr b/tests/ui/attributes/macro_export_on_decl_macro.stderr
new file mode 100644
index 00000000000..565e07919bc
--- /dev/null
+++ b/tests/ui/attributes/macro_export_on_decl_macro.stderr
@@ -0,0 +1,16 @@
+error: `#[macro_export]` has no effect on declarative macro definitions
+  --> $DIR/macro_export_on_decl_macro.rs:6:1
+   |
+LL | #[macro_export]
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: declarative macros follow the same exporting rules as regular items
+note: the lint level is defined here
+  --> $DIR/macro_export_on_decl_macro.rs:4:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/const-generics/lifetime-in-const-param.rs b/tests/ui/const-generics/lifetime-in-const-param.rs
new file mode 100644
index 00000000000..be90dbb213e
--- /dev/null
+++ b/tests/ui/const-generics/lifetime-in-const-param.rs
@@ -0,0 +1,9 @@
+// https://github.com/rust-lang/rust/issues/113462
+
+struct S2<'b>(&'b ());
+
+struct S<'a, const N: S2>(&'a ());
+//~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR `S2<'_>` is forbidden as the type of a const generic parameter
+
+fn main() {}
diff --git a/tests/ui/const-generics/lifetime-in-const-param.stderr b/tests/ui/const-generics/lifetime-in-const-param.stderr
new file mode 100644
index 00000000000..8fd9068e8ef
--- /dev/null
+++ b/tests/ui/const-generics/lifetime-in-const-param.stderr
@@ -0,0 +1,18 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/lifetime-in-const-param.rs:5:23
+   |
+LL | struct S<'a, const N: S2>(&'a ());
+   |                       ^^ expected named lifetime parameter
+
+error: `S2<'_>` is forbidden as the type of a const generic parameter
+  --> $DIR/lifetime-in-const-param.rs:5:23
+   |
+LL | struct S<'a, const N: S2>(&'a ());
+   |                       ^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#![feature(adt_const_params)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/const_prop/ice-issue-111353.rs b/tests/ui/const_prop/ice-issue-111353.rs
new file mode 100644
index 00000000000..99d1b792fea
--- /dev/null
+++ b/tests/ui/const_prop/ice-issue-111353.rs
@@ -0,0 +1,7 @@
+// build-pass
+#![crate_type = "lib"]
+#![feature(unsized_fn_params)]
+
+pub fn f(mut x: [i32]) {
+    x[0] = 1;
+}
diff --git a/tests/ui/const_prop/ice-issue-96944.rs b/tests/ui/const_prop/ice-issue-96944.rs
new file mode 100644
index 00000000000..74baffddd8b
--- /dev/null
+++ b/tests/ui/const_prop/ice-issue-96944.rs
@@ -0,0 +1,26 @@
+// build-pass
+#![crate_type = "lib"]
+#![allow(arithmetic_overflow)]
+
+pub trait BitSplit {
+    type Half;
+    fn merge(halves: [Self::Half; 2]) -> Self;
+}
+
+macro_rules! impl_ints {
+    ($int:ty => $half:ty; $mask:expr) => {
+        impl BitSplit for $int {
+            type Half = $half;
+            #[inline]
+            fn merge(halves: [Self::Half; 2]) -> Self {
+                const HALF_SIZE: usize = std::mem::size_of::<$half>() * 8;
+                (halves[0] << HALF_SIZE) as $int | halves[1] as $int
+            }
+        }
+    };
+}
+
+impl_ints!(u128 => u64; 0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFF);
+impl_ints!( u64 => u32;                     0x0000_0000_FFFF_FFFF);
+impl_ints!( u32 => u16;                               0x0000_FFFF);
+impl_ints!( u16 =>  u8;                                    0x00FF);
diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs
new file mode 100644
index 00000000000..2b4062fd22b
--- /dev/null
+++ b/tests/ui/consts/const-compare-bytes-ub.rs
@@ -0,0 +1,41 @@
+// check-fail
+
+#![feature(core_intrinsics)]
+#![feature(const_intrinsic_compare_bytes)]
+use std::intrinsics::compare_bytes;
+use std::mem::MaybeUninit;
+
+fn main() {
+    const LHS_NULL: i32 = unsafe {
+        compare_bytes(0 as *const u8, 2 as *const u8, 0)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const RHS_NULL: i32 = unsafe {
+        compare_bytes(1 as *const u8, 0 as *const u8, 0)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const DANGLING_PTR_NON_ZERO_LENGTH: i32 = unsafe {
+        compare_bytes(1 as *const u8, 2 as *const u8, 1)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const LHS_OUT_OF_BOUNDS: i32 = unsafe {
+        compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const RHS_OUT_OF_BOUNDS: i32 = unsafe {
+        compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const LHS_UNINIT: i32 = unsafe {
+        compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const RHS_UNINIT: i32 = unsafe {
+        compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1)
+        //~^ ERROR evaluation of constant value failed
+    };
+    const WITH_PROVENANCE: i32 = unsafe {
+        compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::<usize>())
+        //~^ ERROR evaluation of constant value failed
+    };
+}
diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr
new file mode 100644
index 00000000000..54fafded07b
--- /dev/null
+++ b/tests/ui/consts/const-compare-bytes-ub.stderr
@@ -0,0 +1,54 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:10:9
+   |
+LL |         compare_bytes(0 as *const u8, 2 as *const u8, 0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:14:9
+   |
+LL |         compare_bytes(1 as *const u8, 0 as *const u8, 0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:18:9
+   |
+LL |         compare_bytes(1 as *const u8, 2 as *const u8, 1)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:22:9
+   |
+LL |         compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc6 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:26:9
+   |
+LL |         compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc13 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:30:9
+   |
+LL |         compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc17[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:34:9
+   |
+LL |         compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc25[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-compare-bytes-ub.rs:38:9
+   |
+LL |         compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::<usize>())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs
new file mode 100644
index 00000000000..74e29f81386
--- /dev/null
+++ b/tests/ui/consts/const-compare-bytes.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+#![feature(core_intrinsics)]
+#![feature(const_intrinsic_compare_bytes)]
+use std::intrinsics::compare_bytes;
+
+fn main() {
+    const A: i32 = unsafe {
+        compare_bytes(1 as *const u8, 2 as *const u8, 0)
+    };
+    assert_eq!(A, 0);
+
+    const B: i32 = unsafe {
+        compare_bytes([1, 2].as_ptr(), [1, 3].as_ptr(), 1)
+    };
+    assert_eq!(B, 0);
+
+    const C: i32 = unsafe {
+        compare_bytes([1, 2, 9].as_ptr(), [1, 3, 8].as_ptr(), 2)
+    };
+    assert!(C < 0);
+
+    const D: i32 = unsafe {
+        compare_bytes([1, 3, 8].as_ptr(), [1, 2, 9].as_ptr(), 2)
+    };
+    assert!(D > 0);
+}
diff --git a/tests/ui/extern/extern-thiscall.rs b/tests/ui/extern/extern-thiscall.rs
index 717df57ec48..c491c156af5 100644
--- a/tests/ui/extern/extern-thiscall.rs
+++ b/tests/ui/extern/extern-thiscall.rs
@@ -1,8 +1,6 @@
 // run-pass
 // only-x86
 
-#![feature(abi_thiscall)]
-
 trait A {
     extern "thiscall" fn test1(i: i32);
 }
diff --git a/tests/ui/feature-gates/feature-gate-thiscall.rs b/tests/ui/feature-gates/feature-gate-thiscall.rs
deleted file mode 100644
index 97a732bcff7..00000000000
--- a/tests/ui/feature-gates/feature-gate-thiscall.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// gate-test-abi_thiscall
-// needs-llvm-components: x86
-// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib
-#![no_core]
-#![feature(no_core, lang_items)]
-#[lang="sized"]
-trait Sized { }
-
-// Test that the "thiscall" ABI is feature-gated, and cannot be used when
-// the `abi_thiscall` feature gate is not used.
-
-extern "thiscall-unwind" fn fu() {} //~ ERROR thiscall-unwind ABI is experimental
-extern "thiscall" fn f() {} //~ ERROR thiscall is experimental
-
-trait T {
-    extern "thiscall" fn m(); //~ ERROR thiscall is experimental
-    extern "thiscall-unwind" fn mu(); //~ ERROR thiscall-unwind ABI is experimental
-
-    extern "thiscall" fn dm() {} //~ ERROR thiscall is experimental
-    extern "thiscall-unwind" fn dmu() {} //~ ERROR thiscall-unwind ABI is experimental
-}
-
-struct S;
-impl T for S {
-    extern "thiscall" fn m() {} //~ ERROR thiscall is experimental
-    extern "thiscall-unwind" fn mu() {} //~ ERROR thiscall-unwind ABI is experimental
-}
-
-impl S {
-    extern "thiscall" fn im() {} //~ ERROR thiscall is experimental
-    extern "thiscall-unwind" fn imu() {} //~ ERROR thiscall-unwind ABI is experimental
-}
-
-type TA = extern "thiscall" fn(); //~ ERROR thiscall is experimental
-type TAU = extern "thiscall-unwind" fn(); //~ ERROR thiscall-unwind ABI is experimental
-
-extern "thiscall" {} //~ ERROR thiscall is experimental
-extern "thiscall-unwind" {} //~ ERROR thiscall-unwind ABI is experimental
diff --git a/tests/ui/feature-gates/feature-gate-thiscall.stderr b/tests/ui/feature-gates/feature-gate-thiscall.stderr
deleted file mode 100644
index 346e45952cd..00000000000
--- a/tests/ui/feature-gates/feature-gate-thiscall.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:12:8
-   |
-LL | extern "thiscall-unwind" fn fu() {}
-   |        ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:13:8
-   |
-LL | extern "thiscall" fn f() {}
-   |        ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:16:12
-   |
-LL |     extern "thiscall" fn m();
-   |            ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:17:12
-   |
-LL |     extern "thiscall-unwind" fn mu();
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:19:12
-   |
-LL |     extern "thiscall" fn dm() {}
-   |            ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:20:12
-   |
-LL |     extern "thiscall-unwind" fn dmu() {}
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:25:12
-   |
-LL |     extern "thiscall" fn m() {}
-   |            ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:26:12
-   |
-LL |     extern "thiscall-unwind" fn mu() {}
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:30:12
-   |
-LL |     extern "thiscall" fn im() {}
-   |            ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:31:12
-   |
-LL |     extern "thiscall-unwind" fn imu() {}
-   |            ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:34:18
-   |
-LL | type TA = extern "thiscall" fn();
-   |                  ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:35:19
-   |
-LL | type TAU = extern "thiscall-unwind" fn();
-   |                   ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:37:8
-   |
-LL | extern "thiscall" {}
-   |        ^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error[E0658]: thiscall-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-thiscall.rs:38:8
-   |
-LL | extern "thiscall-unwind" {}
-   |        ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable
-
-error: aborting due to 14 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr
index d55efedfcbe..0955efdbb73 100644
--- a/tests/ui/for/issue-20605.next.stderr
+++ b/tests/ui/for/issue-20605.next.stderr
@@ -34,12 +34,6 @@ error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIte
 LL |     for item in *things { *item = 0 }
    |                 ^^^^^^^
 
-error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced
-  --> $DIR/issue-20605.rs:5:27
-   |
-LL |     for item in *things { *item = 0 }
-   |                           ^^^^^
-
 error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time
   --> $DIR/issue-20605.rs:5:9
    |
@@ -66,6 +60,12 @@ LL |     for item in *things { *item = 0 }
 note: required by a bound in `None`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
+error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced
+  --> $DIR/issue-20605.rs:5:27
+   |
+LL |     for item in *things { *item = 0 }
+   |                           ^^^^^
+
 error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0277, E0614.
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.rs b/tests/ui/generic-associated-types/issue-90014-tait2.rs
index 34330ed8cba..7fb14eddc2c 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.rs
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.rs
@@ -1,27 +1,9 @@
 //! This test checks that opaque type collection doesn't try to normalize the projection
 //! without respecting its binders (which would ICE).
 //! Unfortunately we don't even reach opaque type collection, as we ICE in typeck before that.
-// known-bug: #109281
-// failure-status: 101
-// error-pattern:internal compiler error
-// normalize-stderr-test "internal compiler error.*" -> ""
-// normalize-stderr-test "DefId\([^)]*\)" -> "..."
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
-// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
-// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
-// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
-// normalize-stderr-test "stack backtrace:\n" -> ""
-// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
-// normalize-stderr-test "\s at .*\n" -> ""
-// normalize-stderr-test ".*note: Some details.*\n" -> ""
-// normalize-stderr-test "\n\n[ ]*\n" -> ""
-// normalize-stderr-test "compiler/.*: projection" -> "projection"
-// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
-// normalize-stderr-test "error: [\s\n]*query stack" -> "error: query stack"
-// normalize-stderr-test "[\n\s]*\nquery stack during panic:" -> "query stack during panic:"
+//! See #109281 for the original report.
 // edition:2018
+// error-pattern: expected generic lifetime parameter, found `'a`
 
 #![feature(type_alias_impl_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
index 2538eb46dfa..d04788a919a 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.stderr
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
@@ -1,12 +1,5 @@
-error: 
-  --> $DIR/issue-90014-tait2.rs:44:27
-   |
-LL |     fn make_fut(&self) -> Box<dyn for<'a> Trait<'a, Thing = Fut<'a>>> {
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^query stack during panic:
-#0 [typeck] type-checking `<impl at $DIR/issue-90014-tait2.rs:43:1: 43:13>::make_fut`
-#1 [type_of] computing type of `Fut::{opaque#0}`
-#2 [check_mod_item_types] checking item types in top-level module
-#3 [analysis] running analysis passes on this crate
-end of query stack
+error[E0792]: expected generic lifetime parameter, found `'a`
+
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/issues/issue-100605.rs b/tests/ui/issues/issue-100605.rs
deleted file mode 100644
index 917a45c15bb..00000000000
--- a/tests/ui/issues/issue-100605.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-fn takes_option(_arg: Option<&String>) {}
-
-fn main() {
-    takes_option(&None); //~ ERROR 4:18: 4:23: mismatched types [E0308]
-
-    let x = String::from("x");
-    let res = Some(x);
-    takes_option(&res); //~ ERROR 8:18: 8:22: mismatched types [E0308]
-}
diff --git a/tests/ui/lazy-type-alias/auxiliary/eager.rs b/tests/ui/lazy-type-alias/auxiliary/eager.rs
new file mode 100644
index 00000000000..8793a1701ec
--- /dev/null
+++ b/tests/ui/lazy-type-alias/auxiliary/eager.rs
@@ -0,0 +1,6 @@
+// This crate does *not* have lazy type aliases enabled.
+
+#![allow(type_alias_bounds)]
+
+// The `Copy` bound is ignored both locally and externally for backward compatibility.
+pub type Alias<T: Copy> = Option<T>;
diff --git a/tests/ui/lazy-type-alias/auxiliary/lazy.rs b/tests/ui/lazy-type-alias/auxiliary/lazy.rs
new file mode 100644
index 00000000000..caa7999b4f7
--- /dev/null
+++ b/tests/ui/lazy-type-alias/auxiliary/lazy.rs
@@ -0,0 +1,4 @@
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+pub type Alias<T: Copy> = Option<T>;
diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr b/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr
new file mode 100644
index 00000000000..98b3921dec4
--- /dev/null
+++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr
@@ -0,0 +1,11 @@
+warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/coerce-behind-lazy.rs:5:12
+   |
+LL | #![feature(lazy_type_alias)]
+   |            ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr b/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr
new file mode 100644
index 00000000000..98b3921dec4
--- /dev/null
+++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr
@@ -0,0 +1,11 @@
+warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/coerce-behind-lazy.rs:5:12
+   |
+LL | #![feature(lazy_type_alias)]
+   |            ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.rs b/tests/ui/lazy-type-alias/coerce-behind-lazy.rs
new file mode 100644
index 00000000000..745eadb9625
--- /dev/null
+++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.rs
@@ -0,0 +1,16 @@
+// check-pass
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+#![feature(lazy_type_alias)]
+//~^ WARN the feature `lazy_type_alias` is incomplete
+
+use std::any::Any;
+
+type Coerce = Box<dyn Any>;
+
+fn test() -> Coerce {
+    Box::new(1)
+}
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs b/tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs
new file mode 100644
index 00000000000..07389961c4c
--- /dev/null
+++ b/tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs
@@ -0,0 +1,23 @@
+// This test serves as a regression test for issue #114468 and it also ensures that we consider
+// type aliases from external crates that don't have `lazy_type_alias` enabled to be eager.
+
+// aux-crate:eager=eager.rs
+// edition: 2021
+// check-pass
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// This used to crash when we were computing the variances of `Struct` since we would convert
+// `eager::Alias<T>` to a weak projection due to the presence of `#![feature(lazy_type_alias)]` in
+// this (!) crate and subsequently attempt to obtain the variances of the type alias associated with
+// the weak projection which would panic because we don't compute this information for eager type
+// aliases at all.
+struct Struct<T>(eager::Alias<T>);
+
+fn main() {
+    // We want to ignore (or rather “end up ignoring”) the bound `T: Copy` since `Alias` should be
+    // treated as an eager type alias not just inside the crate it is defined in but also in
+    // dependent crates (like this one).
+    let _: eager::Alias<String>;
+}
diff --git a/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr
new file mode 100644
index 00000000000..9e0e2bfa872
--- /dev/null
+++ b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/extern-crate-has-lazy-type-aliases.rs:15:12
+   |
+LL |     let _: lazy::Alias<String>;
+   |            ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+note: required by a bound on the type alias `Alias`
+  --> $DIR/auxiliary/lazy.rs:4:19
+   |
+LL | pub type Alias<T: Copy> = Option<T>;
+   |                   ^^^^ required by this bound
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr
new file mode 100644
index 00000000000..9e0e2bfa872
--- /dev/null
+++ b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/extern-crate-has-lazy-type-aliases.rs:15:12
+   |
+LL |     let _: lazy::Alias<String>;
+   |            ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+note: required by a bound on the type alias `Alias`
+  --> $DIR/auxiliary/lazy.rs:4:19
+   |
+LL | pub type Alias<T: Copy> = Option<T>;
+   |                   ^^^^ required by this bound
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs
new file mode 100644
index 00000000000..31a19161b6c
--- /dev/null
+++ b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs
@@ -0,0 +1,16 @@
+// revisions: locally_eager locally_lazy
+// aux-crate:lazy=lazy.rs
+// edition: 2021
+
+// Test that we treat lazy type aliases from external crates as lazy independently of whether the
+// local crate enables `lazy_type_alias` or not.
+
+#![cfg_attr(
+    locally_lazy,
+    feature(lazy_type_alias),
+    allow(incomplete_features)
+)]
+
+fn main() {
+    let _: lazy::Alias<String>; //~ ERROR the trait bound `String: Copy` is not satisfied
+}
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index 4994e4dc444..01ec69a6110 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -3,11 +3,6 @@ error[E0106]: missing lifetime specifier
    |
 LL | fn d<const C: S>() {}
    |               ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL | fn d<'a, const C: S<'a>>() {}
-   |      +++           ++++
 
 error[E0770]: the type of const parameters must not depend on other generic parameters
   --> $DIR/unusual-rib-combinations.rs:29:22
diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr
index 5d457ba0ec7..0d269e599dd 100644
--- a/tests/ui/lint/clashing-extern-fn.stderr
+++ b/tests/ui/lint/clashing-extern-fn.stderr
@@ -1,11 +1,30 @@
+warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
+  --> $DIR/clashing-extern-fn.rs:433:55
+   |
+LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
+   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+   = note: `#[warn(improper_ctypes)]` on by default
+
+warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe
+  --> $DIR/clashing-extern-fn.rs:437:46
+   |
+LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 warning: `clash` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:14:13
    |
 LL |             fn clash(x: u8);
-   |             ---------------- `clash` previously declared here
+   |             --------------- `clash` previously declared here
 ...
 LL |             fn clash(x: u64);
-   |             ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(u8)`
               found `unsafe extern "C" fn(u64)`
@@ -18,12 +37,11 @@ LL | #![warn(clashing_extern_declarations)]
 warning: `extern_link_name` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:52:9
    |
-LL | /     #[link_name = "extern_link_name"]
-LL | |     fn some_new_name(x: i16);
-   | |_____________________________- `extern_link_name` previously declared here
+LL |     #[link_name = "extern_link_name"]
+   |     --------------------------------- `extern_link_name` previously declared here
 ...
-LL |           fn extern_link_name(x: u32);
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+LL |         fn extern_link_name(x: u32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(i16)`
               found `unsafe extern "C" fn(u32)`
@@ -31,13 +49,11 @@ LL |           fn extern_link_name(x: u32);
 warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
   --> $DIR/clashing-extern-fn.rs:55:9
    |
-LL |       fn some_other_new_name(x: i16);
-   |       ------------------------------- `some_other_new_name` previously declared here
+LL |     fn some_other_new_name(x: i16);
+   |     ------------------------------ `some_other_new_name` previously declared here
 ...
-LL | /         #[link_name = "some_other_new_name"]
-LL | |
-LL | |         fn some_other_extern_link_name(x: u32);
-   | |_______________________________________________^ this signature doesn't match the previous declaration
+LL |         #[link_name = "some_other_new_name"]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(i16)`
               found `unsafe extern "C" fn(u32)`
@@ -45,14 +61,11 @@ LL | |         fn some_other_extern_link_name(x: u32);
 warning: `other_both_names_different` redeclares `link_name_same` with a different signature
   --> $DIR/clashing-extern-fn.rs:59:9
    |
-LL | /     #[link_name = "link_name_same"]
-LL | |     fn both_names_different(x: i16);
-   | |____________________________________- `link_name_same` previously declared here
+LL |     #[link_name = "link_name_same"]
+   |     ------------------------------- `link_name_same` previously declared here
 ...
-LL | /         #[link_name = "link_name_same"]
-LL | |
-LL | |         fn other_both_names_different(x: u32);
-   | |______________________________________________^ this signature doesn't match the previous declaration
+LL |         #[link_name = "link_name_same"]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(i16)`
               found `unsafe extern "C" fn(u32)`
@@ -61,10 +74,10 @@ warning: `different_mod` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:72:9
    |
 LL |         fn different_mod(x: u8);
-   |         ------------------------ `different_mod` previously declared here
+   |         ----------------------- `different_mod` previously declared here
 ...
 LL |         fn different_mod(x: u64);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(u8)`
               found `unsafe extern "C" fn(u64)`
@@ -73,10 +86,10 @@ warning: `variadic_decl` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:82:9
    |
 LL |     fn variadic_decl(x: u8, ...);
-   |     ----------------------------- `variadic_decl` previously declared here
+   |     ---------------------------- `variadic_decl` previously declared here
 ...
 LL |         fn variadic_decl(x: u8);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(u8, ...)`
               found `unsafe extern "C" fn(u8)`
@@ -85,10 +98,10 @@ warning: `weigh_banana` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:142:13
    |
 LL |             fn weigh_banana(count: *const Banana) -> u64;
-   |             --------------------------------------------- `weigh_banana` previously declared here
+   |             -------------------------------------------- `weigh_banana` previously declared here
 ...
 LL |             fn weigh_banana(count: *const Banana) -> u64;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(*const one::Banana) -> u64`
               found `unsafe extern "C" fn(*const three::Banana) -> u64`
@@ -97,10 +110,10 @@ warning: `draw_point` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:171:13
    |
 LL |             fn draw_point(p: Point);
-   |             ------------------------ `draw_point` previously declared here
+   |             ----------------------- `draw_point` previously declared here
 ...
 LL |             fn draw_point(p: Point);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
               found `unsafe extern "C" fn(sameish_members::b::Point)`
@@ -109,10 +122,10 @@ warning: `origin` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:197:13
    |
 LL |             fn origin() -> Point3;
-   |             ---------------------- `origin` previously declared here
+   |             --------------------- `origin` previously declared here
 ...
 LL |             fn origin() -> Point3;
-   |             ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3`
               found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
@@ -121,10 +134,10 @@ warning: `transparent_incorrect` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:220:13
    |
 LL |             fn transparent_incorrect() -> T;
-   |             -------------------------------- `transparent_incorrect` previously declared here
+   |             ------------------------------- `transparent_incorrect` previously declared here
 ...
 LL |             fn transparent_incorrect() -> isize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> T`
               found `unsafe extern "C" fn() -> isize`
@@ -133,10 +146,10 @@ warning: `missing_return_type` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:259:13
    |
 LL |             fn missing_return_type() -> usize;
-   |             ---------------------------------- `missing_return_type` previously declared here
+   |             --------------------------------- `missing_return_type` previously declared here
 ...
 LL |             fn missing_return_type();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> usize`
               found `unsafe extern "C" fn()`
@@ -145,10 +158,10 @@ warning: `non_zero_usize` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:277:13
    |
 LL |             fn non_zero_usize() -> core::num::NonZeroUsize;
-   |             ----------------------------------------------- `non_zero_usize` previously declared here
+   |             ---------------------------------------------- `non_zero_usize` previously declared here
 ...
 LL |             fn non_zero_usize() -> usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> NonZeroUsize`
               found `unsafe extern "C" fn() -> usize`
@@ -157,10 +170,10 @@ warning: `non_null_ptr` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:279:13
    |
 LL |             fn non_null_ptr() -> core::ptr::NonNull<usize>;
-   |             ----------------------------------------------- `non_null_ptr` previously declared here
+   |             ---------------------------------------------- `non_null_ptr` previously declared here
 ...
 LL |             fn non_null_ptr() -> *const usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> NonNull<usize>`
               found `unsafe extern "C" fn() -> *const usize`
@@ -169,10 +182,10 @@ warning: `option_non_zero_usize_incorrect` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:377:13
    |
 LL |             fn option_non_zero_usize_incorrect() -> usize;
-   |             ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
+   |             --------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
 ...
 LL |             fn option_non_zero_usize_incorrect() -> isize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> usize`
               found `unsafe extern "C" fn() -> isize`
@@ -181,10 +194,10 @@ warning: `option_non_null_ptr_incorrect` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:379:13
    |
 LL |             fn option_non_null_ptr_incorrect() -> *const usize;
-   |             --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
+   |             -------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
 ...
 LL |             fn option_non_null_ptr_incorrect() -> *const isize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> *const usize`
               found `unsafe extern "C" fn() -> *const isize`
@@ -193,10 +206,10 @@ warning: `hidden_niche_transparent_no_niche` redeclared with a different signatu
   --> $DIR/clashing-extern-fn.rs:433:13
    |
 LL |             fn hidden_niche_transparent_no_niche() -> usize;
-   |             ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
+   |             ----------------------------------------------- `hidden_niche_transparent_no_niche` previously declared here
 ...
 LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> usize`
               found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
@@ -205,32 +218,13 @@ warning: `hidden_niche_unsafe_cell` redeclared with a different signature
   --> $DIR/clashing-extern-fn.rs:437:13
    |
 LL |             fn hidden_niche_unsafe_cell() -> usize;
-   |             --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
+   |             -------------------------------------- `hidden_niche_unsafe_cell` previously declared here
 ...
 LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn() -> usize`
               found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
 
-warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:433:55
-   |
-LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
-   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-   = note: enum has no representation hint
-   = note: `#[warn(improper_ctypes)]` on by default
-
-warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:437:46
-   |
-LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-   = note: enum has no representation hint
-
 warning: 19 warnings emitted
 
diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr
index 054c06d38b3..f2d55c107ba 100644
--- a/tests/ui/lint/invalid-nan-comparison.stderr
+++ b/tests/ui/lint/invalid-nan-comparison.stderr
@@ -5,11 +5,6 @@ LL | const TEST: bool = 5f32 == f32::NAN;
    |                    ^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(invalid_nan_comparisons)]` on by default
-help: use `f32::is_nan()` or `f64::is_nan()` instead
-   |
-LL - const TEST: bool = 5f32 == f32::NAN;
-LL + const TEST: bool = 5f32.is_nan();
-   |
 
 warning: incorrect NaN comparison, NaN cannot be directly compared to itself
   --> $DIR/invalid-nan-comparison.rs:14:5
diff --git a/tests/ui/lint/issue-111359.stderr b/tests/ui/lint/issue-111359.stderr
index 2296d8413d6..0aef5007a2b 100644
--- a/tests/ui/lint/issue-111359.stderr
+++ b/tests/ui/lint/issue-111359.stderr
@@ -1,26 +1,26 @@
-error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
+error: type could implement `Copy`; consider adding `impl Copy`
   --> $DIR/issue-111359.rs:7:5
    |
 LL |     pub struct BarPub;
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-111359.rs:1:8
+  --> $DIR/issue-111359.rs:2:8
    |
-LL | #[deny(missing_debug_implementations)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deny(missing_copy_implementations)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: type could implement `Copy`; consider adding `impl Copy`
+error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
   --> $DIR/issue-111359.rs:7:5
    |
 LL |     pub struct BarPub;
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-111359.rs:2:8
+  --> $DIR/issue-111359.rs:1:8
    |
-LL | #[deny(missing_copy_implementations)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deny(missing_debug_implementations)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lint/issue-1866.stderr b/tests/ui/lint/issue-1866.stderr
index d19a1349668..36d323825a4 100644
--- a/tests/ui/lint/issue-1866.stderr
+++ b/tests/ui/lint/issue-1866.stderr
@@ -2,10 +2,10 @@ warning: `rust_task_is_unwinding` redeclared with a different signature
   --> $DIR/issue-1866.rs:23:13
    |
 LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
-   |             ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
+   |             ----------------------------------------------------------- `rust_task_is_unwinding` previously declared here
 ...
 LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
    = note: expected `unsafe extern "C" fn(*const usize) -> bool`
               found `unsafe extern "C" fn(*const bool) -> bool`
diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr
index 9587556b0c1..7fe078068fe 100644
--- a/tests/ui/lint/lint-attr-everywhere-late.stderr
+++ b/tests/ui/lint/lint-attr-everywhere-late.stderr
@@ -34,12 +34,6 @@ note: the lint level is defined here
 LL |     #![deny(missing_docs)]
    |             ^^^^^^^^^^^^
 
-error: missing documentation for a function
-  --> $DIR/lint-attr-everywhere-late.rs:47:5
-   |
-LL |     pub fn missing_inner() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
 error: missing documentation for an associated function
   --> $DIR/lint-attr-everywhere-late.rs:54:5
    |
@@ -142,52 +136,6 @@ note: the lint level is defined here
 LL |     #[deny(missing_docs)]
    |            ^^^^^^^^^^^^
 
-error: missing documentation for a variant
-  --> $DIR/lint-attr-everywhere-late.rs:112:5
-   |
-LL |     Variant1,
-   |     ^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:111:12
-   |
-LL |     #[deny(missing_docs)]
-   |            ^^^^^^^^^^^^
-
-error: `clashing1` redeclared with a different signature
-  --> $DIR/lint-attr-everywhere-late.rs:123:5
-   |
-LL |         fn clashing1();
-   |         --------------- `clashing1` previously declared here
-...
-LL |     fn clashing1(_: i32);
-   |     ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
-   |
-   = note: expected `unsafe extern "C" fn()`
-              found `unsafe extern "C" fn(i32)`
-note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:122:13
-   |
-LL |     #![deny(clashing_extern_declarations)]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `clashing2` redeclared with a different signature
-  --> $DIR/lint-attr-everywhere-late.rs:128:5
-   |
-LL |         fn clashing2();
-   |         --------------- `clashing2` previously declared here
-...
-LL |     fn clashing2(_: i32);
-   |     ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
-   |
-   = note: expected `unsafe extern "C" fn()`
-              found `unsafe extern "C" fn(i32)`
-note: the lint level is defined here
-  --> $DIR/lint-attr-everywhere-late.rs:127:12
-   |
-LL |     #[deny(clashing_extern_declarations)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped
   --> $DIR/lint-attr-everywhere-late.rs:93:38
    |
@@ -230,6 +178,18 @@ note: the lint level is defined here
 LL |     #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000;
    |            ^^^^^^^^^^^^^^^^^^^^
 
+error: missing documentation for a variant
+  --> $DIR/lint-attr-everywhere-late.rs:112:5
+   |
+LL |     Variant1,
+   |     ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:111:12
+   |
+LL |     #[deny(missing_docs)]
+   |            ^^^^^^^^^^^^
+
 error: variable `PARAM` should have a snake case name
   --> $DIR/lint-attr-everywhere-late.rs:131:37
    |
@@ -436,5 +396,45 @@ note: the lint level is defined here
 LL |     TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: missing documentation for a function
+  --> $DIR/lint-attr-everywhere-late.rs:47:5
+   |
+LL |     pub fn missing_inner() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `clashing1` redeclared with a different signature
+  --> $DIR/lint-attr-everywhere-late.rs:123:5
+   |
+LL |         fn clashing1();
+   |         -------------- `clashing1` previously declared here
+...
+LL |     fn clashing1(_: i32);
+   |     ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn()`
+              found `unsafe extern "C" fn(i32)`
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:122:13
+   |
+LL |     #![deny(clashing_extern_declarations)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `clashing2` redeclared with a different signature
+  --> $DIR/lint-attr-everywhere-late.rs:128:5
+   |
+LL |         fn clashing2();
+   |         -------------- `clashing2` previously declared here
+...
+LL |     fn clashing2(_: i32);
+   |     ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn()`
+              found `unsafe extern "C" fn(i32)`
+note: the lint level is defined here
+  --> $DIR/lint-attr-everywhere-late.rs:127:12
+   |
+LL |     #[deny(clashing_extern_declarations)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 32 previous errors
 
diff --git a/tests/ui/lint/lint-missing-doc.stderr b/tests/ui/lint/lint-missing-doc.stderr
index adcc21c44b2..4e9ee4f2769 100644
--- a/tests/ui/lint/lint-missing-doc.stderr
+++ b/tests/ui/lint/lint-missing-doc.stderr
@@ -113,24 +113,6 @@ LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:174:5
-   |
-LL |     pub fn undocumented1() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:175:5
-   |
-LL |     pub fn undocumented2() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:181:9
-   |
-LL |         pub fn also_undocumented1() {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
   --> $DIR/lint-missing-doc.rs:196:5
    |
 LL |     pub fn extern_fn_undocumented(f: f32) -> f32;
@@ -154,5 +136,23 @@ error: missing documentation for a trait alias
 LL | pub trait T = Sync;
    | ^^^^^^^^^^^
 
+error: missing documentation for a function
+  --> $DIR/lint-missing-doc.rs:174:5
+   |
+LL |     pub fn undocumented1() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/lint-missing-doc.rs:175:5
+   |
+LL |     pub fn undocumented2() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+  --> $DIR/lint-missing-doc.rs:181:9
+   |
+LL |         pub fn also_undocumented1() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 25 previous errors
 
diff --git a/tests/ui/lint/lint-unconditional-drop-recursion.rs b/tests/ui/lint/lint-unconditional-drop-recursion.rs
new file mode 100644
index 00000000000..348cd280139
--- /dev/null
+++ b/tests/ui/lint/lint-unconditional-drop-recursion.rs
@@ -0,0 +1,38 @@
+// Because drop recursion can only be detected after drop elaboration which
+// happens for codegen:
+// build-fail
+
+#![deny(unconditional_recursion)]
+#![allow(dead_code)]
+
+pub struct RecursiveDrop;
+
+impl Drop for RecursiveDrop {
+    fn drop(&mut self) { //~ ERROR function cannot return without recursing
+        let _ = RecursiveDrop;
+    }
+}
+
+#[derive(Default)]
+struct NotRecursiveDrop1;
+
+impl Drop for NotRecursiveDrop1 {
+    fn drop(&mut self) {
+        // Before drop elaboration, the MIR can look like a recursive drop will
+        // occur. But it will not, since forget() prevents drop() from running.
+        let taken = std::mem::take(self);
+        std::mem::forget(taken);
+    }
+}
+
+struct NotRecursiveDrop2;
+
+impl Drop for NotRecursiveDrop2 {
+    fn drop(&mut self) {
+        // Before drop elaboration, the MIR can look like a recursive drop will
+        // occur. But it will not, since this will panic.
+        std::panic::panic_any(NotRecursiveDrop2);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-unconditional-drop-recursion.stderr b/tests/ui/lint/lint-unconditional-drop-recursion.stderr
new file mode 100644
index 00000000000..76f95481605
--- /dev/null
+++ b/tests/ui/lint/lint-unconditional-drop-recursion.stderr
@@ -0,0 +1,17 @@
+error: function cannot return without recursing
+  --> $DIR/lint-unconditional-drop-recursion.rs:11:5
+   |
+LL |     fn drop(&mut self) {
+   |     ^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |         let _ = RecursiveDrop;
+   |                              - recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+note: the lint level is defined here
+  --> $DIR/lint-unconditional-drop-recursion.rs:5:9
+   |
+LL | #![deny(unconditional_recursion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lint/missing-copy-implementations-negative-copy.rs b/tests/ui/lint/missing-copy-implementations-negative-copy.rs
new file mode 100644
index 00000000000..b29d2209fa9
--- /dev/null
+++ b/tests/ui/lint/missing-copy-implementations-negative-copy.rs
@@ -0,0 +1,15 @@
+// Regression test for issue #101980.
+// Ensure that we don't suggest impl'ing `Copy` for a type if it already impl's `!Copy`.
+
+// check-pass
+
+#![feature(negative_impls)]
+#![deny(missing_copy_implementations)]
+
+pub struct Struct {
+    pub field: i32,
+}
+
+impl !Copy for Struct {}
+
+fn main() {}
diff --git a/tests/ui/lint/missing-doc-private-macro.stderr b/tests/ui/lint/missing-doc-private-macro.stderr
index 979b007d0ec..18c8ad2de6b 100644
--- a/tests/ui/lint/missing-doc-private-macro.stderr
+++ b/tests/ui/lint/missing-doc-private-macro.stderr
@@ -1,8 +1,8 @@
 error: missing documentation for a macro
-  --> $DIR/missing-doc-private-macro.rs:31:5
+  --> $DIR/missing-doc-private-macro.rs:37:1
    |
-LL |     macro_rules! exported_to_top_level {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub macro top_level_pub_macro {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/missing-doc-private-macro.rs:5:9
@@ -11,10 +11,10 @@ LL | #![deny(missing_docs)]
    |         ^^^^^^^^^^^^
 
 error: missing documentation for a macro
-  --> $DIR/missing-doc-private-macro.rs:37:1
+  --> $DIR/missing-doc-private-macro.rs:31:5
    |
-LL | pub macro top_level_pub_macro {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     macro_rules! exported_to_top_level {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/missing_debug_impls.rs b/tests/ui/missing_debug_impls.rs
index dc4dacfc468..ccad861c037 100644
--- a/tests/ui/missing_debug_impls.rs
+++ b/tests/ui/missing_debug_impls.rs
@@ -35,4 +35,4 @@ struct PrivateStruct;
 enum PrivateEnum {}
 
 #[derive(Debug)]
-struct GenericType<T>(T);
+pub struct GenericType<T>(T);
diff --git a/tests/ui/nll/guarantor-issue-46974.rs b/tests/ui/nll/guarantor-issue-46974.rs
index 96af4bf5c36..93fdf7b460b 100644
--- a/tests/ui/nll/guarantor-issue-46974.rs
+++ b/tests/ui/nll/guarantor-issue-46974.rs
@@ -9,7 +9,6 @@ fn foo(s: &mut (i32,)) -> i32 {
 }
 
 fn bar(s: &Box<(i32,)>) -> &'static i32 {
-    // FIXME(#46983): error message should be better
     &s.0 //~ ERROR lifetime may not live long enough
 }
 
diff --git a/tests/ui/nll/guarantor-issue-46974.stderr b/tests/ui/nll/guarantor-issue-46974.stderr
index 7edc3dcc5cd..f09faf1630b 100644
--- a/tests/ui/nll/guarantor-issue-46974.stderr
+++ b/tests/ui/nll/guarantor-issue-46974.stderr
@@ -10,11 +10,10 @@ LL |     *x
    |     -- borrow later used here
 
 error: lifetime may not live long enough
-  --> $DIR/guarantor-issue-46974.rs:13:5
+  --> $DIR/guarantor-issue-46974.rs:12:5
    |
 LL | fn bar(s: &Box<(i32,)>) -> &'static i32 {
    |           - let's call the lifetime of this reference `'1`
-LL |     // FIXME(#46983): error message should be better
 LL |     &s.0
    |     ^^^^ returning this value requires that `'1` must outlive `'static`
 
diff --git a/tests/ui/panic-handler/weak-lang-item-2.rs b/tests/ui/panic-handler/weak-lang-item-2.rs
index a429d8fabc7..2cc5f23b45e 100644
--- a/tests/ui/panic-handler/weak-lang-item-2.rs
+++ b/tests/ui/panic-handler/weak-lang-item-2.rs
@@ -1,15 +1,15 @@
 // run-pass
 // aux-build:weak-lang-items.rs
 
-// ignore-emscripten no threads support
 // pretty-expanded FIXME #23616
 
 extern crate weak_lang_items as other;
 
-use std::thread;
-
 fn main() {
-    let _ = thread::spawn(move|| {
-        other::foo()
-    });
+    // The goal of the test is just to make sure other::foo() is referenced at link time. Since
+    // the function panics, to prevent it from running we gate it behind an always-false `if` that
+    // is not going to be optimized away.
+    if std::hint::black_box(false) {
+        other::foo();
+    }
 }
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index e476a8024fd..ac65ba07512 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -18,7 +18,7 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro
 use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*;
 #[macro_use /* 0#1 */]
 extern crate core /* 0#1 */;
-extern crate compiler_builtins /* 444 */ as _ /* 0#1 */;
+extern crate compiler_builtins /* 445 */ as _ /* 0#1 */;
 // Don't load unnecessary hygiene information from std
 extern crate std /* 0#0 */;
 
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index 23a21004238..4031eb98a38 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
 use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*;
 #[macro_use /* 0#1 */]
 extern crate core /* 0#2 */;
-extern crate compiler_builtins /* 444 */ as _ /* 0#2 */;
+extern crate compiler_builtins /* 445 */ as _ /* 0#2 */;
 // Don't load unnecessary hygiene information from std
 extern crate std /* 0#0 */;
 
diff --git a/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs
new file mode 100644
index 00000000000..83349dd3350
--- /dev/null
+++ b/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs
@@ -0,0 +1,10 @@
+#![deny(unused_qualifications)]
+// check-pass
+fn bar() {
+    match Option::<Option<()>>::None {
+        Some(v) => {}
+        None => {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/unresolved-segments-visibility.rs b/tests/ui/resolve/unresolved-segments-visibility.rs
new file mode 100644
index 00000000000..c26171f75d2
--- /dev/null
+++ b/tests/ui/resolve/unresolved-segments-visibility.rs
@@ -0,0 +1,11 @@
+// Check that we do not ICE due to unresolved segments in visibility path.
+#![crate_type = "lib"]
+
+extern crate alloc as b;
+
+mod foo {
+    mod bar {
+        pub(in b::string::String::newy) extern crate alloc as e;
+        //~^ ERROR failed to resolve: `String` is a struct, not a module [E0433]
+    }
+}
diff --git a/tests/ui/resolve/unresolved-segments-visibility.stderr b/tests/ui/resolve/unresolved-segments-visibility.stderr
new file mode 100644
index 00000000000..0a11549cdbf
--- /dev/null
+++ b/tests/ui/resolve/unresolved-segments-visibility.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: `String` is a struct, not a module
+  --> $DIR/unresolved-segments-visibility.rs:8:27
+   |
+LL |         pub(in b::string::String::newy) extern crate alloc as e;
+   |                           ^^^^^^ `String` is a struct, not a module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/span/visibility-ty-params.rs b/tests/ui/span/visibility-ty-params.rs
index d77febe0aa2..11c2cf44cb4 100644
--- a/tests/ui/span/visibility-ty-params.rs
+++ b/tests/ui/span/visibility-ty-params.rs
@@ -4,7 +4,7 @@ macro_rules! m {
 
 struct S<T>(T);
 m!{ S<u8> } //~ ERROR unexpected generic arguments in path
-            //~| ERROR expected module, found struct `S`
+            //~| ERROR failed to resolve: `S` is a struct, not a module [E0433]
 
 mod m {
     m!{ m<> } //~ ERROR unexpected generic arguments in path
diff --git a/tests/ui/span/visibility-ty-params.stderr b/tests/ui/span/visibility-ty-params.stderr
index 067893fd22d..97d05c4644e 100644
--- a/tests/ui/span/visibility-ty-params.stderr
+++ b/tests/ui/span/visibility-ty-params.stderr
@@ -4,11 +4,11 @@ error: unexpected generic arguments in path
 LL | m!{ S<u8> }
    |      ^^^^
 
-error[E0577]: expected module, found struct `S`
+error[E0433]: failed to resolve: `S` is a struct, not a module
   --> $DIR/visibility-ty-params.rs:6:5
    |
 LL | m!{ S<u8> }
-   |     ^^^^^ not a module
+   |     ^ `S` is a struct, not a module
 
 error: unexpected generic arguments in path
   --> $DIR/visibility-ty-params.rs:10:10
@@ -18,4 +18,4 @@ LL |     m!{ m<> }
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0577`.
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs
index fd91d81cdf0..20f504928c7 100644
--- a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs
+++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Ztrait-solver=next
-// known-bug: #95863
+// check-pass
 
 pub trait With {
     type F;
diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr b/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr
deleted file mode 100644
index d0a4cd661b3..00000000000
--- a/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/lazy-nested-obligations-2.rs:15:23
-   |
-LL |     let _: V<i32> = V(f);
-   |                     - ^ types differ
-   |                     |
-   |                     arguments to this struct are incorrect
-   |
-   = note: expected associated type `<i32 as With>::F`
-                      found fn item `for<'a> fn(&'a str) {f}`
-   = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-note: tuple struct defined here
-  --> $DIR/lazy-nested-obligations-2.rs:16:16
-   |
-LL |     pub struct V<T: With>(<T as With>::F);
-   |                ^
-
-error[E0308]: mismatched types
-  --> $DIR/lazy-nested-obligations-2.rs:21:30
-   |
-LL |     let _: E3<i32> = E3::Var(f);
-   |                      ------- ^ types differ
-   |                      |
-   |                      arguments to this enum variant are incorrect
-   |
-   = note: expected associated type `<i32 as With>::F`
-                      found fn item `for<'a> fn(&'a str) {f}`
-   = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-note: tuple variant defined here
-  --> $DIR/lazy-nested-obligations-2.rs:19:9
-   |
-LL |         Var(<T as With>::F),
-   |         ^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr
index 4554b8c7473..54965dee184 100644
--- a/tests/ui/traits/new-solver/more-object-bound.stderr
+++ b/tests/ui/traits/new-solver/more-object-bound.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `dyn Trait<A = A, B = B>: Trait` is not satisfied
-  --> $DIR/more-object-bound.rs:12:17
+  --> $DIR/more-object-bound.rs:12:5
    |
 LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait<A = A, B = B>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait<A = A, B = B>`
    |
 note: required by a bound in `foo`
   --> $DIR/more-object-bound.rs:18:8
diff --git a/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs
new file mode 100644
index 00000000000..d02dada72c9
--- /dev/null
+++ b/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs
@@ -0,0 +1,20 @@
+// compile-flags: -Ztrait-solver=next
+// ignore-test
+
+trait Trait {
+    type Gat<'lt>;
+}
+impl Trait for u8 {
+    type Gat<'lt> = u8;
+}
+
+fn test<T: Trait, F: FnOnce(<T as Trait>::Gat<'_>) -> S + ?Sized, S>() {}
+
+fn main() {
+    // Proving `dyn FnOnce: FnOnce` requires making sure that all of the supertraits
+    // of the trait and associated type bounds hold. We check this in
+    // `predicates_for_object_candidate`, and eagerly replace projections using equality
+    // which may generalize a type and emit a nested AliasRelate goal. Make sure that
+    // we don't ICE in that case, and bubble that goal up to the caller.
+    test::<u8, dyn FnOnce(<u8 as Trait>::Gat<'_>) + 'static, _>();
+}
diff --git a/tests/ui/type-alias-impl-trait/under-binder.rs b/tests/ui/type-alias-impl-trait/under-binder.rs
new file mode 100644
index 00000000000..caf21d64027
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/under-binder.rs
@@ -0,0 +1,9 @@
+#![feature(type_alias_impl_trait)]
+
+type Opaque<'a> = impl Sized + 'a;
+
+fn test(f: fn(u8)) -> fn(Opaque<'_>) {
+    f //~ ERROR E0792
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/under-binder.stderr b/tests/ui/type-alias-impl-trait/under-binder.stderr
new file mode 100644
index 00000000000..82c4ec97335
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/under-binder.stderr
@@ -0,0 +1,12 @@
+error[E0792]: expected generic lifetime parameter, found `'_`
+  --> $DIR/under-binder.rs:6:5
+   |
+LL | type Opaque<'a> = impl Sized + 'a;
+   |             -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     f
+   |     ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/type/option-ref-advice.rs b/tests/ui/type/option-ref-advice.rs
new file mode 100644
index 00000000000..2dcee5a2eb9
--- /dev/null
+++ b/tests/ui/type/option-ref-advice.rs
@@ -0,0 +1,11 @@
+// Regression test for https://github.com/rust-lang/rust/issues/100605
+
+fn takes_option(_arg: Option<&String>) {}
+
+fn main() {
+    takes_option(&None); //~ ERROR 6:18: 6:23: mismatched types [E0308]
+
+    let x = String::from("x");
+    let res = Some(x);
+    takes_option(&res); //~ ERROR 10:18: 10:22: mismatched types [E0308]
+}
diff --git a/tests/ui/issues/issue-100605.stderr b/tests/ui/type/option-ref-advice.stderr
index 6f11f44755a..d4dbef3013f 100644
--- a/tests/ui/issues/issue-100605.stderr
+++ b/tests/ui/type/option-ref-advice.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-100605.rs:4:18
+  --> $DIR/option-ref-advice.rs:6:18
    |
 LL |     takes_option(&None);
    |     ------------ ^^^^^ expected `Option<&String>`, found `&Option<_>`
@@ -9,7 +9,7 @@ LL |     takes_option(&None);
    = note:   expected enum `Option<&String>`
            found reference `&Option<_>`
 note: function defined here
-  --> $DIR/issue-100605.rs:1:4
+  --> $DIR/option-ref-advice.rs:3:4
    |
 LL | fn takes_option(_arg: Option<&String>) {}
    |    ^^^^^^^^^^^^ ---------------------
@@ -20,7 +20,7 @@ LL +     takes_option(None);
    |
 
 error[E0308]: mismatched types
-  --> $DIR/issue-100605.rs:8:18
+  --> $DIR/option-ref-advice.rs:10:18
    |
 LL |     takes_option(&res);
    |     ------------ ^^^^ expected `Option<&String>`, found `&Option<String>`
@@ -30,7 +30,7 @@ LL |     takes_option(&res);
    = note:   expected enum `Option<&String>`
            found reference `&Option<String>`
 note: function defined here
-  --> $DIR/issue-100605.rs:1:4
+  --> $DIR/option-ref-advice.rs:3:4
    |
 LL | fn takes_option(_arg: Option<&String>) {}
    |    ^^^^^^^^^^^^ ---------------------
diff --git a/tests/ui/use/use-self-type.stderr b/tests/ui/use/use-self-type.stderr
index 3da04a851f6..498df34fe32 100644
--- a/tests/ui/use/use-self-type.stderr
+++ b/tests/ui/use/use-self-type.stderr
@@ -1,8 +1,8 @@
-error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
+error[E0433]: failed to resolve: `Self` cannot be used in imports
   --> $DIR/use-self-type.rs:7:16
    |
 LL |         pub(in Self::f) struct Z;
-   |                ^^^^ `Self` is only available in impls, traits, and type definitions
+   |                ^^^^ `Self` cannot be used in imports
 
 error[E0432]: unresolved import `Self`
   --> $DIR/use-self-type.rs:6:13