about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-19 05:51:07 +0000
committerbors <bors@rust-lang.org>2023-09-19 05:51:07 +0000
commit81cd774bd02ee352104df4ae7bcf21890b6c674f (patch)
tree2f541730900ea6f537a6d286a22922fe9d6dd0ab
parent25e7808021ff1554f91541eaad7dd5d170a86f91 (diff)
parent1e2813fa0f4a93552f33826957ea397d2365c23c (diff)
downloadrust-81cd774bd02ee352104df4ae7bcf21890b6c674f.tar.gz
rust-81cd774bd02ee352104df4ae7bcf21890b6c674f.zip
Auto merge of #3064 - rust-lang:rustup-2023-09-19, r=RalfJung
Automatic sync from rustc
-rw-r--r--.github/workflows/ci.yml10
-rw-r--r--.github/workflows/dependencies.yml4
-rw-r--r--.gitignore1
-rw-r--r--.mailmap5
-rw-r--r--Cargo.lock76
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs16
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs8
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs19
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs34
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs98
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs35
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs37
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/returning.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs36
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs58
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl4
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs23
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs7
-rw-r--r--compiler/rustc_const_eval/messages.ftl3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs4
-rw-r--r--compiler/rustc_const_eval/src/errors.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs54
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs69
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs9
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0691.md4
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl40
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs96
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs93
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs72
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl58
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs65
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs273
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs224
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs46
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs8
-rw-r--r--compiler/rustc_infer/src/infer/free_regions.rs9
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs7
-rw-r--r--compiler/rustc_interface/src/util.rs20
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/lints.rs2
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs52
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs11
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp24
-rw-r--r--compiler/rustc_metadata/src/fs.rs4
-rw-r--r--compiler/rustc_middle/messages.ftl2
-rw-r--r--compiler/rustc_middle/src/error.rs7
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs10
-rw-r--r--compiler/rustc_middle/src/infer/mod.rs2
-rw-r--r--compiler/rustc_middle/src/macros.rs4
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs64
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs18
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs38
-rw-r--r--compiler/rustc_middle/src/mir/query.rs2
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs1
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs35
-rw-r--r--compiler/rustc_middle/src/traits/query.rs21
-rw-r--r--compiler/rustc_middle/src/traits/select.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs33
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs34
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs8
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs4
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs6
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs35
-rw-r--r--compiler/rustc_middle/src/ty/error.rs4
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs4
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs20
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs29
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs149
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs8
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs25
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs287
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs8
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs40
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_parse_format/src/lib.rs54
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs25
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs36
-rw-r--r--compiler/rustc_resolve/src/macros.rs5
-rw-r--r--compiler/rustc_session/src/config.rs12
-rw-r--r--compiler/rustc_session/src/output.rs19
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs86
-rw-r--r--compiler/rustc_target/src/abi/call/x86.rs6
-rw-r--r--compiler/rustc_target/src/abi/mod.rs13
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs3
-rw-r--r--compiler/rustc_target/src/spec/abi.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs3
-rw-r--r--compiler/rustc_trait_selection/messages.ftl2
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs33
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect.rs138
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs109
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs44
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs7
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs3
-rw-r--r--compiler/rustc_type_ir/src/lib.rs7
-rw-r--r--compiler/rustc_type_ir/src/sty.rs16
-rw-r--r--config.example.toml1
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs4
-rw-r--r--library/alloc/src/fmt.rs4
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/macros.rs14
-rw-r--r--library/alloc/src/rc.rs2
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/alloc/src/vec/mod.rs6
-rw-r--r--library/core/primitive_docs/box_into_raw.md1
-rw-r--r--library/core/primitive_docs/fs_file.md1
-rw-r--r--library/core/primitive_docs/io_bufread.md1
-rw-r--r--library/core/primitive_docs/io_read.md1
-rw-r--r--library/core/primitive_docs/io_seek.md1
-rw-r--r--library/core/primitive_docs/io_write.md1
-rw-r--r--library/core/primitive_docs/net_tosocketaddrs.md1
-rw-r--r--library/core/primitive_docs/process_exit.md1
-rw-r--r--library/core/primitive_docs/string_string.md1
-rw-r--r--library/core/src/ascii/ascii_char.rs41
-rw-r--r--library/core/src/cell.rs4
-rw-r--r--library/core/src/cmp.rs105
-rw-r--r--library/core/src/ffi/c_str.rs1
-rw-r--r--library/core/src/fmt/builders.rs8
-rw-r--r--library/core/src/fmt/mod.rs24
-rw-r--r--library/core/src/hash/mod.rs5
-rw-r--r--library/core/src/hint.rs41
-rw-r--r--library/core/src/iter/range.rs87
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/macros/mod.rs2
-rw-r--r--library/core/src/mem/mod.rs2
-rw-r--r--library/core/src/num/mod.rs3
-rw-r--r--library/core/src/num/saturating.rs437
-rw-r--r--library/core/src/ops/deref.rs10
-rw-r--r--library/core/src/primitive_docs.rs29
-rw-r--r--library/core/src/ptr/mod.rs3
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/core/src/slice/mod.rs2
-rw-r--r--library/core/src/str/mod.rs2
-rw-r--r--library/core/src/sync/atomic.rs3
-rw-r--r--library/core/src/tuple.rs2
-rw-r--r--library/std/primitive_docs/box_into_raw.md1
-rw-r--r--library/std/primitive_docs/fs_file.md1
-rw-r--r--library/std/primitive_docs/io_bufread.md1
-rw-r--r--library/std/primitive_docs/io_read.md1
-rw-r--r--library/std/primitive_docs/io_seek.md1
-rw-r--r--library/std/primitive_docs/io_write.md1
-rw-r--r--library/std/primitive_docs/net_tosocketaddrs.md1
-rw-r--r--library/std/primitive_docs/process_exit.md1
-rw-r--r--library/std/primitive_docs/string_string.md1
-rw-r--r--library/std/src/lib.rs29
-rw-r--r--library/std/src/num.rs2
-rw-r--r--library/std/src/os/unix/fs.rs2
-rw-r--r--library/std/src/primitive_docs.rs1593
-rw-r--r--library/std/src/sync/mpsc/mod.rs15
-rw-r--r--library/std/src/thread/mod.rs82
-rw-r--r--src/bootstrap/README.md5
-rw-r--r--src/bootstrap/bin/_helper.rs24
-rw-r--r--src/bootstrap/bin/rustc.rs17
-rw-r--r--src/bootstrap/bin/rustdoc.rs19
-rw-r--r--src/bootstrap/bootstrap.py8
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/compile.rs9
-rw-r--r--src/bootstrap/config.rs29
-rw-r--r--src/bootstrap/config/tests.rs14
-rw-r--r--src/bootstrap/download.rs2
-rw-r--r--src/bootstrap/lib.rs11
-rw-r--r--src/bootstrap/llvm.rs34
-rw-r--r--src/bootstrap/sanity.rs21
-rw-r--r--src/bootstrap/setup.rs1
-rw-r--r--src/bootstrap/test.rs22
-rw-r--r--src/ci/docker/host-x86_64/arm-android/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/dist-android/Dockerfile2
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh2
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/ci/github-actions/ci.yml6
-rw-r--r--src/doc/rustdoc/src/unstable-features.md44
-rw-r--r--src/etc/rust_analyzer_settings.json4
-rw-r--r--src/librustdoc/config.rs24
-rw-r--r--src/librustdoc/doctest.rs1
-rw-r--r--src/librustdoc/externalfiles.rs4
-rw-r--r--src/librustdoc/html/highlight.rs25
-rw-r--r--src/librustdoc/html/markdown.rs482
-rw-r--r--src/librustdoc/html/markdown/tests.rs189
-rw-r--r--src/librustdoc/html/render/context.rs15
-rw-r--r--src/librustdoc/html/render/mod.rs9
-rw-r--r--src/librustdoc/html/static/css/noscript.css213
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css410
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css181
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css102
-rw-r--r--src/librustdoc/html/static/css/themes/light.css99
-rw-r--r--src/librustdoc/html/static/js/main.js11
-rw-r--r--src/librustdoc/html/static/js/storage.js36
-rw-r--r--src/librustdoc/html/static_files.rs3
-rw-r--r--src/librustdoc/html/templates/page.html12
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/markdown.rs14
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs9
-rw-r--r--src/librustdoc/passes/check_custom_code_classes.rs88
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs9
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs4
-rw-r--r--src/librustdoc/passes/mod.rs5
-rw-r--r--src/librustdoc/theme.rs3
-rw-r--r--src/librustdoc/theme/tests.rs2
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs6
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr2
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr2
-rw-r--r--src/tools/compiletest/src/runtest.rs16
-rw-r--r--src/tools/compiletest/src/util.rs5
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/helpers.rs3
-rw-r--r--src/tools/miri/tests/fail/const-ub-checks.stderr2
-rw-r--r--src/tools/miri/tests/fail/erroneous_const.stderr2
-rw-r--r--src/tools/miri/tests/fail/erroneous_const2.stderr4
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/opt-dist/src/environment.rs108
-rw-r--r--src/tools/opt-dist/src/environment/linux.rs58
-rw-r--r--src/tools/opt-dist/src/environment/mod.rs77
-rw-r--r--src/tools/opt-dist/src/environment/windows.rs92
-rw-r--r--src/tools/opt-dist/src/exec.rs4
-rw-r--r--src/tools/opt-dist/src/main.rs227
-rw-r--r--src/tools/opt-dist/src/tests.rs16
-rw-r--r--src/tools/opt-dist/src/training.rs22
-rw-r--r--src/tools/opt-dist/src/utils/io.rs8
-rw-r--r--src/tools/opt-dist/src/utils/mod.rs4
-rw-r--r--src/tools/rust-analyzer/.cargo/config.toml2
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml8
-rw-r--r--src/tools/rust-analyzer/.github/workflows/metrics.yaml23
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml2
-rw-r--r--src/tools/rust-analyzer/Cargo.lock114
-rw-r--r--src/tools/rust-analyzer/Cargo.toml12
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/fixture.rs10
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/lib.rs26
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs177
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs469
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs89
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs103
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs502
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs60
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs45
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs170
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs132
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs141
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs92
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs85
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs144
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs183
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs58
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs104
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs131
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs446
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs159
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs91
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs43
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs205
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs43
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs64
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs57
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/documentation.rs281
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs169
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs108
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs101
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html58
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs248
-rw-r--r--src/tools/rust-analyzer/crates/intern/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs88
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs19
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast105
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-test/build.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs91
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs11
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs97
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt44
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs24
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs40
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs61
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs155
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs30
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs29
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs (renamed from src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs)4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs (renamed from src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs)4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs (renamed from src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs)0
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs (renamed from src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs)146
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs (renamed from src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs)4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs173
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs165
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs8
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram22
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs169
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs19
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs19
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs20
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs103
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/docs/dev/architecture.md2
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md6
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json11
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts20
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts4
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts35
-rw-r--r--src/tools/rust-analyzer/editors/code/src/util.ts16
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml5
-rw-r--r--src/tools/rust-analyzer/xtask/src/flags.rs20
-rw-r--r--src/tools/rust-analyzer/xtask/src/metrics.rs61
-rw-r--r--src/tools/rustdoc-themes/main.rs44
-rw-r--r--src/tools/tidy/src/lib.rs2
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/primitive_docs.rs17
-rw-r--r--src/tools/tidy/src/rustdoc_css_themes.rs99
-rw-r--r--tests/coverage-map/status-quo/closure.cov-map14
-rw-r--r--tests/coverage-map/status-quo/closure_bug.cov-map148
-rw-r--r--tests/coverage-map/status-quo/closure_bug.rs44
-rw-r--r--tests/coverage-map/status-quo/generator.cov-map4
-rw-r--r--tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir6
-rw-r--r--tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir6
-rw-r--r--tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir6
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.32bit.mir4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.64bit.mir4
-rw-r--r--tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir2
-rw-r--r--tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir2
-rw-r--r--tests/run-coverage/closure.coverage14
-rw-r--r--tests/run-coverage/closure_bug.coverage53
-rw-r--r--tests/run-coverage/closure_bug.rs44
-rw-r--r--tests/run-make/issue-88756-default-output/output-default.stdout2
-rw-r--r--tests/run-make/metadata-dep-info/Makefile13
-rw-r--r--tests/run-make/metadata-dep-info/dash-separated.rs4
-rw-r--r--tests/run-make/metadata-dep-info/dash-separated_something-extra.normalized.d5
-rw-r--r--tests/run-make/rustdoc-themes/Makefile3
-rw-r--r--tests/rustdoc-gui/search-result-color.goml2
-rw-r--r--tests/rustdoc-ui/custom_code_classes_in_docs-warning.rs85
-rw-r--r--tests/rustdoc-ui/custom_code_classes_in_docs-warning.stderr113
-rw-r--r--tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs17
-rw-r--r--tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr33
-rw-r--r--tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.rs10
-rw-r--r--tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.stderr14
-rw-r--r--tests/rustdoc-ui/issues/issue-91713.stdout2
-rw-r--r--tests/rustdoc/custom_code_classes.rs28
-rw-r--r--tests/ui/abi/debug.rs1
-rw-r--r--tests/ui/abi/debug.stderr34
-rw-r--r--tests/ui/associated-consts/defaults-cyclic-fail.rs2
-rw-r--r--tests/ui/associated-consts/defaults-cyclic-fail.stderr14
-rw-r--r--tests/ui/associated-consts/defaults-not-assumed-fail.stderr6
-rw-r--r--tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr12
-rw-r--r--tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr12
-rw-r--r--tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr12
-rw-r--r--tests/ui/borrowck/issue-81899.stderr2
-rw-r--r--tests/ui/borrowck/issue-88434-minimal-example.stderr2
-rw-r--r--tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr2
-rw-r--r--tests/ui/c-variadic/variadic-ffi-2.rs5
-rw-r--r--tests/ui/c-variadic/variadic-ffi-2.stderr2
-rw-r--r--tests/ui/cast/cast-as-bool.rs4
-rw-r--r--tests/ui/cast/cast-as-bool.stderr28
-rw-r--r--tests/ui/cast/cast-rfc0401-2.stderr7
-rw-r--r--tests/ui/closures/2229_closure_analysis/repr_packed.rs10
-rw-r--r--tests/ui/closures/2229_closure_analysis/repr_packed.stderr19
-rw-r--r--tests/ui/consts/const-err-late.stderr6
-rw-r--r--tests/ui/consts/const-err-multi.stderr6
-rw-r--r--tests/ui/consts/const-eval/erroneous-const.stderr2
-rw-r--r--tests/ui/consts/const-eval/erroneous-const2.stderr2
-rw-r--r--tests/ui/consts/const-eval/issue-44578.stderr6
-rw-r--r--tests/ui/consts/const-eval/issue-50814-2.stderr2
-rw-r--r--tests/ui/consts/const-eval/issue-50814.stderr2
-rw-r--r--tests/ui/consts/const-eval/panic-assoc-never-type.rs2
-rw-r--r--tests/ui/consts/const-eval/panic-assoc-never-type.stderr4
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.32bit.stderr6
-rw-r--r--tests/ui/consts/const-eval/raw-bytes.64bit.stderr6
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr4
-rw-r--r--tests/ui/consts/const-eval/ub-wide-ptr.stderr6
-rw-r--r--tests/ui/consts/const-eval/union-const-eval-field.stderr4
-rw-r--r--tests/ui/consts/const-float-bits-reject-conv.stderr16
-rw-r--r--tests/ui/consts/const-len-underflow-separate-spans.next.stderr2
-rw-r--r--tests/ui/consts/const-len-underflow-separate-spans.old.stderr2
-rw-r--r--tests/ui/consts/invalid-union.32bit.stderr4
-rw-r--r--tests/ui/consts/invalid-union.64bit.stderr4
-rw-r--r--tests/ui/consts/issue-36163.stderr14
-rw-r--r--tests/ui/consts/miri_unleashed/assoc_const.stderr4
-rw-r--r--tests/ui/consts/miri_unleashed/assoc_const_2.stderr4
-rw-r--r--tests/ui/consts/uninhabited-const-issue-61744.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs4
-rw-r--r--tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr6
-rw-r--r--tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs37
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr110
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs7
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr12
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs11
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr24
-rw-r--r--tests/ui/error-codes/E0040.stderr10
-rw-r--r--tests/ui/error-codes/E0054.stderr7
-rw-r--r--tests/ui/error-festival.stderr7
-rw-r--r--tests/ui/explicit/explicit-call-to-dtor.stderr10
-rw-r--r--tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr10
-rw-r--r--tests/ui/fmt/raw-idents.rs17
-rw-r--r--tests/ui/fmt/raw-idents.stderr44
-rw-r--r--tests/ui/issues/issue-17252.stderr11
-rw-r--r--tests/ui/issues/issue-23302-1.stderr9
-rw-r--r--tests/ui/issues/issue-23302-2.stderr9
-rw-r--r--tests/ui/issues/issue-23302-3.stderr14
-rw-r--r--tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr2
-rw-r--r--tests/ui/limits/issue-55878.stderr4
-rw-r--r--tests/ui/lint/ptr_null_checks.rs14
-rw-r--r--tests/ui/lint/ptr_null_checks.stderr38
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.stderr7
-rw-r--r--tests/ui/range/range-1.stderr2
-rw-r--r--tests/ui/repr/repr-transparent-non-exhaustive.rs40
-rw-r--r--tests/ui/repr/repr-transparent-non-exhaustive.stderr42
-rw-r--r--tests/ui/repr/repr-transparent.rs23
-rw-r--r--tests/ui/repr/repr-transparent.stderr82
-rw-r--r--tests/ui/span/send-is-not-static-std-sync.rs2
-rw-r--r--tests/ui/span/send-is-not-static-std-sync.stderr8
-rw-r--r--tests/ui/thir-print/thir-flat-const-variant.stdout96
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout20
-rw-r--r--triagebot.toml3
562 files changed, 11886 insertions, 7523 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3680136d89f..618a26958ee 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,7 +67,7 @@ jobs:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 2
       - name: configure the PR in which the error message will be posted
@@ -393,7 +393,7 @@ jobs:
           - name: dist-x86_64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
-              SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths
+              SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-2019-8core-32gb
           - name: dist-i686-msvc
@@ -435,7 +435,7 @@ jobs:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 2
       - name: configure the PR in which the error message will be posted
@@ -555,7 +555,7 @@ jobs:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 2
       - name: configure the PR in which the error message will be posted
@@ -662,7 +662,7 @@ jobs:
     if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 2
       - name: publish toolstate
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 26d2ba636f3..97ed891c491 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -50,7 +50,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           submodules: recursive
       - name: install the bootstrap toolchain
@@ -87,7 +87,7 @@ jobs:
       pull-requests: write
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: download Cargo.lock from update job
         uses: actions/download-artifact@v3
diff --git a/.gitignore b/.gitignore
index 4c8d1a03764..485968d9c56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,7 +58,6 @@ build/
 \#*
 \#*\#
 .#*
-rustc-ice-*.txt
 
 ## Tags
 tags
diff --git a/.mailmap b/.mailmap
index eb82cf4de8d..21e1adb43cf 100644
--- a/.mailmap
+++ b/.mailmap
@@ -328,7 +328,8 @@ Kyle J Strand <batmanaod@gmail.com> <BatmanAoD@users.noreply.github.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.j.strand@gmail.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
-Laurențiu Nicola <lnicola@dend.ro>
+Laurențiu Nicola <lnicola@dend.ro> Laurentiu Nicola <lnicola@dend.ro>
+Laurențiu Nicola <lnicola@dend.ro> <lnicola@users.noreply.github.com>
 lcnr <rust@lcnr.de> <bastian_kauschke@hotmail.de>
 Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
 Lee Wondong <wdlee91@gmail.com>
@@ -549,6 +550,8 @@ Timothy Maloney <tmaloney@pdx.edu>
 Tomas Koutsky <tomas@stepnivlk.net>
 Torsten Weber <TorstenWeber12@gmail.com>
 Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
+Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com>
+Trevor Gross <tmgross@umich.edu> <tgross@intrepidcs.com>
 Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt>
 Tshepang Mbambo <tshepang@gmail.com>
 Ty Overby <ty@pre-alpha.com>
diff --git a/Cargo.lock b/Cargo.lock
index d0dde610500..a93078829e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -861,12 +861,36 @@ dependencies = [
 
 [[package]]
 name = "darling"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
+dependencies = [
+ "darling_core 0.14.4",
+ "darling_macro 0.14.4",
+]
+
+[[package]]
+name = "darling"
 version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
 dependencies = [
- "darling_core",
- "darling_macro",
+ "darling_core 0.20.3",
+ "darling_macro 0.20.3",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.109",
 ]
 
 [[package]]
@@ -885,11 +909,22 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
+dependencies = [
+ "darling_core 0.14.4",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
 version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
 dependencies = [
- "darling_core",
+ "darling_core 0.20.3",
  "quote",
  "syn 2.0.29",
 ]
@@ -921,6 +956,37 @@ dependencies = [
 ]
 
 [[package]]
+name = "derive_builder"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
+dependencies = [
+ "derive_builder_macro",
+]
+
+[[package]]
+name = "derive_builder_core"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
+dependencies = [
+ "darling 0.14.4",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "derive_builder_macro"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
+dependencies = [
+ "derive_builder_core",
+ "syn 1.0.109",
+]
+
+[[package]]
 name = "derive_more"
 version = "0.99.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -939,7 +1005,7 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
 dependencies = [
- "darling",
+ "darling 0.20.3",
  "proc-macro2",
  "quote",
  "syn 2.0.29",
@@ -2594,6 +2660,8 @@ dependencies = [
  "anyhow",
  "build_helper",
  "camino",
+ "clap",
+ "derive_builder",
  "env_logger 0.10.0",
  "fs_extra",
  "glob",
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 19a2b3017bc..db008ea139d 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -99,6 +99,22 @@ impl Attribute {
         }
     }
 
+    pub fn path_matches(&self, name: &[Symbol]) -> bool {
+        match &self.kind {
+            AttrKind::Normal(normal) => {
+                normal.item.path.segments.len() == name.len()
+                    && normal
+                        .item
+                        .path
+                        .segments
+                        .iter()
+                        .zip(name)
+                        .all(|(s, n)| s.args.is_none() && s.ident.name == *n)
+            }
+            AttrKind::DocComment(..) => false,
+        }
+    }
+
     pub fn is_word(&self) -> bool {
         if let AttrKind::Normal(normal) = &self.kind {
             matches!(normal.item.args, AttrArgs::Empty)
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 337af89b21f..b40e89e471d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         span: Span,
         counter: usize,
     ) -> RegionNameHighlight {
-        let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
-        highlight.highlighting_region_vid(needle_fr, counter);
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter);
         let type_name =
             self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
 
@@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             return None;
         }
 
-        let mut highlight = RegionHighlightMode::new(tcx);
-        highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap());
         let type_name =
             self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
 
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 8d8db4c13fa..207ae8ad844 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -137,6 +137,8 @@ builtin_macros_format_positional_after_named = positional arguments cannot follo
     .label = positional arguments must be before named arguments
     .named_args = named argument
 
+builtin_macros_format_remove_raw_ident = remove the `r#`
+
 builtin_macros_format_requires_string = requires at least a format string argument
 
 builtin_macros_format_string_invalid = invalid format string: {$desc}
@@ -165,6 +167,8 @@ builtin_macros_format_unused_arg = {$named ->
 builtin_macros_format_unused_args = multiple unused formatting arguments
     .label = multiple missing formatting specifiers
 
+builtin_macros_format_use_positional = consider using a positional formatting argument instead
+
 builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
 
 builtin_macros_invalid_crate_attribute = invalid crate attribute
@@ -205,8 +209,6 @@ builtin_macros_requires_cfg_pattern =
 
 builtin_macros_should_panic = functions using `#[should_panic]` must return `()`
 
-builtin_macros_sugg = consider using a positional formatting argument instead
-
 builtin_macros_test_arg_non_lifetime = functions used as tests can not have any non-lifetime generic parameters
 
 builtin_macros_test_args = functions used as tests can not have any arguments
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 745358fde4b..a000e4895d1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -18,6 +18,20 @@ pub fn expand_deriving_eq(
     is_const: bool,
 ) {
     let span = cx.with_def_site_ctxt(span);
+
+    let structural_trait_def = TraitDef {
+        span,
+        path: path_std!(marker::StructuralEq),
+        skip_path_as_bound: true, // crucial!
+        needs_copy_as_bound_if_packed: false,
+        additional_bounds: Vec::new(),
+        supports_unions: true,
+        methods: Vec::new(),
+        associated_types: Vec::new(),
+        is_const: false,
+    };
+    structural_trait_def.expand(cx, mitem, item, push);
+
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::Eq),
@@ -44,9 +58,6 @@ pub fn expand_deriving_eq(
         associated_types: Vec::new(),
         is_const,
     };
-
-    super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
-
     trait_def.expand_ext(cx, mitem, item, push, true)
 }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index a71ecc5db7d..a170468b413 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq(
         BlockOrExpr::new_expr(expr)
     }
 
-    super::inject_impl_of_structural_trait(
-        cx,
+    let structural_trait_def = TraitDef {
         span,
-        item,
-        path_std!(marker::StructuralPartialEq),
-        push,
-    );
+        path: path_std!(marker::StructuralPartialEq),
+        skip_path_as_bound: true, // crucial!
+        needs_copy_as_bound_if_packed: false,
+        additional_bounds: Vec::new(),
+        // We really don't support unions, but that's already checked by the impl generated below;
+        // a second check here would lead to redundant error messages.
+        supports_unions: true,
+        methods: Vec::new(),
+        associated_types: Vec::new(),
+        is_const: false,
+    };
+    structural_trait_def.expand(cx, mitem, item, push);
 
     // No need to generate `ne`, the default suffices, and not generating it is
     // faster.
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6597ee3cf1b..7252658d460 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -88,7 +88,7 @@
 //!
 //! When generating the `expr` for the `A` impl, the `SubstructureFields` is
 //!
-//! ```{.text}
+//! ```text
 //! Struct(vec![FieldInfo {
 //!            span: <span of x>
 //!            name: Some(<ident of x>),
@@ -99,7 +99,7 @@
 //!
 //! For the `B` impl, called with `B(a)` and `B(b)`,
 //!
-//! ```{.text}
+//! ```text
 //! Struct(vec![FieldInfo {
 //!           span: <span of `i32`>,
 //!           name: None,
@@ -113,7 +113,7 @@
 //! When generating the `expr` for a call with `self == C0(a)` and `other
 //! == C0(b)`, the SubstructureFields is
 //!
-//! ```{.text}
+//! ```text
 //! EnumMatching(0, <ast::Variant for C0>,
 //!              vec![FieldInfo {
 //!                 span: <span of i32>
@@ -125,7 +125,7 @@
 //!
 //! For `C1 {x}` and `C1 {x}`,
 //!
-//! ```{.text}
+//! ```text
 //! EnumMatching(1, <ast::Variant for C1>,
 //!              vec![FieldInfo {
 //!                 span: <span of x>
@@ -137,7 +137,7 @@
 //!
 //! For the tags,
 //!
-//! ```{.text}
+//! ```text
 //! EnumTag(
 //!     &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
 //! ```
@@ -149,7 +149,7 @@
 //!
 //! A static method on the types above would result in,
 //!
-//! ```{.text}
+//! ```text
 //! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
 //!
 //! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
@@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> {
                             .collect();
 
                         // Require the current trait.
-                        bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
+                        if !self.skip_path_as_bound {
+                            bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
+                        }
 
                         // Add a `Copy` bound if required.
                         if is_packed && self.needs_copy_as_bound_if_packed {
@@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> {
                             ));
                         }
 
-                        let predicate = ast::WhereBoundPredicate {
-                            span: self.span,
-                            bound_generic_params: field_ty_param.bound_generic_params,
-                            bounded_ty: field_ty_param.ty,
-                            bounds,
-                        };
+                        if !bounds.is_empty() {
+                            let predicate = ast::WhereBoundPredicate {
+                                span: self.span,
+                                bound_generic_params: field_ty_param.bound_generic_params,
+                                bounded_ty: field_ty_param.ty,
+                                bounds,
+                            };
 
-                        let predicate = ast::WherePredicate::BoundPredicate(predicate);
-                        where_clause.predicates.push(predicate);
+                            let predicate = ast::WherePredicate::BoundPredicate(predicate);
+                            where_clause.predicates.push(predicate);
+                        }
                     }
                 }
             }
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index d34336e7679..a6f3252e7be 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -2,9 +2,9 @@
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem};
+use rustc_ast::{GenericArg, MetaItem};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
@@ -116,100 +116,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
     }))
 }
 
-// Injects `impl<...> Structural for ItemType<...> { }`. In particular,
-// does *not* add `where T: Structural` for parameters `T` in `...`.
-// (That's the main reason we cannot use TraitDef here.)
-fn inject_impl_of_structural_trait(
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    item: &Annotatable,
-    structural_path: generic::ty::Path,
-    push: &mut dyn FnMut(Annotatable),
-) {
-    let Annotatable::Item(item) = item else {
-        unreachable!();
-    };
-
-    let generics = match &item.kind {
-        ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
-        // Do not inject `impl Structural for Union`. (`PartialEq` does not
-        // support unions, so we will see error downstream.)
-        ItemKind::Union(..) => return,
-        _ => unreachable!(),
-    };
-
-    // Create generics param list for where clauses and impl headers
-    let mut generics = generics.clone();
-
-    let ctxt = span.ctxt();
-
-    // Create the type of `self`.
-    //
-    // in addition, remove defaults from generic params (impls cannot have them).
-    let self_params: Vec<_> = generics
-        .params
-        .iter_mut()
-        .map(|param| match &mut param.kind {
-            ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
-                cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
-            ),
-            ast::GenericParamKind::Type { default } => {
-                *default = None;
-                ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
-            }
-            ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
-                *default = None;
-                ast::GenericArg::Const(
-                    cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
-                )
-            }
-        })
-        .collect();
-
-    let type_ident = item.ident;
-
-    let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
-    let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
-
-    // It would be nice to also encode constraint `where Self: Eq` (by adding it
-    // onto `generics` cloned above). Unfortunately, that strategy runs afoul of
-    // rust-lang/rust#48214. So we perform that additional check in the compiler
-    // itself, instead of encoding it here.
-
-    // Keep the lint and stability attributes of the original item, to control
-    // how the generated implementation is linted.
-    let mut attrs = ast::AttrVec::new();
-    attrs.extend(
-        item.attrs
-            .iter()
-            .filter(|a| {
-                [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
-                    .contains(&a.name_or_empty())
-            })
-            .cloned(),
-    );
-    // Mark as `automatically_derived` to avoid some silly lints.
-    attrs.push(cx.attr_word(sym::automatically_derived, span));
-
-    let newitem = cx.item(
-        span,
-        Ident::empty(),
-        attrs,
-        ItemKind::Impl(Box::new(Impl {
-            unsafety: ast::Unsafe::No,
-            polarity: ast::ImplPolarity::Positive,
-            defaultness: ast::Defaultness::Final,
-            constness: ast::Const::No,
-            generics,
-            of_trait: Some(trait_ref),
-            self_ty: self_type,
-            items: ThinVec::new(),
-        })),
-    );
-
-    push(Annotatable::Item(newitem));
-}
-
 fn assert_ty_bounds(
     cx: &mut ExtCtxt<'_>,
     stmts: &mut ThinVec<ast::Stmt>,
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index fbf0395bb05..1238773d58b 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -539,18 +539,29 @@ pub(crate) struct InvalidFormatStringLabel {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(
-    builtin_macros_sugg,
-    style = "verbose",
-    applicability = "machine-applicable"
-)]
-pub(crate) struct InvalidFormatStringSuggestion {
-    #[suggestion_part(code = "{len}")]
-    pub(crate) captured: Span,
-    pub(crate) len: String,
-    #[suggestion_part(code = ", {arg}")]
-    pub(crate) span: Span,
-    pub(crate) arg: String,
+pub(crate) enum InvalidFormatStringSuggestion {
+    #[multipart_suggestion(
+        builtin_macros_format_use_positional,
+        style = "verbose",
+        applicability = "machine-applicable"
+    )]
+    UsePositional {
+        #[suggestion_part(code = "{len}")]
+        captured: Span,
+        len: String,
+        #[suggestion_part(code = ", {arg}")]
+        span: Span,
+        arg: String,
+    },
+    #[suggestion(
+        builtin_macros_format_remove_raw_ident,
+        code = "",
+        applicability = "machine-applicable"
+    )]
+    RemoveRawIdent {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index ede95dbf897..8397b5e4221 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -260,20 +260,29 @@ fn make_format_args(
         if let Some((label, span)) = err.secondary_label && is_source_literal {
             e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
         }
-        if err.should_be_replaced_with_positional_argument {
-            let captured_arg_span =
-                fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
-            if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
-                let span = match args.unnamed_args().last() {
-                    Some(arg) => arg.expr.span,
-                    None => fmt_span,
-                };
-                e.sugg_ = Some(errors::InvalidFormatStringSuggestion {
-                    captured: captured_arg_span,
-                    len: args.unnamed_args().len().to_string(),
-                    span: span.shrink_to_hi(),
-                    arg,
-                });
+        match err.suggestion {
+            parse::Suggestion::None => {}
+            parse::Suggestion::UsePositional => {
+                let captured_arg_span =
+                    fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
+                if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
+                    let span = match args.unnamed_args().last() {
+                        Some(arg) => arg.expr.span,
+                        None => fmt_span,
+                    };
+                    e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional {
+                        captured: captured_arg_span,
+                        len: args.unnamed_args().len().to_string(),
+                        span: span.shrink_to_hi(),
+                        arg,
+                    });
+                }
+            }
+            parse::Suggestion::RemoveRawIdent(span) => {
+                if is_source_literal {
+                    let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
+                    e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
+                }
             }
         }
         ecx.emit_err(e);
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index d847e524f8c..0d16da48067 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -100,11 +100,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
             },
-            PassMode::Cast(ref cast, pad_i32) => {
+            PassMode::Cast { ref cast, pad_i32 } => {
                 assert!(!pad_i32, "padding support not yet implemented");
                 cast_target_to_abi_params(cast)
             }
-            PassMode::Indirect { attrs, extra_attrs: None, on_stack } => {
+            PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
                 if on_stack {
                     // Abi requires aligning struct size to pointer size
                     let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
@@ -117,11 +117,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                     smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
                 }
             }
-            PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => {
+            PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
                 assert!(!on_stack);
                 smallvec![
                     apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
-                    apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs),
+                    apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
                 ]
             }
         }
@@ -148,14 +148,14 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
             },
-            PassMode::Cast(ref cast, _) => {
+            PassMode::Cast { ref cast, .. } => {
                 (None, cast_target_to_abi_params(cast).into_iter().collect())
             }
-            PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => {
+            PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
                 assert!(!on_stack);
                 (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
             }
-            PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+            PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
                 unreachable!("unsized return value")
             }
         }
@@ -229,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
             let (a, b) = arg.load_scalar_pair(fx);
             smallvec![a, b]
         }
-        PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast),
+        PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast),
         PassMode::Indirect { .. } => {
             if is_owned {
                 match arg.force_stack(fx) {
@@ -287,14 +287,14 @@ pub(super) fn cvalue_for_param<'tcx>(
             assert_eq!(block_params.len(), 2, "{:?}", block_params);
             Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
         }
-        PassMode::Cast(ref cast, _) => {
+        PassMode::Cast { ref cast, .. } => {
             Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
         }
-        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
             assert_eq!(block_params.len(), 1, "{:?}", block_params);
             Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
         }
-        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
             assert_eq!(block_params.len(), 2, "{:?}", block_params);
             Some(CValue::by_ref_unsized(
                 Pointer::new(block_params[0]),
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index 14e54d5ee38..646fb4a3cdc 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>(
     block_params_iter: &mut impl Iterator<Item = Value>,
 ) -> CPlace<'tcx> {
     let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
-        PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => {
+        PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => {
             let is_ssa =
                 ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty);
             (
@@ -26,7 +26,7 @@ pub(super) fn codegen_return_param<'tcx>(
                 smallvec![],
             )
         }
-        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
             let ret_param = block_params_iter.next().unwrap();
             assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
             (
@@ -34,7 +34,7 @@ pub(super) fn codegen_return_param<'tcx>(
                 smallvec![ret_param],
             )
         }
-        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
     };
@@ -62,7 +62,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
 ) {
     let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
         PassMode::Ignore => (None, None),
-        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
             if let Some(ret_ptr) = ret_place.try_to_ptr() {
                 // This is an optimization to prevent unnecessary copies of the return value when
                 // the return place is already a memory place as opposed to a register.
@@ -73,10 +73,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
                 (Some(place), Some(place.to_ptr().get_addr(fx)))
             }
         }
-        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
-        PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None),
+        PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None),
     };
 
     let call_inst = f(fx, return_ptr);
@@ -93,21 +93,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
             ret_place
                 .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
         }
-        PassMode::Cast(ref cast, _) => {
+        PassMode::Cast { ref cast, .. } => {
             let results =
                 fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
             let result =
                 super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
             ret_place.write_cvalue(fx, result);
         }
-        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
             if let Some(ret_temp_place) = ret_temp_place {
                 // If ret_temp_place is None, it is not necessary to copy the return value.
                 let ret_temp_value = ret_temp_place.to_cvalue(fx);
                 ret_place.write_cvalue(fx, ret_temp_value);
             }
         }
-        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
     }
@@ -116,10 +116,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
 /// Codegen a return instruction with the right return value(s) if any.
 pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
     match fx.fn_abi.as_ref().unwrap().ret.mode {
-        PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+        PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
             fx.bcx.ins().return_(&[]);
         }
-        PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+        PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
         PassMode::Direct(_) => {
@@ -132,7 +132,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
         }
-        PassMode::Cast(ref cast, _) => {
+        PassMode::Cast { ref cast, .. } => {
             let place = fx.get_local_place(RETURN_PLACE);
             let ret_val = place.to_cvalue(fx);
             let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 54f82dcc8ae..9b5a6b89191 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -250,7 +250,10 @@ pub(crate) fn verify_func(
 }
 
 fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
-    if !crate::constant::check_constants(fx) {
+    if let Err(err) =
+        fx.mir.post_mono_checks(fx.tcx, ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
+    {
+        err.emit_err(fx.tcx);
         fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
         fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
         // compilation should have been aborted
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 8c67760a0b9..0d9bd3cf240 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -2,9 +2,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::interpret::{
-    read_target_uint, AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
-};
+use rustc_middle::mir::interpret::{read_target_uint, AllocId, ConstValue, GlobalAlloc, Scalar};
 
 use cranelift_module::*;
 
@@ -33,16 +31,6 @@ impl ConstantCx {
     }
 }
 
-pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
-    let mut all_constants_ok = true;
-    for constant in &fx.mir.required_consts {
-        if eval_mir_constant(fx, constant).is_none() {
-            all_constants_ok = false;
-        }
-    }
-    all_constants_ok
-}
-
 pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
     let mut constants_cx = ConstantCx::new();
     constants_cx.todo.push(TodoItem::Static(def_id));
@@ -76,30 +64,20 @@ pub(crate) fn codegen_tls_ref<'tcx>(
 pub(crate) fn eval_mir_constant<'tcx>(
     fx: &FunctionCx<'_, '_, 'tcx>,
     constant: &Constant<'tcx>,
-) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
+) -> (ConstValue<'tcx>, Ty<'tcx>) {
     let cv = fx.monomorphize(constant.literal);
+    // This cannot fail because we checked all required_consts in advance.
     let val = cv
         .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
-        .map_err(|err| match err {
-            ErrorHandled::Reported(_) => {
-                fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
-            }
-            ErrorHandled::TooGeneric => {
-                span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
-            }
-        })
-        .ok();
-    val.map(|val| (val, cv.ty()))
+        .expect("erroneous constant not captured by required_consts");
+    (val, cv.ty())
 }
 
 pub(crate) fn codegen_constant_operand<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     constant: &Constant<'tcx>,
 ) -> CValue<'tcx> {
-    let (const_val, ty) = eval_mir_constant(fx, constant).unwrap_or_else(|| {
-        span_bug!(constant.span, "erroneous constant not captured by required_consts")
-    });
-
+    let (const_val, ty) = eval_mir_constant(fx, constant);
     codegen_const_value(fx, const_val, ty)
 }
 
@@ -459,7 +437,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
     operand: &Operand<'tcx>,
 ) -> Option<ConstValue<'tcx>> {
     match operand {
-        Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).unwrap().0),
+        Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0),
         // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
         // inside a temporary before being passed to the intrinsic requiring the const argument.
         // This code tries to find a single constant defining definition of the referenced local.
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 518e3da07a4..eba90949b5e 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -242,8 +242,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
                 }
             }
             InlineAsmOperand::Const { ref value } => {
-                let (const_value, ty) = crate::constant::eval_mir_constant(fx, value)
-                    .unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved"));
+                let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
                 let value = rustc_codegen_ssa::common::asm_const_to_str(
                     fx.tcx,
                     span,
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 377dc753f68..a49530ebb4c 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -113,7 +113,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             match self.ret.mode {
                 PassMode::Ignore => cx.type_void(),
                 PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
-                PassMode::Cast(ref cast, _) => cast.gcc_type(cx),
+                PassMode::Cast { ref cast, .. } => cast.gcc_type(cx),
                 PassMode::Indirect { .. } => {
                     argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
                     cx.type_void()
@@ -129,21 +129,21 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
                     continue;
                 }
-                PassMode::Indirect { extra_attrs: Some(_), .. } => {
+                PassMode::Indirect { meta_attrs: Some(_), .. } => {
                     unimplemented!();
                 }
-                PassMode::Cast(ref cast, pad_i32) => {
+                PassMode::Cast { ref cast, pad_i32 } => {
                     // add padding
                     if pad_i32 {
                         argument_tys.push(Reg::i32().gcc_type(cx));
                     }
                     cast.gcc_type(cx)
                 }
-                PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => {
+                PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => {
                     on_stack_param_indices.insert(argument_tys.len());
                     arg.memory_ty(cx)
                 },
-                PassMode::Indirect { extra_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
+                PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
             };
             argument_tys.push(arg_ty);
         }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index f8c32c6dbbb..68a087a1d7f 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -144,7 +144,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                 sym::volatile_load | sym::unaligned_volatile_load => {
                     let tp_ty = fn_args.type_at(0);
                     let mut ptr = args[0].immediate();
-                    if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
+                    if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
                         ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
                     }
                     let load = self.volatile_load(ptr.get_type(), ptr);
@@ -353,7 +353,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
             };
 
         if !fn_abi.ret.is_ignore() {
-            if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
+            if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
                 let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
                 let ptr = self.pointercast(result.llval, ptr_llty);
                 self.store(llval, ptr, result.align);
@@ -449,7 +449,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
         else if self.is_unsized_indirect() {
             bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
         }
-        else if let PassMode::Cast(ref cast, _) = self.mode {
+        else if let PassMode::Cast { ref cast, .. } = self.mode {
             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
             // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
             let can_store_through_cast_ptr = false;
@@ -511,10 +511,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             PassMode::Pair(..) => {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             },
-            PassMode::Indirect { extra_attrs: Some(_), .. } => {
+            PassMode::Indirect { meta_attrs: Some(_), .. } => {
                 OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
             },
-            PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => {
+            PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } | PassMode::Cast { .. } => {
                 let next_arg = next();
                 self.store(bx, next_arg, dst);
             },
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 64587f98b8a..9e834b83df4 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -211,7 +211,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
         } else if self.is_unsized_indirect() {
             bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
-        } else if let PassMode::Cast(cast, _) = &self.mode {
+        } else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode {
             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
             // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
             let can_store_through_cast_ptr = false;
@@ -274,12 +274,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             PassMode::Pair(..) => {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
-            PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
+            PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
                 OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
             }
             PassMode::Direct(_)
-            | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
-            | PassMode::Cast(..) => {
+            | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
+            | PassMode::Cast { .. } => {
                 let next_arg = next();
                 self.store(bx, next_arg, dst);
             }
@@ -332,7 +332,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         let llreturn_ty = match &self.ret.mode {
             PassMode::Ignore => cx.type_void(),
             PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
-            PassMode::Cast(cast, _) => cast.llvm_type(cx),
+            PassMode::Cast { cast, pad_i32: _ } => cast.llvm_type(cx),
             PassMode::Indirect { .. } => {
                 llargument_tys.push(cx.type_ptr());
                 cx.type_void()
@@ -351,6 +351,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
                     // aggregates...
                     if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
+                        assert!(
+                            arg.layout.is_sized(),
+                            "`PassMode::Direct` for unsized type: {}",
+                            arg.layout.ty
+                        );
                         // This really shouldn't happen, since `immediate_llvm_type` will use
                         // `layout.fields` to turn this Rust type into an LLVM type. This means all
                         // sorts of Rust type details leak into the ABI. However wasm sadly *does*
@@ -378,8 +383,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
                     continue;
                 }
-                PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
-                    assert!(arg.layout.is_unsized());
+                PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => {
+                    // `Indirect` with metadata is only for unsized types, and doesn't work with
+                    // on-stack passing.
+                    assert!(arg.layout.is_unsized() && !on_stack);
                     // Construct the type of a (wide) pointer to `ty`, and pass its two fields.
                     // Any two ABI-compatible unsized types have the same metadata type and
                     // moreover the same metadata value leads to the same dynamic size and
@@ -390,7 +397,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
                     continue;
                 }
-                PassMode::Cast(cast, pad_i32) => {
+                PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
+                    assert!(arg.layout.is_sized());
+                    cx.type_ptr()
+                }
+                PassMode::Cast { cast, pad_i32 } => {
+                    // `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
+                    assert!(arg.layout.is_sized());
                     // add padding
                     if *pad_i32 {
                         llargument_tys.push(Reg::i32().llvm_type(cx));
@@ -399,7 +412,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     // We assume here that ABI-compatible Rust types have the same cast type.
                     cast.llvm_type(cx)
                 }
-                PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
             };
             llargument_tys.push(llarg_ty);
         }
@@ -442,13 +454,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             PassMode::Direct(attrs) => {
                 attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
             }
-            PassMode::Indirect { attrs, extra_attrs: _, on_stack } => {
+            PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
                 assert!(!on_stack);
                 let i = apply(attrs);
                 let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
                 attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
             }
-            PassMode::Cast(cast, _) => {
+            PassMode::Cast { cast, pad_i32: _ } => {
                 cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
             }
             _ => {}
@@ -456,25 +468,25 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         for arg in self.args.iter() {
             match &arg.mode {
                 PassMode::Ignore => {}
-                PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
+                PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
                     let i = apply(attrs);
                     let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
                     attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
                 }
                 PassMode::Direct(attrs)
-                | PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
+                | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
                     apply(attrs);
                 }
-                PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => {
+                PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
                     assert!(!on_stack);
                     apply(attrs);
-                    apply(extra_attrs);
+                    apply(meta_attrs);
                 }
                 PassMode::Pair(a, b) => {
                     apply(a);
                     apply(b);
                 }
-                PassMode::Cast(cast, pad_i32) => {
+                PassMode::Cast { cast, pad_i32 } => {
                     if *pad_i32 {
                         apply(&ArgAttributes::new());
                     }
@@ -504,13 +516,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             PassMode::Direct(attrs) => {
                 attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
             }
-            PassMode::Indirect { attrs, extra_attrs: _, on_stack } => {
+            PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
                 assert!(!on_stack);
                 let i = apply(bx.cx, attrs);
                 let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
                 attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
             }
-            PassMode::Cast(cast, _) => {
+            PassMode::Cast { cast, pad_i32: _ } => {
                 cast.attrs.apply_attrs_to_callsite(
                     llvm::AttributePlace::ReturnValue,
                     &bx.cx,
@@ -532,7 +544,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         for arg in self.args.iter() {
             match &arg.mode {
                 PassMode::Ignore => {}
-                PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
+                PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
                     let i = apply(bx.cx, attrs);
                     let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
                     attributes::apply_to_callsite(
@@ -542,18 +554,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     );
                 }
                 PassMode::Direct(attrs)
-                | PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
+                | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
                     apply(bx.cx, attrs);
                 }
-                PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack: _ } => {
+                PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack: _ } => {
                     apply(bx.cx, attrs);
-                    apply(bx.cx, extra_attrs);
+                    apply(bx.cx, meta_attrs);
                 }
                 PassMode::Pair(a, b) => {
                     apply(bx.cx, a);
                     apply(bx.cx, b);
                 }
-                PassMode::Cast(cast, pad_i32) => {
+                PassMode::Cast { cast, pad_i32 } => {
                     if *pad_i32 {
                         apply(bx.cx, &ArgAttributes::new());
                     }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a9b06030e70..9289c37d763 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -165,7 +165,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             sym::volatile_load | sym::unaligned_volatile_load => {
                 let tp_ty = fn_args.type_at(0);
                 let ptr = args[0].immediate();
-                let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
+                let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
                     let llty = ty.llvm_type(self);
                     self.volatile_load(llty, ptr)
                 } else {
@@ -386,7 +386,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         };
 
         if !fn_abi.ret.is_ignore() {
-            if let PassMode::Cast(_, _) = &fn_abi.ret.mode {
+            if let PassMode::Cast { .. } = &fn_abi.ret.mode {
                 self.store(llval, result.llval, result.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 9ce13ff469c..d0a078505d2 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -19,8 +19,6 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
 
 codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
 
-codegen_ssa_erroneous_constant = erroneous constant encountered
-
 codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
 
 codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)`
@@ -174,8 +172,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
 
 codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
 
-codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
-
 codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
     .note = {$output}
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index fa49095c9e8..bfd572a2eea 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -596,20 +596,6 @@ pub struct InvalidWindowsSubsystem {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa_erroneous_constant)]
-pub struct ErroneousConstant {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_ssa_polymorphic_constant_too_generic)]
-pub struct PolymorphicConstantTooGeneric {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_ssa_shuffle_indices_evaluation)]
 pub struct ShuffleIndicesEvaluation {
     #[primary_span]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index d8f6b4ed836..b738a49bf11 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -416,7 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
-            PassMode::Cast(cast_ty, _) => {
+            PassMode::Cast { cast: cast_ty, pad_i32: _ } => {
                 let op = match self.locals[mir::RETURN_PLACE] {
                     LocalRef::Operand(op) => op,
                     LocalRef::PendingOperand => bug!("use of return before def"),
@@ -1088,9 +1088,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
                 }
                 mir::InlineAsmOperand::Const { ref value } => {
-                    let const_value = self
-                        .eval_mir_constant(value)
-                        .unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
+                    let const_value = self.eval_mir_constant(value);
                     let string = common::asm_const_to_str(
                         bx.tcx(),
                         span,
@@ -1310,7 +1308,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) {
         match arg.mode {
             PassMode::Ignore => return,
-            PassMode::Cast(_, true) => {
+            PassMode::Cast { pad_i32: true, .. } => {
                 // Fill padding with undef value, where applicable.
                 llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32())));
             }
@@ -1322,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
                 _ => bug!("codegen_argument: {:?} invalid for pair argument", op),
             },
-            PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => match op.val {
+            PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val {
                 Ref(a, Some(b), _) => {
                     llargs.push(a);
                     llargs.push(b);
@@ -1347,7 +1345,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     op.val.store(bx, scratch);
                     (scratch.llval, scratch.align, true)
                 }
-                PassMode::Cast(..) => {
+                PassMode::Cast { .. } => {
                     let scratch = PlaceRef::alloca(bx, arg.layout);
                     op.val.store(bx, scratch);
                     (scratch.llval, scratch.align, true)
@@ -1400,7 +1398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         if by_ref && !arg.is_indirect() {
             // Have to load the argument, maybe while casting it.
-            if let PassMode::Cast(ty, _) = &arg.mode {
+            if let PassMode::Cast { cast: ty, .. } = &arg.mode {
                 let llty = bx.cast_backend_type(ty);
                 llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
             } else {
@@ -1744,7 +1742,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
-                let op = if let PassMode::Cast(..) = ret_abi.mode {
+                let op = if let PassMode::Cast { .. } = ret_abi.mode {
                     let tmp = PlaceRef::alloca(bx, ret_abi.layout);
                     tmp.storage_live(bx);
                     bx.store_arg(&ret_abi, llval, tmp);
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 4d7bd60ceca..263b41ed880 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -14,34 +14,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &self,
         bx: &mut Bx,
         constant: &mir::Constant<'tcx>,
-    ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
-        let val = self.eval_mir_constant(constant)?;
+    ) -> OperandRef<'tcx, Bx::Value> {
+        let val = self.eval_mir_constant(constant);
         let ty = self.monomorphize(constant.ty());
-        Ok(OperandRef::from_const(bx, val, ty))
+        OperandRef::from_const(bx, val, ty)
     }
 
-    pub fn eval_mir_constant(
-        &self,
-        constant: &mir::Constant<'tcx>,
-    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
+    pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> ConstValue<'tcx> {
         self.monomorphize(constant.literal)
             .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
-            .map_err(|err| {
-                match err {
-                    ErrorHandled::Reported(_) => {
-                        self.cx
-                            .tcx()
-                            .sess
-                            .emit_err(errors::ErroneousConstant { span: constant.span });
-                    }
-                    ErrorHandled::TooGeneric => {
-                        self.cx.tcx().sess.diagnostic().emit_bug(
-                            errors::PolymorphicConstantTooGeneric { span: constant.span },
-                        );
-                    }
-                }
-                err
-            })
+            .expect("erroneous constant not captured by required_consts")
     }
 
     /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index ac705a5f35c..d1560114763 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -579,23 +579,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     if let Some(dbg_var) = dbg_var {
                         let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
 
-                        if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
-                            self.set_debug_loc(bx, var.source_info);
-                            let base = Self::spill_operand_to_stack(
-                                operand,
-                                Some(var.name.to_string()),
-                                bx,
-                            );
-
-                            bx.dbg_var_addr(
-                                dbg_var,
-                                dbg_loc,
-                                base.llval,
-                                Size::ZERO,
-                                &[],
-                                fragment,
-                            );
-                        }
+                        let operand = self.eval_mir_constant_to_operand(bx, &c);
+                        self.set_debug_loc(bx, var.source_info);
+                        let base =
+                            Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
+
+                        bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
                     }
                 }
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 8821fb21fd0..8efef440522 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         if !fn_abi.ret.is_ignore() {
-            if let PassMode::Cast(..) = &fn_abi.ret.mode {
+            if let PassMode::Cast { .. } = &fn_abi.ret.mode {
                 bx.store(llval, result.llval, result.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index c4408f2db4c..1e905a7c78e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -3,7 +3,6 @@ use crate::traits::*;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::UnwindTerminateReason;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
@@ -212,23 +211,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
 
-    // Evaluate all required consts; codegen later assumes that CTFE will never fail.
-    let mut all_consts_ok = true;
-    for const_ in &mir.required_consts {
-        if let Err(err) = fx.eval_mir_constant(const_) {
-            all_consts_ok = false;
-            match err {
-                // errored or at least linted
-                ErrorHandled::Reported(_) => {}
-                ErrorHandled::TooGeneric => {
-                    span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
-                }
-            }
-        }
-    }
-    if !all_consts_ok {
-        // We leave the IR in some half-built state here, and rely on this code not even being
-        // submitted to LLVM once an error was raised.
+    // Rust post-monomorphization checks; we later rely on them.
+    if let Err(err) =
+        mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
+    {
+        err.emit_err(cx.tcx());
+        // This IR shouldn't ever be emitted, but let's try to guard against any of this code
+        // ever running.
+        start_bx.abort();
         return;
     }
 
@@ -327,7 +317,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 for i in 0..tupled_arg_tys.len() {
                     let arg = &fx.fn_abi.args[idx];
                     idx += 1;
-                    if let PassMode::Cast(_, true) = arg.mode {
+                    if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
                         llarg_idx += 1;
                     }
                     let pr_field = place.project_field(bx, i);
@@ -351,7 +341,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             let arg = &fx.fn_abi.args[idx];
             idx += 1;
-            if let PassMode::Cast(_, true) = arg.mode {
+            if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
                 llarg_idx += 1;
             }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 1926bb8df52..e192d16ff38 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -575,12 +575,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_consume(bx, place.as_ref())
             }
 
-            mir::Operand::Constant(ref constant) => {
-                // This cannot fail because we checked all required_consts in advance.
-                self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
-                    span_bug!(constant.span, "erroneous constant not captured by required_consts")
-                })
-            }
+            mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
         }
     }
 }
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 020402fe25e..d23e2a9f3e4 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -83,9 +83,6 @@ const_eval_dyn_call_vtable_mismatch =
 const_eval_dyn_star_call_vtable_mismatch =
     `dyn*` call on a pointer whose vtable does not match its type
 
-const_eval_erroneous_constant =
-    erroneous constant used
-
 const_eval_error = {$error_kind ->
     [static] could not evaluate static initializer
     [const] evaluation of constant value failed
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 2d20d553ef7..bf1e0a37073 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDi
 use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{layout::LayoutError, ConstInt};
-use rustc_span::{ErrorGuaranteed, Span, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
 
 use super::InterpCx;
 use crate::errors::{self, FrameNote, ReportErrorExt};
@@ -134,11 +134,11 @@ where
         // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
         // should remain silent.
         err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-            ErrorHandled::TooGeneric
+            ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))
         }
-        err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar),
+        err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)),
         err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
-            ErrorHandled::Reported(guar.into())
+            ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
         }
         // Report remaining errors.
         _ => {
@@ -152,7 +152,7 @@ where
 
             // Use *our* span to label the interp error
             err.span_label(our_span, msg);
-            ErrorHandled::Reported(err.emit().into())
+            ErrorHandled::Reported(err.emit().into(), span)
         }
     }
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 454baf2a745..807794a2a59 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -212,7 +212,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
         key.param_env = key.param_env.with_user_facing();
         match tcx.eval_to_const_value_raw(key) {
             // try again with reveal all as requested
-            Err(ErrorHandled::TooGeneric) => {}
+            Err(ErrorHandled::TooGeneric(_)) => {}
             // deduplicate calls
             other => return other,
         }
@@ -259,7 +259,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         key.param_env = key.param_env.with_user_facing();
         match tcx.eval_to_allocation_raw(key) {
             // try again with reveal all as requested
-            Err(ErrorHandled::TooGeneric) => {}
+            Err(ErrorHandled::TooGeneric(_)) => {}
             // deduplicate calls
             other => return other,
         }
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c3c6cbe3991..b1599dd6894 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -239,13 +239,6 @@ pub struct LongRunningWarn {
     pub item_span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(const_eval_erroneous_constant)]
-pub(crate) struct ErroneousConstUsed {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Subdiagnostic)]
 #[note(const_eval_non_const_impl)]
 pub(crate) struct NonConstImplNote {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 966ce66c7ad..cb14e165b5c 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -7,7 +7,7 @@ use hir::CRATE_HIR_ID;
 use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidMetaKind, ReportedErrorInfo};
+use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
@@ -21,10 +21,10 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
 
 use super::{
     AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
-    MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
+    MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
     Projectable, Provenance, Scalar, StackPopJump,
 };
-use crate::errors::{self, ErroneousConstUsed};
+use crate::errors;
 use crate::util;
 use crate::{fluent_generated as fluent, ReportErrorExt};
 
@@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     >(
         &self,
         value: T,
-    ) -> Result<T, InterpError<'tcx>> {
+    ) -> Result<T, ErrorHandled> {
         self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
     }
 
@@ -566,7 +566,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         value: T,
-    ) -> Result<T, InterpError<'tcx>> {
+    ) -> Result<T, ErrorHandled> {
         frame
             .instance
             .try_subst_mir_and_normalize_erasing_regions(
@@ -574,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.param_env,
                 ty::EarlyBinder::bind(value),
             )
-            .map_err(|_| err_inval!(TooGeneric))
+            .map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
     }
 
     /// The `args` are assumed to already be in our interpreter "universe" (param_env).
@@ -750,11 +750,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
         if M::POST_MONO_CHECKS {
-            for ct in &body.required_consts {
-                let span = ct.span;
-                let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
-                self.eval_mir_constant(&ct, Some(span), None)?;
-            }
+            // `ctfe_query` does some error message decoration that we want to be in effect here.
+            self.ctfe_query(None, |tcx| {
+                body.post_mono_checks(*tcx, self.param_env, |c| {
+                    self.subst_from_current_frame_and_normalize_erasing_regions(c)
+                })
+            })?;
         }
 
         // done
@@ -1059,28 +1060,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         span: Option<Span>,
         query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
-    ) -> InterpResult<'tcx, T> {
+    ) -> Result<T, ErrorHandled> {
         // Use a precise span for better cycle errors.
         query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
-            match err {
-                ErrorHandled::Reported(err) => {
-                    if !err.is_tainted_by_errors() && let Some(span) = span {
-                        // To make it easier to figure out where this error comes from, also add a note at the current location.
-                        self.tcx.sess.emit_note(ErroneousConstUsed { span });
-                    }
-                    err_inval!(AlreadyReported(err))
-                }
-                ErrorHandled::TooGeneric => err_inval!(TooGeneric),
-            }
-            .into()
+            err.emit_note(*self.tcx);
+            err
         })
     }
 
     pub fn eval_global(
         &self,
-        gid: GlobalId<'tcx>,
-        span: Option<Span>,
+        instance: ty::Instance<'tcx>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+        let gid = GlobalId { instance, promoted: None };
         // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
         // and thus don't care about the parameter environment. While we could just use
         // `self.param_env`, that would mean we invoke the query to evaluate the static
@@ -1091,10 +1083,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         } else {
             self.param_env
         };
-        let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
+        let val = self.ctfe_query(None, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
         self.raw_const_to_mplace(val)
     }
 
+    pub fn eval_mir_constant(
+        &self,
+        val: &mir::ConstantKind<'tcx>,
+        span: Option<Span>,
+        layout: Option<TyAndLayout<'tcx>>,
+    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
+        let const_val = self.ctfe_query(span, |tcx| val.eval(*tcx, self.param_env, span))?;
+        self.const_val_to_op(const_val, val.ty(), layout)
+    }
+
     #[must_use]
     pub fn dump_place(
         &self,
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 8b33dbb677f..082c0f5b84e 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -8,15 +8,14 @@ use either::{Either, Left, Right};
 use rustc_hir::def::Namespace;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
-use rustc_middle::ty::{ConstInt, Ty, ValTree};
+use rustc_middle::ty::{ConstInt, Ty};
 use rustc_middle::{mir, ty};
-use rustc_span::Span;
 use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
 
 use super::{
-    alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId,
-    InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer,
-    Projectable, Provenance, Scalar,
+    alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, InterpCx,
+    InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable,
+    Provenance, Scalar,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -136,7 +135,11 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
 
 impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("ImmTy").field("imm", &self.imm).field("ty", &self.layout.ty).finish()
+        // Printing `layout` results in too much noise; just print a nice version of the type.
+        f.debug_struct("ImmTy")
+            .field("imm", &self.imm)
+            .field("ty", &format_args!("{}", self.layout.ty))
+            .finish()
     }
 }
 
@@ -305,7 +308,11 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
 
 impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("OpTy").field("op", &self.op).field("ty", &self.layout.ty).finish()
+        // Printing `layout` results in too much noise; just print a nice version of the type.
+        f.debug_struct("OpTy")
+            .field("op", &self.op)
+            .field("ty", &format_args!("{}", self.layout.ty))
+            .finish()
     }
 }
 
@@ -693,54 +700,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(op)
     }
 
-    fn eval_ty_constant(
-        &self,
-        val: ty::Const<'tcx>,
-        span: Option<Span>,
-    ) -> InterpResult<'tcx, ValTree<'tcx>> {
-        Ok(match val.kind() {
-            ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
-                throw_inval!(TooGeneric)
-            }
-            // FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated
-            ty::ConstKind::Expr(_) => throw_inval!(TooGeneric),
-            ty::ConstKind::Error(reported) => {
-                throw_inval!(AlreadyReported(reported.into()))
-            }
-            ty::ConstKind::Unevaluated(uv) => {
-                let instance = self.resolve(uv.def, uv.args)?;
-                let cid = GlobalId { instance, promoted: None };
-                self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))?
-                    .unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"))
-            }
-            ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
-                span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}")
-            }
-            ty::ConstKind::Value(valtree) => valtree,
-        })
-    }
-
-    pub fn eval_mir_constant(
-        &self,
-        val: &mir::ConstantKind<'tcx>,
-        span: Option<Span>,
-        layout: Option<TyAndLayout<'tcx>>,
-    ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        match *val {
-            mir::ConstantKind::Ty(ct) => {
-                let ty = ct.ty();
-                let valtree = self.eval_ty_constant(ct, span)?;
-                let const_val = self.tcx.valtree_to_const_val((ty, valtree));
-                self.const_val_to_op(const_val, ty, layout)
-            }
-            mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
-            mir::ConstantKind::Unevaluated(uv, _) => {
-                let instance = self.resolve(uv.def, uv.args)?;
-                Ok(self.eval_global(GlobalId { instance, promoted: uv.promoted }, span)?.into())
-            }
-        }
-    }
-
     pub(crate) fn const_val_to_op(
         &self,
         val_val: ConstValue<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 90f2b470179..0f66df5c30d 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -117,9 +117,10 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
 
 impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        // Printing `layout` results in too much noise; just print a nice version of the type.
         f.debug_struct("MPlaceTy")
             .field("mplace", &self.mplace)
-            .field("ty", &self.layout.ty)
+            .field("ty", &format_args!("{}", self.layout.ty))
             .finish()
     }
 }
@@ -237,7 +238,11 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
 
 impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("PlaceTy").field("place", &self.place).field("ty", &self.layout.ty).finish()
+        // Printing `layout` results in too much noise; just print a nice version of the type.
+        f.debug_struct("PlaceTy")
+            .field("place", &self.place)
+            .field("ty", &format_args!("{}", self.layout.ty))
+            .finish()
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 85ef2de9b5e..4075481e561 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -51,7 +51,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
     // Traverse the graph, collecting a number of things:
     //
     // * Preorder mapping (to it, and back to the actual ordering)
-    // * Postorder mapping (used exclusively for rank_partial_cmp on the final product)
+    // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product)
     // * Parents for each vertex in the preorder tree
     //
     // These are all done here rather than through one of the 'standard'
@@ -342,8 +342,8 @@ impl<Node: Idx> Dominators<Node> {
     /// relationship, the dominator will always precede the dominated. (The relative ordering
     /// of two unrelated nodes will also be consistent, but otherwise the order has no
     /// meaning.) This method cannot be used to determine if either Node dominates the other.
-    pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
-        self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
+    pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
+        self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs])
     }
 
     /// Returns true if `a` dominates `b`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0691.md b/compiler/rustc_error_codes/src/error_codes/E0691.md
index 483c74c0ff5..a5bedd61e92 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0691.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0691.md
@@ -1,9 +1,11 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A struct, enum, or union with the `repr(transparent)` representation hint
 contains a zero-sized field that requires non-trivial alignment.
 
 Erroneous code example:
 
-```compile_fail,E0691
+```ignore (error is no longer emitted)
 #![feature(repr_align)]
 
 #[repr(align(32))]
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index fcb112eadfe..f3b88f46bae 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -401,6 +401,8 @@ declare_features! (
     /// Allows function attribute `#[coverage(on/off)]`, to control coverage
     /// instrumentation of that function.
     (active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None),
+    /// Allows users to provide classes for fenced code block using `class:classname`.
+    (active, custom_code_classes_in_docs, "CURRENT_RUSTC_VERSION", Some(79483), None),
     /// Allows non-builtin attributes in inner attribute position.
     (active, custom_inner_attributes, "1.30.0", Some(54726), None),
     /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
@@ -414,7 +416,7 @@ declare_features! (
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
     (active, deprecated_suggestion, "1.61.0", Some(94785), None),
     /// Allows using the `#[diagnostic]` attribute tool namespace
-    (active, diagnostic_namespace, "1.73.0", Some(94785), None),
+    (active, diagnostic_namespace, "1.73.0", Some(111996), None),
     /// Controls errors in trait implementations.
     (active, do_not_recommend, "1.67.0", Some(51992), None),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b4b794d4e09..04ebe22a9eb 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -700,6 +700,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
     ),
     rustc_attr!(
+        rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
+        "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
+    ),
+    rustc_attr!(
         rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
         "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
     ),
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 50da2278312..18f7a18625e 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -95,6 +95,34 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par
 hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
     .note = parent implementation is in crate `{$cname}`
 
+hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait
+    .label = impl requires at least one non-auto trait
+    .note = define and implement a new trait or type instead
+
+hir_analysis_inherent_nominal = no nominal type found for inherent implementation
+    .label = impl requires a nominal type
+    .note = either implement a trait on it or create a newtype to wrap it instead
+hir_analysis_inherent_primitive_ty = cannot define inherent `impl` for primitive types
+    .help = consider using an extension trait instead
+
+hir_analysis_inherent_primitive_ty_note = you could also try moving the reference to uses of `{$subty}` (such as `self`) within the implementation
+
+hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outside of the crate where the type is defined
+    .help = consider moving this inherent impl into the crate defining the type if possible
+    .span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
+
+hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined
+    .label = impl for type defined outside of crate.
+    .note = define and implement a trait or new type instead
+
+hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core`
+    .help = consider moving this inherent impl into `core` if possible
+    .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
+
+hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a type outside of the crate where the type is defined
+    .help = consider moving this inherent impl into the crate defining the type if possible
+    .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
+
 hir_analysis_invalid_union_field =
     field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
     .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
@@ -276,13 +304,13 @@ hir_analysis_transparent_enum_variant = transparent enum needs exactly one varia
     .many_label = too many variants in `{$path}`
     .multi_label = variant here
 
-hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
-    .label = needs at most one non-zero-sized field, but has {$field_count}
-    .labels = this field is non-zero-sized
+hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count}
+    .label = needs at most one field with non-trivial size or alignment, but has {$field_count}
+    .labels = this field has non-zero size or requires alignment
 
-hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
-    .label = needs at most one non-zero-sized field, but has {$field_count}
-    .labels = this field is non-zero-sized
+hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count}
+    .label = needs at most one field with non-trivial size or alignment, but has {$field_count}
+    .labels = this field has non-zero size or requires alignment
 
 hir_analysis_typeof_reserved_keyword_used =
     `typeof` is a reserved keyword but unimplemented
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 9a57cc6dbab..13826264a22 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1138,19 +1138,19 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
         return;
     }
 
-    // For each field, figure out if it's known to be a ZST and align(1), with "known"
-    // respecting #[non_exhaustive] attributes.
+    // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
+    // "known" respecting #[non_exhaustive] attributes.
     let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
         let param_env = tcx.param_env(field.did);
         let layout = tcx.layout_of(param_env.and(ty));
         // We are currently checking the type this field came from, so it must be local
         let span = tcx.hir().span_if_local(field.did).unwrap();
-        let zst = layout.is_ok_and(|layout| layout.is_zst());
-        let align = layout.ok().map(|layout| layout.align.abi.bytes());
-        if !zst {
-            return (span, zst, align, None);
+        let trivial = layout.is_ok_and(|layout| layout.is_1zst());
+        if !trivial {
+            return (span, trivial, None);
         }
+        // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`.
 
         fn check_non_exhaustive<'tcx>(
             tcx: TyCtxt<'tcx>,
@@ -1184,58 +1184,52 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
             }
         }
 
-        (span, zst, align, check_non_exhaustive(tcx, ty).break_value())
+        (span, trivial, check_non_exhaustive(tcx, ty).break_value())
     });
 
-    let non_zst_fields = field_infos
+    let non_trivial_fields = field_infos
         .clone()
-        .filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
-    let non_zst_count = non_zst_fields.clone().count();
-    if non_zst_count >= 2 {
-        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
+        .filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
+    let non_trivial_count = non_trivial_fields.clone().count();
+    if non_trivial_count >= 2 {
+        bad_non_zero_sized_fields(
+            tcx,
+            adt,
+            non_trivial_count,
+            non_trivial_fields,
+            tcx.def_span(adt.did()),
+        );
+        return;
     }
-    let incompatible_zst_fields =
-        field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
-    let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
-    for (span, zst, align, non_exhaustive) in field_infos {
-        if zst && align != Some(1) {
-            let mut err = struct_span_err!(
-                tcx.sess,
-                span,
-                E0691,
-                "zero-sized field in transparent {} has alignment larger than 1",
-                adt.descr(),
-            );
-
-            if let Some(align_bytes) = align {
-                err.span_label(
+    let mut prev_non_exhaustive_1zst = false;
+    for (span, _trivial, non_exhaustive_1zst) in field_infos {
+        if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst {
+            // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
+            // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
+            if non_trivial_count > 0 || prev_non_exhaustive_1zst {
+                tcx.struct_span_lint_hir(
+                    REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+                    tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
                     span,
-                    format!("has alignment of {align_bytes}, which is larger than 1"),
-                );
+                    "zero-sized fields in `repr(transparent)` cannot \
+                    contain external non-exhaustive types",
+                    |lint| {
+                        let note = if non_exhaustive {
+                            "is marked with `#[non_exhaustive]`"
+                        } else {
+                            "contains private fields"
+                        };
+                        let field_ty = tcx.def_path_str_with_args(def_id, args);
+                        lint.note(format!(
+                            "this {descr} contains `{field_ty}`, which {note}, \
+                                and makes it not a breaking change to become \
+                                non-zero-sized in the future."
+                        ))
+                    },
+                )
             } else {
-                err.span_label(span, "may have alignment larger than 1");
+                prev_non_exhaustive_1zst = true;
             }
-
-            err.emit();
-        }
-        if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
-            tcx.struct_span_lint_hir(
-                REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
-                tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
-                span,
-                "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
-                |lint| {
-                    let note = if non_exhaustive {
-                        "is marked with `#[non_exhaustive]`"
-                    } else {
-                        "contains private fields"
-                    };
-                    let field_ty = tcx.def_path_str_with_args(def_id, args);
-                    lint
-                        .note(format!("this {descr} contains `{field_ty}`, which {note}, \
-                            and makes it not a breaking change to become non-zero-sized in the future."))
-                },
-            )
         }
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index a94c75f918a..aa7c9e504c1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -7,7 +7,6 @@
 //! `tcx.inherent_impls(def_id)`). That value, however,
 //! is computed by selecting an idea from this table.
 
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
+use crate::errors;
+
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
 pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
     let mut collect = InherentCollect { tcx, impls_map: Default::default() };
@@ -45,14 +46,6 @@ struct InherentCollect<'tcx> {
     impls_map: CrateInherentImpls,
 }
 
-const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
-const INTO_DEFINING_CRATE: &str =
-    "consider moving this inherent impl into the crate defining the type if possible";
-const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
-     and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
-const ADD_ATTR: &str =
-    "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
-
 impl<'tcx> InherentCollect<'tcx> {
     fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
         if let Some(ty_def_id) = ty_def_id.as_local() {
@@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> {
 
             if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
                 let impl_span = self.tcx.def_span(impl_def_id);
-                struct_span_err!(
-                    self.tcx.sess,
-                    impl_span,
-                    E0390,
-                    "cannot define inherent `impl` for a type outside of the crate where the type is defined",
-                )
-                .help(INTO_DEFINING_CRATE)
-                .span_help(impl_span, ADD_ATTR_TO_TY)
-                .emit();
+                self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
                 return;
             }
 
             for &impl_item in items {
                 if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                     let impl_span = self.tcx.def_span(impl_def_id);
-                    struct_span_err!(
-                        self.tcx.sess,
-                        impl_span,
-                        E0390,
-                        "cannot define inherent `impl` for a type outside of the crate where the type is defined",
-                    )
-                    .help(INTO_DEFINING_CRATE)
-                    .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
-                    .emit();
+                    self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
+                        span: impl_span,
+                        help_span: self.tcx.def_span(impl_item),
+                    });
                     return;
                 }
             }
@@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
             }
         } else {
             let impl_span = self.tcx.def_span(impl_def_id);
-            struct_span_err!(
-                self.tcx.sess,
-                impl_span,
-                E0116,
-                "cannot define inherent `impl` for a type outside of the crate \
-                              where the type is defined"
-            )
-            .span_label(impl_span, "impl for type defined outside of crate.")
-            .note("define and implement a trait or new type instead")
-            .emit();
+            self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
         }
     }
 
@@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> {
                 for &impl_item in items {
                     if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                         let span = self.tcx.def_span(impl_def_id);
-                        struct_span_err!(
-                            self.tcx.sess,
+                        self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
                             span,
-                            E0390,
-                            "cannot define inherent `impl` for primitive types outside of `core`",
-                        )
-                        .help(INTO_CORE)
-                        .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
-                        .emit();
+                            help_span: self.tcx.def_span(impl_item),
+                        });
                         return;
                     }
                 }
             } else {
                 let span = self.tcx.def_span(impl_def_id);
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0390,
-                    "cannot define inherent `impl` for primitive types",
-                );
-                err.help("consider using an extension trait instead");
+                let mut note = None;
                 if let ty::Ref(_, subty, _) = ty.kind() {
-                    err.note(format!(
-                        "you could also try moving the reference to \
-                            uses of `{subty}` (such as `self`) within the implementation"
-                    ));
+                    note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
                 }
-                err.emit();
+                self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
                 return;
             }
         }
@@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
             }
             ty::Dynamic(..) => {
-                struct_span_err!(
-                    self.tcx.sess,
-                    item_span,
-                    E0785,
-                    "cannot define inherent `impl` for a dyn auto trait"
-                )
-                .span_label(item_span, "impl requires at least one non-auto trait")
-                .note("define and implement a new trait or type instead")
-                .emit();
+                self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
             }
             ty::Bool
             | ty::Char
@@ -202,17 +151,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::FnPtr(_)
             | ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
             ty::Alias(..) | ty::Param(_) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    item_span,
-                    E0118,
-                    "no nominal type found for inherent implementation"
-                );
-
-                err.span_label(item_span, "impl requires a nominal type")
-                    .note("either implement a trait on it or create a newtype to wrap it instead");
-
-                err.emit();
+                self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
             }
             ty::FnDef(..)
             | ty::Closure(..)
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 7614913f4bf..b83ef8d07db 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -943,3 +943,75 @@ pub struct AssocBoundOnConst {
     pub span: Span,
     pub descr: &'static str,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
+#[help]
+pub struct InherentTyOutside {
+    #[primary_span]
+    #[help(hir_analysis_span_help)]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")]
+#[help]
+pub struct InherentTyOutsideRelevant {
+    #[primary_span]
+    pub span: Span,
+    #[help(hir_analysis_span_help)]
+    pub help_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")]
+#[note]
+pub struct InherentTyOutsideNew {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")]
+#[help]
+pub struct InherentTyOutsidePrimitive {
+    #[primary_span]
+    pub span: Span,
+    #[help(hir_analysis_span_help)]
+    pub help_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")]
+#[help]
+pub struct InherentPrimitiveTy<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub note: Option<InherentPrimitiveTyNote<'a>>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_analysis_inherent_primitive_ty_note)]
+pub struct InherentPrimitiveTyNote<'a> {
+    pub subty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_dyn, code = "E0785")]
+#[note]
+pub struct InherentDyn {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_nominal, code = "E0118")]
+#[note]
+pub struct InherentNominal {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index b0f333b79ca..ef788935efb 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -117,7 +117,7 @@ use rustc_hir::def::DefKind;
 fluent_messages! { "../messages.ftl" }
 
 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
-    const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
+    const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`";
     const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
     const UNSTABLE_EXPLAIN: &str =
         "using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 034ffc17a7a..921a5f5154a 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -16,6 +16,21 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`
     *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
 }
 
+hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
+    .suggestion = compare with zero instead
+    .help = compare with zero instead
+    .label = unsupported cast
+
+hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
+
+hir_typeck_cast_unknown_pointer = cannot cast {$to ->
+    [true] to
+    *[false] from
+    } a pointer of an unknown kind
+    .label_to = needs more type information
+    .note = the type information given here is insufficient to check whether the pointer cast is valid
+    .label_from = the type information given here is insufficient to check whether the pointer cast is valid
+
 hir_typeck_const_select_must_be_const = this argument must be a `const fn`
     .help = consult the documentation on `const_eval_select` for more information
 
@@ -29,10 +44,16 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `
 
 hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
 
+hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
+
 hir_typeck_expected_default_return_type = expected `()` because of default return type
 
 hir_typeck_expected_return_type = expected `{$expected}` because of return type
 
+hir_typeck_explicit_destructor = explicit use of destructor method
+    .label = explicit destructor calls not allowed
+    .suggestion = consider using `drop` function
+
 hir_typeck_field_multiply_specified_in_initializer =
     field `{$ident}` specified more than once
     .label = used more than once
@@ -52,8 +73,17 @@ hir_typeck_functional_record_update_on_non_struct =
 
 hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
 hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
-hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
 
+hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide ->
+    [true] is
+    *[false] may be
+    } wide
+hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata}
+hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+hir_typeck_invalid_callee = expected function, found {$ty}
+
+hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
 hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
 hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
 
@@ -63,9 +93,22 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
 hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
     .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
 
+hir_typeck_lossy_provenance_int2ptr =
+    strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
+    .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
+    .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+
+hir_typeck_lossy_provenance_ptr2int =
+    under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
+    .suggestion = use `.addr()` to obtain the address of a pointer
+    .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+
 hir_typeck_method_call_on_unknown_raw_pointee =
     cannot call a method on a raw pointer with an unknown pointee type
 
+hir_typeck_missing_fn_lang_items = failed to find an overloaded call trait for closure call
+    .help = make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
+
 hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
 
 hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
@@ -92,6 +135,9 @@ hir_typeck_return_stmt_outside_of_fn_body =
     .encl_body_label = the {$statement_kind} is part of this body...
     .encl_fn_label = ...not the enclosing function body
 
+hir_typeck_rustcall_incorrect_args =
+    functions with the "rust-call" ABI must take a single non-self tuple argument
+
 hir_typeck_struct_expr_non_exhaustive =
     cannot create non-exhaustive {$what} using struct expression
 
@@ -101,8 +147,18 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `
 
 hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
 
+hir_typeck_trivial_cast = trivial {$numeric ->
+    [true] numeric cast
+    *[false] cast
+    }: `{$expr_ty}` as `{$cast_ty}`
+    .help = cast can be replaced by coercion; this might require a temporary variable
+
 hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
 
 hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
+
+hir_typeck_use_is_empty =
+    consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
+
 hir_typeck_yield_expr_outside_of_generator =
     yield expression outside of generator literal
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 02371f85ac3..b39919ece71 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -2,9 +2,9 @@ use super::method::probe::ProbeScope;
 use super::method::MethodCallee;
 use super::{Expectation, FnCtxt, TupleArgumentsFlag};
 
-use crate::type_error_struct;
+use crate::errors;
 use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
+use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
@@ -44,23 +44,15 @@ pub fn check_legal_trait_for_method_call(
     trait_id: DefId,
 ) {
     if tcx.lang_items().drop_trait() == Some(trait_id) {
-        let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
-        err.span_label(span, "explicit destructor calls not allowed");
-
-        let (sp, suggestion) = receiver
-            .and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok())
-            .filter(|snippet| !snippet.is_empty())
-            .map(|snippet| (expr_span, format!("drop({snippet})")))
-            .unwrap_or_else(|| (span, "drop".to_string()));
-
-        err.span_suggestion(
-            sp,
-            "consider using `drop` function",
-            suggestion,
-            Applicability::MaybeIncorrect,
-        );
-
-        err.emit();
+        let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
+            errors::ExplicitDestructorCallSugg::Snippet {
+                lo: expr_span.shrink_to_lo(),
+                hi: receiver.shrink_to_hi().to(expr_span.shrink_to_hi()),
+            }
+        } else {
+            errors::ExplicitDestructorCallSugg::Empty(span)
+        };
+        tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg });
     }
 }
 
@@ -387,6 +379,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Unit testing: function items annotated with
                 // `#[rustc_evaluate_where_clauses]` trigger special output
                 // to let us test the trait evaluation system.
+                // Untranslatable diagnostics are okay for rustc internals
+                #[allow(rustc::untranslatable_diagnostic)]
+                #[allow(rustc::diagnostic_outside_of_impl)]
                 if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
                     let predicates = self.tcx.predicates_of(def_id);
                     let predicates = predicates.instantiate(self.tcx, args);
@@ -478,10 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
                 self.require_type_is_sized(ty, sp, traits::RustCall);
             } else {
-                self.tcx.sess.span_err(
-                        sp,
-                        "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
-                    );
+                self.tcx.sess.emit_err(errors::RustCallIncorrectArgs { span: sp });
             }
         }
 
@@ -610,17 +602,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let callee_ty = self.resolve_vars_if_possible(callee_ty);
-        let mut err = type_error_struct!(
-            self.tcx.sess,
-            callee_expr.span,
-            callee_ty,
-            E0618,
-            "expected function, found {}",
-            match &unit_variant {
+        let mut err = self.tcx.sess.create_err(errors::InvalidCallee {
+            span: callee_expr.span,
+            ty: match &unit_variant {
                 Some((_, kind, path)) => format!("{kind} `{path}`"),
                 None => format!("`{callee_ty}`"),
-            }
-        );
+            },
+        });
+        if callee_ty.references_error() {
+            err.downgrade_to_delayed_bug();
+        }
 
         self.identify_bad_closure_def_and_call(
             &mut err,
@@ -891,15 +882,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
             None => {
                 // This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once`
                 // lang items are not defined (issue #86238).
-                let mut err = fcx.inh.tcx.sess.struct_span_err(
-                    self.call_expr.span,
-                    "failed to find an overloaded call trait for closure call",
-                );
-                err.help(
-                    "make sure the `fn`/`fn_mut`/`fn_once` lang items are defined \
-                     and have correctly defined `call`/`call_mut`/`call_once` methods",
-                );
-                err.emit();
+                fcx.inh.tcx.sess.emit_err(errors::MissingFnLangItems { span: self.call_expr.span });
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index e8d4e6b447f..fa779701e61 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -30,11 +30,10 @@
 
 use super::FnCtxt;
 
+use crate::errors;
 use crate::type_error_struct;
 use hir::ExprKind;
-use rustc_errors::{
-    struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::mir::Mutability;
@@ -321,33 +320,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 .emit();
             }
             CastError::CastToBool => {
-                let mut err = struct_span_err!(
-                    fcx.tcx.sess,
-                    self.span,
-                    E0054,
-                    "cannot cast `{}` as `bool`",
-                    self.expr_ty
-                );
-
-                if self.expr_ty.is_numeric() {
-                    match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
-                        Ok(snippet) => {
-                            err.span_suggestion(
-                                self.span,
-                                "compare with zero instead",
-                                format!("{snippet} != 0"),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        Err(_) => {
-                            err.span_help(self.span, "compare with zero instead");
-                        }
-                    }
+                let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+                let help = if self.expr_ty.is_numeric() {
+                    errors::CannotCastToBoolHelp::Numeric(
+                        self.expr_span.shrink_to_hi().with_hi(self.span.hi()),
+                    )
                 } else {
-                    err.span_label(self.span, "unsupported cast");
-                }
-
-                err.emit();
+                    errors::CannotCastToBoolHelp::Unsupported(self.span)
+                };
+                fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
             }
             CastError::CastToChar => {
                 let mut err = type_error_struct!(
@@ -536,33 +517,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 .emit();
             }
             CastError::IntToFatCast(known_metadata) => {
-                let mut err = struct_span_err!(
-                    fcx.tcx.sess,
-                    self.cast_span,
-                    E0606,
-                    "cannot cast `{}` to a pointer that {} wide",
-                    fcx.ty_to_string(self.expr_ty),
-                    if known_metadata.is_some() { "is" } else { "may be" }
-                );
-
-                err.span_label(
-                    self.cast_span,
-                    format!(
-                        "creating a `{}` requires both an address and {}",
-                        self.cast_ty,
-                        known_metadata.unwrap_or("type-specific metadata"),
-                    ),
-                );
-
-                if fcx.tcx.sess.is_nightly_build() {
-                    err.span_label(
-                        self.expr_span,
-                        "consider casting this expression to `*const ()`, \
-                        then using `core::ptr::from_raw_parts`",
-                    );
-                }
-
-                err.emit();
+                let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
+                let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+                let expr_ty = fcx.ty_to_string(self.expr_ty);
+                let metadata = known_metadata.unwrap_or("type-specific metadata");
+                let known_wide = known_metadata.is_some();
+                let span = self.cast_span;
+                fcx.tcx.sess.emit_err(errors::IntToWide {
+                    span,
+                    metadata,
+                    expr_ty,
+                    cast_ty,
+                    expr_if_nightly,
+                    known_wide,
+                });
             }
             CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
                 let unknown_cast_to = match e {
@@ -570,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     CastError::UnknownExprPtrKind => false,
                     _ => bug!(),
                 };
-                let mut err = struct_span_err!(
-                    fcx.tcx.sess,
-                    if unknown_cast_to { self.cast_span } else { self.span },
-                    E0641,
-                    "cannot cast {} a pointer of an unknown kind",
-                    if unknown_cast_to { "to" } else { "from" }
-                );
-                if unknown_cast_to {
-                    err.span_label(self.cast_span, "needs more type information");
-                    err.note(
-                        "the type information given here is insufficient to check whether \
-                        the pointer cast is valid",
-                    );
+                let (span, sub) = if unknown_cast_to {
+                    (self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span))
                 } else {
-                    err.span_label(
-                        self.span,
-                        "the type information given here is insufficient to check whether \
-                        the pointer cast is valid",
-                    );
-                }
-                err.emit();
+                    (self.cast_span, errors::CastUnknownPointerSub::From(self.span))
+                };
+                fcx.tcx.sess.emit_err(errors::CastUnknownPointer {
+                    span,
+                    to: unknown_cast_to,
+                    sub,
+                });
             }
             CastError::ForeignNonExhaustiveAdt => {
                 make_invalid_casting_error(
@@ -674,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
-        let t_cast = self.cast_ty;
-        let t_expr = self.expr_ty;
-        let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
-            ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
+        let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() {
+            (true, lint::builtin::TRIVIAL_NUMERIC_CASTS)
         } else {
-            ("", lint::builtin::TRIVIAL_CASTS)
+            (false, lint::builtin::TRIVIAL_CASTS)
         };
-        fcx.tcx.struct_span_lint_hir(
+        let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+        let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+        fcx.tcx.emit_spanned_lint(
             lint,
             self.expr.hir_id,
             self.span,
-            DelayDm(|| {
-                format!(
-                    "trivial {}cast: `{}` as `{}`",
-                    adjective,
-                    fcx.ty_to_string(t_expr),
-                    fcx.ty_to_string(t_cast)
-                )
-            }),
-            |lint| {
-                lint.help(
-                    "cast can be replaced by coercion; this might \
-                     require a temporary variable",
-                )
-            },
+            errors::TrivialCast { numeric, expr_ty, cast_ty },
         );
     }
 
@@ -991,93 +935,67 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         if let ty::Adt(d, _) = self.expr_ty.kind()
             && d.has_dtor(fcx.tcx)
         {
-            fcx.tcx.struct_span_lint_hir(
+            let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+            let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+
+            fcx.tcx.emit_spanned_lint(
                 lint::builtin::CENUM_IMPL_DROP_CAST,
                 self.expr.hir_id,
                 self.span,
-                DelayDm(|| format!(
-                    "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
-                    self.expr_ty, self.cast_ty
-                )),
-                |lint| {
-                    lint
-                },
+                errors::CastEnumDrop {
+                    expr_ty,
+                    cast_ty,
+                }
             );
         }
     }
 
     fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
-        fcx.tcx.struct_span_lint_hir(
+        let expr_prec = self.expr.precedence().order();
+        let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
+
+        let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
+        let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
+        let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+        let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+        let expr_span = self.expr_span.shrink_to_lo();
+        let sugg = match (needs_parens, needs_cast) {
+            (true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast {
+                expr_span,
+                cast_span,
+                cast_ty,
+            },
+            (true, false) => {
+                errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span }
+            }
+            (false, true) => {
+                errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty }
+            }
+            (false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span },
+        };
+
+        let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg };
+        fcx.tcx.emit_spanned_lint(
             lint::builtin::LOSSY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            DelayDm(|| format!(
-                    "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
-                    self.expr_ty, self.cast_ty
-                )),
-            |lint| {
-                let msg = "use `.addr()` to obtain the address of a pointer";
-
-                let expr_prec = self.expr.precedence().order();
-                let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
-
-                let scalar_cast = match t_c {
-                    ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
-                    _ => format!(" as {}", self.cast_ty),
-                };
-
-                let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
-
-                if needs_parens {
-                    let suggestions = vec![
-                        (self.expr_span.shrink_to_lo(), String::from("(")),
-                        (cast_span, format!(").addr(){scalar_cast}")),
-                    ];
-
-                    lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
-                } else {
-                    lint.span_suggestion(
-                        cast_span,
-                        msg,
-                        format!(".addr(){scalar_cast}"),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-
-                lint.help(
-                    "if you can't comply with strict provenance and need to expose the pointer \
-                    provenance you can use `.expose_addr()` instead"
-                );
-
-                lint
-            },
+            lint,
         );
     }
 
     fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
-        fcx.tcx.struct_span_lint_hir(
+        let sugg = errors::LossyProvenanceInt2PtrSuggestion {
+            lo: self.expr_span.shrink_to_lo(),
+            hi: self.expr_span.shrink_to_hi().to(self.cast_span),
+        };
+        let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+        let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+        let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg };
+        fcx.tcx.emit_spanned_lint(
             lint::builtin::FUZZY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            DelayDm(|| format!(
-                "strict provenance disallows casting integer `{}` to pointer `{}`",
-                self.expr_ty, self.cast_ty
-            )),
-            |lint| {
-                let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
-                let suggestions = vec![
-                    (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
-                    (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
-                ];
-
-                lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
-                lint.help(
-                    "if you can't comply with strict provenance and don't have a pointer with \
-                    the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
-                 );
-
-                lint
-            },
+            lint,
         );
     }
 
@@ -1093,26 +1011,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             if let Some((deref_ty, _)) = derefed {
                 // Give a note about what the expr derefs to.
                 if deref_ty != self.expr_ty.peel_refs() {
-                    err.span_note(
-                        self.expr_span,
-                        format!(
-                            "this expression `Deref`s to `{}` which implements `is_empty`",
-                            fcx.ty_to_string(deref_ty)
-                        ),
-                    );
+                    err.subdiagnostic(errors::DerefImplsIsEmpty {
+                        span: self.expr_span,
+                        deref_ty: fcx.ty_to_string(deref_ty),
+                    });
                 }
 
                 // Create a multipart suggestion: add `!` and `.is_empty()` in
                 // place of the cast.
-                let suggestion = vec![
-                    (self.expr_span.shrink_to_lo(), "!".to_string()),
-                    (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
-                ];
-
-                err.multipart_suggestion_verbose(format!(
-                    "consider using the `is_empty` method on `{}` to determine if it contains anything",
-                    fcx.ty_to_string(self.expr_ty),
-                ),  suggestion, Applicability::MaybeIncorrect);
+                err.subdiagnostic(errors::UseIsEmpty {
+                    lo: self.expr_span.shrink_to_lo(),
+                    hi: self.span.with_lo(self.expr_span.hi()),
+                    expr_ty: fcx.ty_to_string(self.expr_ty),
+                });
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 255fe5e0206..7152585d440 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
     SubdiagnosticMessage,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{
     edition::{Edition, LATEST_STABLE_EDITION},
@@ -55,6 +55,13 @@ impl IntoDiagnosticArg for ReturnLikeStatementKind {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_typeck_rustcall_incorrect_args)]
+pub struct RustCallIncorrectArgs {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")]
 pub struct YieldExprOutsideOfGenerator {
     #[primary_span]
@@ -77,6 +84,14 @@ pub struct MethodCallOnUnknownRawPointee {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_typeck_missing_fn_lang_items)]
+#[help]
+pub struct MissingFnLangItems {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[primary_span]
@@ -130,6 +145,29 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_typeck_explicit_destructor, code = "E0040")]
+pub struct ExplicitDestructorCall {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: ExplicitDestructorCallSugg,
+}
+
+#[derive(Subdiagnostic)]
+pub enum ExplicitDestructorCallSugg {
+    #[suggestion(hir_typeck_suggestion, code = "drop", applicability = "maybe-incorrect")]
+    Empty(#[primary_span] Span),
+    #[multipart_suggestion(hir_typeck_suggestion, style = "short")]
+    Snippet {
+        #[suggestion_part(code = "drop(")]
+        lo: Span,
+        #[suggestion_part(code = ")")]
+        hi: Span,
+    },
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
 pub struct MissingParenthesesInRange {
     #[primary_span]
@@ -231,6 +269,69 @@ pub struct LangStartIncorrectRetTy<'tcx> {
     pub found_ty: Ty<'tcx>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_lossy_provenance_int2ptr)]
+#[help]
+pub struct LossyProvenanceInt2Ptr<'tcx> {
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub sugg: LossyProvenanceInt2PtrSuggestion,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
+pub struct LossyProvenanceInt2PtrSuggestion {
+    #[suggestion_part(code = "(...).with_addr(")]
+    pub lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_lossy_provenance_ptr2int)]
+#[help]
+pub struct LossyProvenancePtr2Int<'tcx> {
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub sugg: LossyProvenancePtr2IntSuggestion<'tcx>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum LossyProvenancePtr2IntSuggestion<'tcx> {
+    #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
+    NeedsParensCast {
+        #[suggestion_part(code = "(")]
+        expr_span: Span,
+        #[suggestion_part(code = ").addr() as {cast_ty}")]
+        cast_span: Span,
+        cast_ty: Ty<'tcx>,
+    },
+    #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
+    NeedsParens {
+        #[suggestion_part(code = "(")]
+        expr_span: Span,
+        #[suggestion_part(code = ").addr()")]
+        cast_span: Span,
+    },
+    #[suggestion(
+        hir_typeck_suggestion,
+        code = ".addr() as {cast_ty}",
+        applicability = "maybe-incorrect"
+    )]
+    NeedsCast {
+        #[primary_span]
+        cast_span: Span,
+        cast_ty: Ty<'tcx>,
+    },
+    #[suggestion(hir_typeck_suggestion, code = ".addr()", applicability = "maybe-incorrect")]
+    Other {
+        #[primary_span]
+        cast_span: Span,
+    },
+}
+
 #[derive(Subdiagnostic)]
 pub enum HelpUseLatestEdition {
     #[help(hir_typeck_help_set_edition_cargo)]
@@ -252,6 +353,28 @@ impl HelpUseLatestEdition {
     }
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_typeck_invalid_callee, code = "E0618")]
+pub struct InvalidCallee {
+    #[primary_span]
+    pub span: Span,
+    pub ty: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_int_to_fat, code = "E0606")]
+pub struct IntToWide<'tcx> {
+    #[primary_span]
+    #[label(hir_typeck_int_to_fat_label)]
+    pub span: Span,
+    pub metadata: &'tcx str,
+    pub expr_ty: String,
+    pub cast_ty: Ty<'tcx>,
+    #[label(hir_typeck_int_to_fat_label_nightly)]
+    pub expr_if_nightly: Option<Span>,
+    pub known_wide: bool,
+}
+
 #[derive(Subdiagnostic)]
 pub enum OptionResultRefMismatch {
     #[suggestion(
@@ -350,6 +473,20 @@ pub struct UnionPatDotDot {
     pub span: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    hir_typeck_use_is_empty,
+    applicability = "maybe-incorrect",
+    style = "verbose"
+)]
+pub struct UseIsEmpty {
+    #[suggestion_part(code = "!")]
+    pub lo: Span,
+    #[suggestion_part(code = ".is_empty()")]
+    pub hi: Span,
+    pub expr_ty: String,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_arg_mismatch_indeterminate)]
 pub struct ArgMismatchIndeterminate {
@@ -396,6 +533,15 @@ pub struct SuggestPtrNullMut {
     pub span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_trivial_cast)]
+#[help]
+pub struct TrivialCast<'tcx> {
+    pub numeric: bool,
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_no_associated_item, code = "E0599")]
 pub struct NoAssociatedItem {
@@ -419,6 +565,74 @@ pub struct CandidateTraitNote {
 }
 
 #[derive(Diagnostic)]
+#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")]
+pub struct CannotCastToBool<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub expr_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub help: CannotCastToBoolHelp,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_cast_enum_drop)]
+pub struct CastEnumDrop<'tcx> {
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")]
+pub struct CastUnknownPointer {
+    #[primary_span]
+    pub span: Span,
+    pub to: bool,
+    #[subdiagnostic]
+    pub sub: CastUnknownPointerSub,
+}
+
+pub enum CastUnknownPointerSub {
+    To(Span),
+    From(Span),
+}
+
+impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
+    where
+        F: Fn(
+            &mut Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        match self {
+            CastUnknownPointerSub::To(span) => {
+                let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into());
+                diag.span_label(span, msg);
+                let msg = f(diag, crate::fluent_generated::hir_typeck_note.into());
+                diag.note(msg);
+            }
+            CastUnknownPointerSub::From(span) => {
+                let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into());
+                diag.span_label(span, msg);
+            }
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub enum CannotCastToBoolHelp {
+    #[suggestion(
+        hir_typeck_suggestion,
+        applicability = "machine-applicable",
+        code = " != 0",
+        style = "verbose"
+    )]
+    Numeric(#[primary_span] Span),
+    #[label(hir_typeck_label)]
+    Unsupported(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
 #[diag(hir_typeck_ctor_is_private, code = "E0603")]
 pub struct CtorIsPrivate {
     #[primary_span]
@@ -427,6 +641,14 @@ pub struct CtorIsPrivate {
 }
 
 #[derive(Subdiagnostic)]
+#[note(hir_typeck_deref_is_empty)]
+pub struct DerefImplsIsEmpty {
+    #[primary_span]
+    pub span: Span,
+    pub deref_ty: String,
+}
+
+#[derive(Subdiagnostic)]
 #[multipart_suggestion(
     hir_typeck_convert_using_method,
     applicability = "machine-applicable",
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 1a41786d251..ba469bd029d 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -195,7 +195,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
         let mut delegate = InferBorrowKind {
-            fcx: self,
             closure_def_id,
             capture_information: Default::default(),
             fake_reads: Default::default(),
@@ -1607,34 +1606,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 /// Truncate the capture so that the place being borrowed is in accordance with RFC 1240,
 /// which states that it's unsafe to take a reference into a struct marked `repr(packed)`.
 fn restrict_repr_packed_field_ref_capture<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     mut place: Place<'tcx>,
     mut curr_borrow_kind: ty::UpvarCapture,
 ) -> (Place<'tcx>, ty::UpvarCapture) {
     let pos = place.projections.iter().enumerate().position(|(i, p)| {
         let ty = place.ty_before_projection(i);
 
-        // Return true for fields of packed structs, unless those fields have alignment 1.
+        // Return true for fields of packed structs.
         match p.kind {
             ProjectionKind::Field(..) => match ty.kind() {
                 ty::Adt(def, _) if def.repr().packed() => {
-                    // We erase regions here because they cannot be hashed
-                    match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
-                        Ok(layout) if layout.align.abi.bytes() == 1 => {
-                            // if the alignment is 1, the type can't be further
-                            // disaligned.
-                            debug!(
-                                "restrict_repr_packed_field_ref_capture: ({:?}) - align = 1",
-                                place
-                            );
-                            false
-                        }
-                        _ => {
-                            debug!("restrict_repr_packed_field_ref_capture: ({:?}) - true", place);
-                            true
-                        }
-                    }
+                    // We stop here regardless of field alignment. Field alignment can change as
+                    // types change, including the types of private fields in other crates, and that
+                    // shouldn't affect how we compute our captures.
+                    true
                 }
 
                 _ => false,
@@ -1689,9 +1674,7 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> Span {
     tcx.sess.source_map().end_point(owner_span)
 }
 
-struct InferBorrowKind<'a, 'tcx> {
-    fcx: &'a FnCtxt<'a, 'tcx>,
-
+struct InferBorrowKind<'tcx> {
     // The def-id of the closure whose kind and upvar accesses are being inferred.
     closure_def_id: LocalDefId,
 
@@ -1725,7 +1708,7 @@ struct InferBorrowKind<'a, 'tcx> {
     fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
 }
 
-impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
+impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
     fn fake_read(
         &mut self,
         place: &PlaceWithHirId<'tcx>,
@@ -1740,12 +1723,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
 
         let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind);
 
-        let (place, _) = restrict_repr_packed_field_ref_capture(
-            self.fcx.tcx,
-            self.fcx.param_env,
-            place,
-            dummy_capture_kind,
-        );
+        let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
         self.fake_reads.push((place, cause, diag_expr_id));
     }
 
@@ -1780,12 +1758,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
         // We only want repr packed restriction to be applied to reading references into a packed
         // struct, and not when the data is being moved. Therefore we call this method here instead
         // of in `restrict_capture_precision`.
-        let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
-            self.fcx.tcx,
-            self.fcx.param_env,
-            place_with_id.place.clone(),
-            capture_kind,
-        );
+        let (place, mut capture_kind) =
+            restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind);
 
         // Raw pointers don't inherit mutability
         if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index f903f7a49ef..4aec28b051f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -385,7 +385,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
 
         let highlight_trait_ref = |trait_ref| Highlighted {
             tcx: self.tcx(),
-            highlight: RegionHighlightMode::new(self.tcx()),
+            highlight: RegionHighlightMode::default(),
             value: trait_ref,
         };
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 12d38ced030..d2ba9966f03 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -67,9 +67,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
 
         impl<'tcx> HighlightBuilder<'tcx> {
-            fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
+            fn build(ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
                 let mut builder =
-                    HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
+                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
                 builder.visit_ty(ty);
                 builder.highlight
             }
@@ -85,12 +85,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
         }
 
-        let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+        let expected_highlight = HighlightBuilder::build(expected);
         let expected = self
             .cx
             .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
             .name;
-        let found_highlight = HighlightBuilder::build(self.tcx(), found);
+        let found_highlight = HighlightBuilder::build(found);
         let found =
             self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
 
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 2402a7ea7c7..ed1a2a11719 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -4,7 +4,7 @@
 //! and use that to decide when one free region outlives another, and so forth.
 
 use rustc_data_structures::transitive_relation::TransitiveRelation;
-use rustc_middle::ty::{Lift, Region, TyCtxt};
+use rustc_middle::ty::{Region, TyCtxt};
 
 /// Combines a `FreeRegionMap` and a `TyCtxt`.
 ///
@@ -101,10 +101,3 @@ impl<'tcx> FreeRegionMap<'tcx> {
         result
     }
 }
-
-impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
-    type Lifted = FreeRegionMap<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
-        self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3706c9646af..4cf9d44ed65 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1600,9 +1600,12 @@ impl<'tcx> InferCtxt<'tcx> {
             if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
                 let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
                 if let Err(e) = ct.error_reported() {
-                    return Err(ErrorHandled::Reported(e.into()));
+                    return Err(ErrorHandled::Reported(
+                        e.into(),
+                        span.unwrap_or(rustc_span::DUMMY_SP),
+                    ));
                 } else if ct.has_non_region_infer() || ct.has_non_region_param() {
-                    return Err(ErrorHandled::TooGeneric);
+                    return Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP)));
                 } else {
                     args = replace_param_and_infer_args_with_placeholder(tcx, args);
                 }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 37e242c6e40..0634e44c562 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -568,6 +568,13 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
     ) {
         sess.emit_fatal(errors::MultipleOutputTypesToStdout);
     }
+
+    let crate_name = sess
+        .opts
+        .crate_name
+        .clone()
+        .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()));
+
     match sess.io.output_file {
         None => {
             // "-" as input file will cause the parser to read from stdin so we
@@ -576,15 +583,11 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
             let dirpath = sess.io.output_dir.clone().unwrap_or_default();
 
             // If a crate name is present, we use it as the link name
-            let stem = sess
-                .opts
-                .crate_name
-                .clone()
-                .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
-                .unwrap_or_else(|| sess.io.input.filestem().to_owned());
+            let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned());
 
             OutputFilenames::new(
                 dirpath,
+                crate_name.unwrap_or_else(|| stem.replace('-', "_")),
                 stem,
                 None,
                 sess.io.temps_dir.clone(),
@@ -609,9 +612,12 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
                 sess.emit_warning(errors::IgnoringOutDir);
             }
 
+            let out_filestem =
+                out_file.filestem().unwrap_or_default().to_str().unwrap().to_string();
             OutputFilenames::new(
                 out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
-                out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(),
+                crate_name.unwrap_or_else(|| out_filestem.replace('-', "_")),
+                out_filestem,
                 ofile,
                 sess.io.temps_dir.clone(),
                 sess.opts.cg.extra_filename.clone(),
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index ba50c9e00e3..7377c6e2f35 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -453,6 +453,8 @@ lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking th
     .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
     .label = expression has type `{$orig_ty}`
 
+lint_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false
+
 lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
     .label = expression has type `{$orig_ty}`
 
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 3e26d6dc32d..c091c260a47 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -635,6 +635,8 @@ pub enum PtrNullChecksDiag<'a> {
         #[label]
         label: Span,
     },
+    #[diag(lint_ptr_null_checks_fn_ret)]
+    FnRet { fn_name: Ident },
 }
 
 // for_loops_over_fallibles.rs
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 02aff91032f..0de72d8d3db 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -31,12 +31,30 @@ declare_lint! {
 
 declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
 
-/// This function detects and returns the original expression from a series of consecutive casts,
-/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
-fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
+/// This function checks if the expression is from a series of consecutive casts,
+/// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either
+/// a fn ptr, a reference, or a function call whose definition is
+/// annotated with `#![rustc_never_returns_null_ptr]`.
+/// If this situation is present, the function returns the appropriate diagnostic.
+fn incorrect_check<'a, 'tcx: 'a>(
+    cx: &'a LateContext<'tcx>,
+    mut e: &'a Expr<'a>,
+) -> Option<PtrNullChecksDiag<'tcx>> {
     let mut had_at_least_one_cast = false;
     loop {
         e = e.peel_blocks();
+        if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
+            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+            && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
+            && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
+            return Some(PtrNullChecksDiag::FnRet { fn_name });
+        } else if let ExprKind::Call(path, _args) = e.kind
+            && let ExprKind::Path(ref qpath) = path.kind
+            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+            && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
+            && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
+            return Some(PtrNullChecksDiag::FnRet { fn_name });
+        }
         e = if let ExprKind::Cast(expr, t) = e.kind
             && let TyKind::Ptr(_) = t.kind {
             had_at_least_one_cast = true;
@@ -46,33 +64,21 @@ fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'
             && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
             had_at_least_one_cast = true;
             expr
-        } else if let ExprKind::Call(path, [arg]) = e.kind
-            && let ExprKind::Path(ref qpath) = path.kind
-            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
-            && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) {
-            had_at_least_one_cast = true;
-            arg
         } else if had_at_least_one_cast {
-            return Some(e);
+            let orig_ty = cx.typeck_results().expr_ty(e);
+            return if orig_ty.is_fn() {
+                Some(PtrNullChecksDiag::FnPtr { orig_ty, label: e.span })
+            } else if orig_ty.is_ref() {
+                Some(PtrNullChecksDiag::Ref { orig_ty, label: e.span })
+            } else {
+                None
+            };
         } else {
             return None;
         };
     }
 }
 
-fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
-    let expr = ptr_cast_chain(cx, expr)?;
-
-    let orig_ty = cx.typeck_results().expr_ty(expr);
-    if orig_ty.is_fn() {
-        Some(PtrNullChecksDiag::FnPtr { orig_ty, label: expr.span })
-    } else if orig_ty.is_ref() {
-        Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
-    } else {
-        None
-    }
-}
-
 impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         match expr.kind {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 672a7a20148..860366fdd61 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3405,8 +3405,8 @@ declare_lint_pass! {
         UNFULFILLED_LINT_EXPECTATIONS,
         UNINHABITED_STATIC,
         UNKNOWN_CRATE_TYPES,
-        UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
         UNKNOWN_LINTS,
+        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
         UNNAMEABLE_TEST_ITEMS,
         UNNAMEABLE_TYPES,
         UNREACHABLE_CODE,
@@ -4420,7 +4420,8 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes.
+    /// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed
+    /// diagnostic attributes.
     ///
     /// ### Example
     ///
@@ -4432,15 +4433,17 @@ declare_lint! {
     ///
     /// {{produces}}
     ///
+    ///
     /// ### Explanation
     ///
     /// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
     /// the spelling, and check the diagnostic attribute listing for the correct name. Also
     /// consider if you are using an old version of the compiler, and the attribute
     /// is only available in a newer version.
-    pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+    pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
     Warn,
-    "unrecognized diagnostic attribute"
+    "unrecognized or malformed diagnostic attribute",
+    @feature_gate = sym::diagnostic_namespace;
 }
 
 declare_lint! {
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index fefb1e0fbe0..461b5290e69 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -239,16 +239,22 @@ enum class LLVMRustCodeGenOptLevel {
   Aggressive,
 };
 
-static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) {
+#if LLVM_VERSION_GE(18, 0)
+  using CodeGenOptLevelEnum = llvm::CodeGenOptLevel;
+#else
+  using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level;
+#endif
+
+static CodeGenOptLevelEnum fromRust(LLVMRustCodeGenOptLevel Level) {
   switch (Level) {
   case LLVMRustCodeGenOptLevel::None:
-    return CodeGenOpt::None;
+    return CodeGenOptLevelEnum::None;
   case LLVMRustCodeGenOptLevel::Less:
-    return CodeGenOpt::Less;
+    return CodeGenOptLevelEnum::Less;
   case LLVMRustCodeGenOptLevel::Default:
-    return CodeGenOpt::Default;
+    return CodeGenOptLevelEnum::Default;
   case LLVMRustCodeGenOptLevel::Aggressive:
-    return CodeGenOpt::Aggressive;
+    return CodeGenOptLevelEnum::Aggressive;
   default:
     report_fatal_error("Bad CodeGenOptLevel.");
   }
@@ -554,9 +560,17 @@ enum class LLVMRustFileType {
 static CodeGenFileType fromRust(LLVMRustFileType Type) {
   switch (Type) {
   case LLVMRustFileType::AssemblyFile:
+#if LLVM_VERSION_GE(18, 0)
+    return CodeGenFileType::AssemblyFile;
+#else
     return CGFT_AssemblyFile;
+#endif
   case LLVMRustFileType::ObjectFile:
+#if LLVM_VERSION_GE(18, 0)
+    return CodeGenFileType::ObjectFile;
+#else
     return CGFT_ObjectFile;
+#endif
   default:
     report_fatal_error("Bad FileType.");
   }
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs
index 2a9662b809a..7eb2a347db2 100644
--- a/compiler/rustc_metadata/src/fs.rs
+++ b/compiler/rustc_metadata/src/fs.rs
@@ -5,7 +5,6 @@ use crate::errors::{
 use crate::{encode_metadata, EncodedMetadata};
 
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OutFileName, OutputType};
 use rustc_session::output::filename_for_metadata;
@@ -40,8 +39,7 @@ pub fn emit_wrapper_file(
 }
 
 pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
-    let crate_name = tcx.crate_name(LOCAL_CRATE);
-    let out_filename = filename_for_metadata(tcx.sess, crate_name, tcx.output_filenames(()));
+    let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(()));
     // To avoid races with another rustc process scanning the output directory,
     // we need to write the file somewhere else and atomically move it to its
     // final destination, with an `fs::rename` call. In order for the rename to
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 108a10b506b..82162fd8571 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -52,6 +52,8 @@ middle_drop_check_overflow =
     overflow while adding drop-check rules for {$ty}
     .note = overflowed on {$overflow_ty}
 
+middle_erroneous_constant = erroneous constant encountered
+
 middle_layout_references_error =
     the type has an unknown layout
 
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index b346cd45391..3c553657087 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi {
     pub abi: &'static str,
 }
 
+#[derive(Diagnostic)]
+#[diag(middle_erroneous_constant)]
+pub struct ErroneousConstant {
+    #[primary_span]
+    pub span: Span,
+}
+
 /// Used by `rustc_const_eval`
 pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index b17f1512886..2f2597d6b22 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -34,7 +34,7 @@ use std::ops::Index;
 /// variables have been rewritten to "canonical vars". These are
 /// numbered starting from 0 in order of first appearance.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct Canonical<'tcx, V> {
     pub value: V,
     pub max_universe: ty::UniverseIndex,
@@ -72,7 +72,7 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
 /// variables. You will need to supply it later to instantiate the
 /// canonicalized query response.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct CanonicalVarValues<'tcx> {
     pub var_values: ty::GenericArgsRef<'tcx>,
 }
@@ -311,7 +311,7 @@ pub enum CanonicalTyVarKind {
 /// After we execute a query with a canonicalized key, we get back a
 /// `Canonical<QueryResponse<..>>`. You can use
 /// `instantiate_query_result` to access the data in this result.
-#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct QueryResponse<'tcx, R> {
     pub var_values: CanonicalVarValues<'tcx>,
     pub region_constraints: QueryRegionConstraints<'tcx>,
@@ -326,7 +326,7 @@ pub struct QueryResponse<'tcx, R> {
 }
 
 #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct QueryRegionConstraints<'tcx> {
     pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
     pub member_constraints: Vec<MemberConstraint<'tcx>>,
@@ -432,7 +432,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
 pub type QueryOutlivesConstraint<'tcx> =
     (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
 
-TrivialTypeTraversalAndLiftImpls! {
+TrivialTypeTraversalImpls! {
     crate::infer::canonical::Certainty,
     crate::infer::canonical::CanonicalTyVarKind,
 }
diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs
index 493bb8a6823..1384611e146 100644
--- a/compiler/rustc_middle/src/infer/mod.rs
+++ b/compiler/rustc_middle/src/infer/mod.rs
@@ -13,7 +13,7 @@ use rustc_span::Span;
 /// R0 member of [O1..On]
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct MemberConstraint<'tcx> {
     /// The `DefId` and args of the opaque type causing this constraint.
     /// Used for error reporting.
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index fca16d8e509..c1884bb8068 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -42,7 +42,7 @@ macro_rules! span_bug {
 // the impls for you.
 
 #[macro_export]
-macro_rules! CloneLiftImpls {
+macro_rules! TrivialLiftImpls {
     ($($ty:ty),+ $(,)?) => {
         $(
             impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
@@ -96,6 +96,6 @@ macro_rules! TrivialTypeTraversalImpls {
 macro_rules! TrivialTypeTraversalAndLiftImpls {
     ($($t:tt)*) => {
         TrivialTypeTraversalImpls! { $($t)* }
-        CloneLiftImpls! { $($t)* }
+        TrivialLiftImpls! { $($t)* }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 70d8f3bd54b..cd770c395e4 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -178,7 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! { Cache }
+TrivialTypeTraversalImpls! { Cache }
 
 impl<S: Encoder> Encodable<S> for Cache {
     #[inline]
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 7e3be0b5d5f..eb4614745d5 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,8 +1,9 @@
 use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
 
+use crate::error;
 use crate::mir::interpret::ConstValue;
 use crate::query::TyCtxtAt;
-use crate::ty::{layout, tls, Ty, ValTree};
+use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
 
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{
@@ -11,7 +12,7 @@ use rustc_errors::{
 };
 use rustc_macros::HashStable;
 use rustc_session::CtfeBacktrace;
-use rustc_span::def_id::DefId;
+use rustc_span::{def_id::DefId, Span, DUMMY_SP};
 use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
 
 use std::borrow::Cow;
@@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt};
 pub enum ErrorHandled {
     /// Already reported an error for this evaluation, and the compilation is
     /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
-    Reported(ReportedErrorInfo),
+    Reported(ReportedErrorInfo, Span),
     /// Don't emit an error, the evaluation failed because the MIR was generic
     /// and the args didn't fully monomorphize it.
-    TooGeneric,
+    TooGeneric(Span),
 }
 
 impl From<ErrorGuaranteed> for ErrorHandled {
     #[inline]
     fn from(error: ErrorGuaranteed) -> ErrorHandled {
-        ErrorHandled::Reported(error.into())
+        ErrorHandled::Reported(error.into(), DUMMY_SP)
+    }
+}
+
+impl ErrorHandled {
+    pub fn with_span(self, span: Span) -> Self {
+        match self {
+            ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
+            ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
+        }
+    }
+
+    pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed {
+        match self {
+            &ErrorHandled::Reported(err, span) => {
+                if !err.is_tainted_by_errors && !span.is_dummy() {
+                    tcx.sess.emit_err(error::ErroneousConstant { span });
+                }
+                err.error
+            }
+            &ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug(
+                span,
+                "encountered TooGeneric error when monomorphic data was expected",
+            ),
+        }
+    }
+
+    pub fn emit_note(&self, tcx: TyCtxt<'_>) {
+        match self {
+            &ErrorHandled::Reported(err, span) => {
+                if !err.is_tainted_by_errors && !span.is_dummy() {
+                    tcx.sess.emit_note(error::ErroneousConstant { span });
+                }
+            }
+            &ErrorHandled::TooGeneric(_) => {}
+        }
     }
 }
 
@@ -45,12 +81,6 @@ impl ReportedErrorInfo {
     pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
         ReportedErrorInfo { is_tainted_by_errors: true, error }
     }
-
-    /// Returns true if evaluation failed because MIR was tainted by errors.
-    #[inline]
-    pub fn is_tainted_by_errors(self) -> bool {
-        self.is_tainted_by_errors
-    }
 }
 
 impl From<ErrorGuaranteed> for ReportedErrorInfo {
@@ -67,7 +97,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
+TrivialTypeTraversalImpls! { ErrorHandled }
 
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
@@ -162,6 +192,16 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
     }
 }
 
+impl From<ErrorHandled> for InterpErrorInfo<'_> {
+    fn from(err: ErrorHandled) -> Self {
+        InterpError::InvalidProgram(match err {
+            ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
+            ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
+        })
+        .into()
+    }
+}
+
 impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
     fn from(kind: InterpError<'tcx>) -> Self {
         InterpErrorInfo(Box::new(InterpErrorInfoInner {
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 44d1dcbbe17..8c00746a180 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
 /// - A constant
 /// - A static
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct GlobalId<'tcx> {
     /// For a constant or static, the `Instance` of the item itself.
     /// For a promoted global, the `Instance` of the function they belong to.
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index fc659ce18a4..fbf6403eabe 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -61,8 +61,10 @@ impl<'tcx> TyCtxt<'tcx> {
                 let cid = GlobalId { instance, promoted: ct.promoted };
                 self.const_eval_global_id(param_env, cid, span)
             }
-            Ok(None) => Err(ErrorHandled::TooGeneric),
-            Err(err) => Err(ErrorHandled::Reported(err.into())),
+            // For errors during resolution, we deliberately do not point at the usage site of the constant,
+            // since for these errors the place the constant is used shouldn't matter.
+            Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
+            Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
         }
     }
 
@@ -117,8 +119,10 @@ impl<'tcx> TyCtxt<'tcx> {
                     }
                 })
             }
-            Ok(None) => Err(ErrorHandled::TooGeneric),
-            Err(err) => Err(ErrorHandled::Reported(err.into())),
+            // For errors during resolution, we deliberately do not point at the usage site of the constant,
+            // since for these errors the place the constant is used shouldn't matter.
+            Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
+            Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
         }
     }
 
@@ -143,7 +147,8 @@ impl<'tcx> TyCtxt<'tcx> {
         // improve caching of queries.
         let inputs = self.erase_regions(param_env.and(cid));
         if let Some(span) = span {
-            self.at(span).eval_to_const_value_raw(inputs)
+            // The query doesn't know where it is being invoked, so we need to fix the span.
+            self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
         } else {
             self.eval_to_const_value_raw(inputs)
         }
@@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
         let inputs = self.erase_regions(param_env.and(cid));
         debug!(?inputs);
         if let Some(span) = span {
-            self.at(span).eval_to_valtree(inputs)
+            // The query doesn't know where it is being invoked, so we need to fix the span.
+            self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
         } else {
             self.eval_to_valtree(inputs)
         }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 8df3a79b4d4..b8032733868 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -565,6 +565,34 @@ impl<'tcx> Body<'tcx> {
     pub fn is_custom_mir(&self) -> bool {
         self.injection_phase.is_some()
     }
+
+    /// *Must* be called once the full substitution for this body is known, to ensure that the body
+    /// is indeed fit for code generation or consumption more generally.
+    ///
+    /// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
+    /// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
+    /// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
+    /// functions makes it seem like exposing the generic args is not the intended strategy.)
+    ///
+    /// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
+    /// so we cannot just immediately ICE on TooGeneric.
+    ///
+    /// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
+    pub fn post_mono_checks(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
+    ) -> Result<(), ErrorHandled> {
+        // For now, the only thing we have to check is is to ensure that all the constants used in
+        // the body successfully evaluate.
+        for &const_ in &self.required_consts {
+            let c = normalize_const(const_.literal)?;
+            c.eval(tcx, param_env, Some(const_.span))?;
+        }
+
+        Ok(())
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -744,7 +772,7 @@ pub enum BindingForm<'tcx> {
     RefForGuard,
 }
 
-TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
+TrivialTypeTraversalImpls! { BindingForm<'tcx> }
 
 mod binding_form_impl {
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -2295,7 +2323,7 @@ pub struct Constant<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
-#[derive(Lift, TypeFoldable, TypeVisitable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum ConstantKind<'tcx> {
     /// This constant came from the type system.
     ///
@@ -2397,10 +2425,10 @@ impl<'tcx> ConstantKind<'tcx> {
     pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
         match self.eval(tcx, param_env, None) {
             Ok(val) => Self::Val(val, self.ty()),
-            Err(ErrorHandled::Reported(guar)) => {
+            Err(ErrorHandled::Reported(guar, _span)) => {
                 Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
             }
-            Err(ErrorHandled::TooGeneric) => self,
+            Err(ErrorHandled::TooGeneric(_span)) => self,
         }
     }
 
@@ -2615,7 +2643,7 @@ impl<'tcx> ConstantKind<'tcx> {
 }
 
 /// An unevaluated (potentially generic) constant used in MIR.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: DefId,
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 71bec49af93..0c80610b308 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -334,7 +334,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 ///
 /// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
 pub enum ConstraintCategory<'tcx> {
     Return(ReturnConstraint),
     Yield,
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 06874741bb0..8d427fdb6f5 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -5,7 +5,7 @@ use rustc_ast::InlineAsmTemplatePiece;
 use super::*;
 use crate::ty;
 
-TrivialTypeTraversalAndLiftImpls! {
+TrivialTypeTraversalImpls! {
     BlockTailInfo,
     MirPhase,
     SourceInfo,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index bf340846f10..9e358ea4eba 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1140,6 +1140,7 @@ rustc_queries! {
     query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
         arena_cache
         desc { "reachability" }
+        cache_on_disk_if { true }
     }
 
     /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 3465759b913..1340e674568 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -13,7 +13,7 @@ use crate::infer::canonical::Canonical;
 use crate::mir::ConstraintCategory;
 use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::GenericArgsRef;
-use crate::ty::{self, AdtKind, Ty, TyCtxt};
+use crate::ty::{self, AdtKind, Ty};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
@@ -86,7 +86,7 @@ pub enum Reveal {
 ///
 /// We do not want to intern this as there are a lot of obligation causes which
 /// only live for a short period of time.
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
 pub struct ObligationCause<'tcx> {
     pub span: Span,
@@ -194,7 +194,7 @@ impl<'tcx> ObligationCause<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
 pub struct UnifyReceiverContext<'tcx> {
     pub assoc_item: ty::AssocItem,
@@ -202,7 +202,7 @@ pub struct UnifyReceiverContext<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
 
-#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)]
+#[derive(Clone, PartialEq, Eq, Default, HashStable)]
 #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
 pub struct InternedObligationCauseCode<'tcx> {
     /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
@@ -238,7 +238,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from the span.
@@ -470,7 +470,7 @@ pub enum WellFormedLoc {
     },
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
 pub struct ImplDerivedObligationCause<'tcx> {
     pub derived: DerivedObligationCause<'tcx>,
@@ -524,14 +524,7 @@ pub enum StatementAsExpression {
     NeedsBoxing,
 }
 
-impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
-    type Lifted = StatementAsExpression;
-    fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
-        Some(self)
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
 pub struct MatchExpressionArmCause<'tcx> {
     pub arm_block_id: Option<hir::HirId>,
@@ -547,7 +540,7 @@ pub struct MatchExpressionArmCause<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
 pub struct IfExpressionCause<'tcx> {
     pub then_id: hir::HirId,
     pub else_id: hir::HirId,
@@ -557,7 +550,7 @@ pub struct IfExpressionCause<'tcx> {
     pub opt_suggest_box_span: Option<Span>,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
 pub struct DerivedObligationCause<'tcx> {
     /// The trait predicate of the parent obligation that led to the
@@ -570,7 +563,7 @@ pub struct DerivedObligationCause<'tcx> {
     pub parent_code: InternedObligationCauseCode<'tcx>,
 }
 
-#[derive(Clone, Debug, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TypeVisitable)]
 pub enum SelectionError<'tcx> {
     /// The trait is not implemented.
     Unimplemented,
@@ -593,7 +586,7 @@ pub enum SelectionError<'tcx> {
     OpaqueTypeAutoTraitLeakageUnknown(DefId),
 }
 
-#[derive(Clone, Debug, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TypeVisitable)]
 pub struct SelectionOutputTypeParameterMismatch<'tcx> {
     pub found_trait_ref: ty::PolyTraitRef<'tcx>,
     pub expected_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -638,7 +631,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 /// ### The type parameter `N`
 ///
 /// See explanation on `ImplSourceUserDefinedData`.
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum ImplSource<'tcx, N> {
     /// ImplSource identifying a particular impl.
@@ -704,7 +697,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
 /// is `Obligation`, as one might expect. During codegen, however, this
 /// is `()`, because codegen only requires a shallow resolution of an
 /// impl, and nested obligations are satisfied later.
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceUserDefinedData<'tcx, N> {
     pub impl_def_id: DefId,
@@ -736,7 +729,7 @@ pub enum BuiltinImplSource {
     TupleUnsizing,
 }
 
-TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
+TrivialTypeTraversalImpls! { BuiltinImplSource }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
 pub enum ObjectSafetyViolation {
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 950a59e9695..975e3e3ac62 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -17,8 +17,7 @@ pub mod type_op {
     use crate::ty::{Predicate, Ty, TyCtxt, UserType};
     use std::fmt;
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
-    #[derive(TypeFoldable, TypeVisitable)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct AscribeUserType<'tcx> {
         pub mir_ty: Ty<'tcx>,
         pub user_ty: UserType<'tcx>,
@@ -30,22 +29,19 @@ pub mod type_op {
         }
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
-    #[derive(TypeFoldable, TypeVisitable)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct Eq<'tcx> {
         pub a: Ty<'tcx>,
         pub b: Ty<'tcx>,
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
-    #[derive(TypeFoldable, TypeVisitable)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct Subtype<'tcx> {
         pub sub: Ty<'tcx>,
         pub sup: Ty<'tcx>,
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
-    #[derive(TypeFoldable, TypeVisitable)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct ProvePredicate<'tcx> {
         pub predicate: Predicate<'tcx>,
     }
@@ -56,8 +52,7 @@ pub mod type_op {
         }
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
-    #[derive(TypeFoldable, TypeVisitable)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct Normalize<T> {
         pub value: T,
     }
@@ -101,7 +96,7 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution {
     }
 }
 
-#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)]
 pub struct DropckOutlivesResult<'tcx> {
     pub kinds: Vec<GenericArg<'tcx>>,
     pub overflows: Vec<Ty<'tcx>>,
@@ -194,7 +189,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
 }
 
 /// Result from the `normalize_projection_ty` query.
-#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct NormalizationResult<'tcx> {
     /// Result of normalization.
     pub normalized_ty: Ty<'tcx>,
@@ -207,7 +202,7 @@ pub struct NormalizationResult<'tcx> {
 /// case they are called implied bounds). They are fed to the
 /// `OutlivesEnv` which in turn is supplied to the region checker and
 /// other parts of the inference system.
-#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift, HashStable)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
 pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index ffae3579889..90bc5dd8f69 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -305,7 +305,7 @@ impl From<ErrorGuaranteed> for OverflowError {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! { OverflowError }
+TrivialTypeTraversalImpls! { OverflowError }
 
 impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
     fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index d8b3a061b77..c3ed40867cf 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -15,9 +15,15 @@ pub enum CacheHit {
 }
 
 #[derive(Eq, PartialEq)]
+pub enum GoalEvaluationKind {
+    Root,
+    Nested { is_normalizes_to_hack: IsNormalizesToHack },
+}
+
+#[derive(Eq, PartialEq)]
 pub struct GoalEvaluation<'tcx> {
     pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub is_normalizes_to_hack: IsNormalizesToHack,
+    pub kind: GoalEvaluationKind,
     pub evaluation: CanonicalGoalEvaluation<'tcx>,
     pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
 }
@@ -25,12 +31,12 @@ pub struct GoalEvaluation<'tcx> {
 #[derive(Eq, PartialEq)]
 pub struct CanonicalGoalEvaluation<'tcx> {
     pub goal: CanonicalInput<'tcx>,
-    pub kind: GoalEvaluationKind<'tcx>,
+    pub kind: CanonicalGoalEvaluationKind<'tcx>,
     pub result: QueryResult<'tcx>,
 }
 
 #[derive(Eq, PartialEq)]
-pub enum GoalEvaluationKind<'tcx> {
+pub enum CanonicalGoalEvaluationKind<'tcx> {
     Overflow,
     CacheHit(CacheHit),
     Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
@@ -52,22 +58,31 @@ pub struct GoalEvaluationStep<'tcx> {
     pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
 
     /// The actual evaluation of the goal, always `ProbeKind::Root`.
-    pub evaluation: GoalCandidate<'tcx>,
+    pub evaluation: Probe<'tcx>,
 }
 
+/// A self-contained computation during trait solving. This either
+/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
+/// of a goal.
 #[derive(Eq, PartialEq)]
-pub struct GoalCandidate<'tcx> {
-    pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
-    pub candidates: Vec<GoalCandidate<'tcx>>,
+pub struct Probe<'tcx> {
+    pub steps: Vec<ProbeStep<'tcx>>,
     pub kind: ProbeKind<'tcx>,
 }
 
-impl Debug for GoalCandidate<'_> {
+impl Debug for Probe<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        ProofTreeFormatter::new(f).format_candidate(self)
+        ProofTreeFormatter::new(f).format_probe(self)
     }
 }
 
+#[derive(Eq, PartialEq)]
+pub enum ProbeStep<'tcx> {
+    AddGoal(Goal<'tcx, ty::Predicate<'tcx>>),
+    EvaluateGoals(AddedGoalsEvaluation<'tcx>),
+    NestedProbe(Probe<'tcx>),
+}
+
 #[derive(Debug, PartialEq, Eq)]
 pub enum ProbeKind<'tcx> {
     /// The root inference context while proving a goal.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index d916e80a625..d33e83ae1ed 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -40,9 +40,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
     }
 
     pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
-        let goal_text = match eval.is_normalizes_to_hack {
-            IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
-            IsNormalizesToHack::No => "GOAL",
+        let goal_text = match eval.kind {
+            GoalEvaluationKind::Root => "ROOT GOAL",
+            GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack {
+                IsNormalizesToHack::No => "GOAL",
+                IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
+            },
         };
         writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
         self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
@@ -68,16 +71,16 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         writeln!(self.f, "GOAL: {:?}", eval.goal)?;
 
         match &eval.kind {
-            GoalEvaluationKind::Overflow => {
+            CanonicalGoalEvaluationKind::Overflow => {
                 writeln!(self.f, "OVERFLOW: {:?}", eval.result)
             }
-            GoalEvaluationKind::CacheHit(CacheHit::Global) => {
+            CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => {
                 writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
             }
-            GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
+            CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
                 writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
             }
-            GoalEvaluationKind::Uncached { revisions } => {
+            CanonicalGoalEvaluationKind::Uncached { revisions } => {
                 for (n, step) in revisions.iter().enumerate() {
                     writeln!(self.f, "REVISION {n}")?;
                     self.nested(|this| this.format_evaluation_step(step))?;
@@ -92,11 +95,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         evaluation_step: &GoalEvaluationStep<'_>,
     ) -> std::fmt::Result {
         writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
-        self.format_candidate(&evaluation_step.evaluation)
+        self.format_probe(&evaluation_step.evaluation)
     }
 
-    pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
-        match &candidate.kind {
+    pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
+        match &probe.kind {
             ProbeKind::Root { result } => {
                 writeln!(self.f, "ROOT RESULT: {result:?}")
             }
@@ -118,11 +121,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         }?;
 
         self.nested(|this| {
-            for candidate in &candidate.candidates {
-                this.format_candidate(candidate)?;
-            }
-            for nested in &candidate.added_goals_evaluations {
-                this.format_added_goals_evaluation(nested)?;
+            for step in &probe.steps {
+                match step {
+                    ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
+                    ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
+                    ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
+                }
             }
             Ok(())
         })
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index cdd8351499b..570f896ba29 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -27,7 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
     }
 }
 
-TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
+TrivialTypeTraversalImpls! { NotConstEvaluatable }
 
 pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
 
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 76931ceaa69..c3e8991c63a 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -76,7 +76,7 @@ pub enum PointerCoercion {
 ///    At some point, of course, `Box` should move out of the compiler, in which
 ///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
 ///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
     pub target: Ty<'tcx>,
@@ -88,7 +88,7 @@ impl<'tcx> Adjustment<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum Adjust<'tcx> {
     /// Go from ! to any type.
     NeverToAny,
@@ -110,7 +110,7 @@ pub enum Adjust<'tcx> {
 /// The target type is `U` in both cases, with the region and mutability
 /// being those shared by both the receiver and the returned reference.
 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct OverloadedDeref<'tcx> {
     pub region: ty::Region<'tcx>,
     pub mutbl: hir::Mutability,
@@ -182,7 +182,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
 }
 
 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum AutoBorrow<'tcx> {
     /// Converts from T to &T.
     Ref(ty::Region<'tcx>, AutoBorrowMutability),
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index b4c6e0d970a..219927f5ab4 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
             }
             Err(err) => {
                 let msg = match err {
-                    ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
-                    ErrorHandled::TooGeneric => "enum discriminant depends on generics",
+                    ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
+                    ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
                 };
                 tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
                 None
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
index 2fec8ac9095..af594bc5f24 100644
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -6,7 +6,7 @@ pub enum BindingMode {
     BindByValue(Mutability),
 }
 
-TrivialTypeTraversalAndLiftImpls! { BindingMode }
+TrivialTypeTraversalImpls! { BindingMode }
 
 impl BindingMode {
     pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 629f9f8cd7d..ba871d6478b 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> {
             | ConstKind::Infer(_)
             | ConstKind::Bound(_, _)
             | ConstKind::Placeholder(_)
-            | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
+            | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
         }
     }
 
@@ -309,8 +309,8 @@ impl<'tcx> Const<'tcx> {
     pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
         match self.eval(tcx, param_env, None) {
             Ok(val) => Self::new_value(tcx, val, self.ty()),
-            Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
-            Err(ErrorHandled::TooGeneric) => self,
+            Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
+            Err(ErrorHandled::TooGeneric(_span)) => self,
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index e25402fe0c2..749b54ca0be 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 
 /// An unevaluated (potentially generic) constant used in the type-system.
-#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: DefId,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f7484048757..9ff4b64f48b 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Constness, HirId, Node, TraitCandidate};
+use rustc_hir::{HirId, Node, TraitCandidate};
 use rustc_index::IndexVec;
 use rustc_macros::HashStable;
 use rustc_query_system::dep_graph::DepNodeIndex;
@@ -82,6 +82,7 @@ use std::ops::{Bound, Deref};
 impl<'tcx> Interner for TyCtxt<'tcx> {
     type AdtDef = ty::AdtDef<'tcx>;
     type GenericArgsRef = ty::GenericArgsRef<'tcx>;
+    type GenericArg = ty::GenericArg<'tcx>;
     type DefId = DefId;
     type Binder<T> = Binder<'tcx, T>;
     type Ty = Ty<'tcx>;
@@ -1214,6 +1215,25 @@ macro_rules! nop_lift {
         impl<'a, 'tcx> Lift<'tcx> for $ty {
             type Lifted = $lifted;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+                // Assert that the set has the right type.
+                // Given an argument that has an interned type, the return type has the type of
+                // the corresponding interner set. This won't actually return anything, we're
+                // just doing this to compute said type!
+                fn _intern_set_ty_from_interned_ty<'tcx, Inner>(
+                    _x: Interned<'tcx, Inner>,
+                ) -> InternedSet<'tcx, Inner> {
+                    unreachable!()
+                }
+                fn _type_eq<T>(_x: &T, _y: &T) {}
+                fn _test<'tcx>(x: $lifted, tcx: TyCtxt<'tcx>) {
+                    // If `x` is a newtype around an `Interned<T>`, then `interner` is an
+                    // interner of appropriate type. (Ideally we'd also check that `x` is a
+                    // newtype with just that one field. Not sure how to do that.)
+                    let interner = _intern_set_ty_from_interned_ty(x.0);
+                    // Now check that this is the same type as `interners.$set`.
+                    _type_eq(&interner, &tcx.interners.$set);
+                }
+
                 tcx.interners
                     .$set
                     .contains_pointer_to(&InternedInSet(&*self.0.0))
@@ -1230,6 +1250,11 @@ macro_rules! nop_list_lift {
         impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
             type Lifted = &'tcx List<$lifted>;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+                // Assert that the set has the right type.
+                if false {
+                    let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set;
+                }
+
                 if self.is_empty() {
                     return Some(List::empty());
                 }
@@ -1251,19 +1276,13 @@ nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
 
 nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
 nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
-nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
-nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
-nop_list_lift! {projs; ProjectionKind => ProjectionKind}
 nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
 
 // This is the impl for `&'a GenericArgs<'a>`.
 nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>}
 
-CloneLiftImpls! {
-    Constness,
-    traits::WellFormedLoc,
+TrivialLiftImpls! {
     ImplPolarity,
-    crate::mir::ReturnConstraint,
 }
 
 macro_rules! sty_debug_print {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index bf6f082c21c..f939d466078 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -11,7 +11,7 @@ use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
 use std::path::PathBuf;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
 pub struct ExpectedFound<T> {
     pub expected: T,
     pub found: T,
@@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> {
 }
 
 // Data structures used in type unification
-#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)]
 #[rustc_pass_by_value]
 pub enum TypeError<'tcx> {
     Mismatch,
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index e598ead791e..72390e4bbb0 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -1029,7 +1029,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
 /// Stores the user-given args to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct UserArgs<'tcx> {
     /// The args for the item as given by the user.
     pub args: GenericArgsRef<'tcx>,
@@ -1056,7 +1056,7 @@ pub struct UserArgs<'tcx> {
 /// the self type, giving `Foo<?A>`. Finally, we unify that with
 /// the self type here, which contains `?A` to be `&'static u32`
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct UserSelfTy<'tcx> {
     pub impl_def_id: DefId,
     pub self_ty: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e5b9203d12a..2b75f6c4e8f 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -18,6 +18,9 @@ use std::fmt;
 /// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
 /// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval
 /// will do all required substitution as they run.
+///
+/// Note: the `Lift` impl is currently not used by rustc, but is used by
+/// rustc_codegen_cranelift when the `jit` feature is enabled.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
 pub struct Instance<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 99b697d0ea5..eb8ea0bc114 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1510,7 +1510,7 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct OpaqueTypeKey<'tcx> {
     pub def_id: LocalDefId,
@@ -1793,7 +1793,7 @@ impl<'tcx> ParamEnv<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
-#[derive(HashStable, Lift)]
+#[derive(HashStable)]
 pub struct ParamEnvAnd<'tcx, T> {
     pub param_env: ParamEnv<'tcx>,
     pub value: T,
@@ -2408,6 +2408,22 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    pub fn get_attrs_by_path<'attr>(
+        self,
+        did: DefId,
+        attr: &'attr [Symbol],
+    ) -> impl Iterator<Item = &'tcx ast::Attribute> + 'attr
+    where
+        'tcx: 'attr,
+    {
+        let filter_fn = move |a: &&ast::Attribute| a.path_matches(&attr);
+        if let Some(did) = did.as_local() {
+            self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+        } else {
+            self.item_attrs(did).iter().filter(filter_fn)
+        }
+    }
+
     pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> {
         if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
             let did: DefId = did.into();
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f24ac79323f..e1d4e43841d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -136,10 +136,8 @@ define_helper!(
 ///
 /// Regions not selected by the region highlight mode are presently
 /// unaffected.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
 pub struct RegionHighlightMode<'tcx> {
-    tcx: TyCtxt<'tcx>,
-
     /// If enabled, when we see the selected region, use "`'N`"
     /// instead of the ordinary behavior.
     highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
@@ -155,14 +153,6 @@ pub struct RegionHighlightMode<'tcx> {
 }
 
 impl<'tcx> RegionHighlightMode<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
-        Self {
-            tcx,
-            highlight_regions: Default::default(),
-            highlight_bound_region: Default::default(),
-        }
-    }
-
     /// If `region` and `number` are both `Some`, invokes
     /// `highlighting_region`.
     pub fn maybe_highlighting_region(
@@ -188,8 +178,13 @@ impl<'tcx> RegionHighlightMode<'tcx> {
     }
 
     /// Convenience wrapper for `highlighting_region`.
-    pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
-        self.highlighting_region(ty::Region::new_var(self.tcx, vid), number)
+    pub fn highlighting_region_vid(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        vid: ty::RegionVid,
+        number: usize,
+    ) {
+        self.highlighting_region(ty::Region::new_var(tcx, vid), number)
     }
 
     /// Returns `Some(n)` with the number to use for the given region, if any.
@@ -1778,7 +1773,7 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
             printed_type_count: 0,
             type_length_limit,
             truncated: false,
-            region_highlight_mode: RegionHighlightMode::new(tcx),
+            region_highlight_mode: RegionHighlightMode::default(),
             ty_infer_name_resolver: None,
             const_infer_name_resolver: None,
         }))
@@ -2746,20 +2741,14 @@ forward_display_to_print! {
 
     // HACK(eddyb) these are exhaustive instead of generic,
     // because `for<'tcx>` isn't possible yet.
-    ty::PolyExistentialPredicate<'tcx>,
     ty::PolyExistentialProjection<'tcx>,
     ty::PolyExistentialTraitRef<'tcx>,
     ty::Binder<'tcx, ty::TraitRef<'tcx>>,
     ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-    ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
     ty::Binder<'tcx, ty::FnSig<'tcx>>,
     ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
     ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
-    ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
     ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
-    ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
-    ty::Binder<'tcx, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>,
-
     ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
     ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 1b29a83f23e..f4158597d10 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -9,15 +9,13 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_hir::def::Namespace;
-use rustc_index::{Idx, IndexVec};
 use rustc_target::abi::TyAndLayout;
 use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
 
 use std::fmt::{self, Debug};
 use std::ops::ControlFlow;
-use std::rc::Rc;
-use std::sync::Arc;
 
+use super::print::PrettyPrinter;
 use super::{GenericArg, GenericArgKind, Region};
 
 impl fmt::Debug for ty::TraitDef {
@@ -343,14 +341,27 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
         this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
         f: &mut core::fmt::Formatter<'_>,
     ) -> core::fmt::Result {
-        // This reflects what `Const` looked liked before `Interned` was
-        // introduced. We print it like this to avoid having to update expected
-        // output in a lot of tests.
+        // If this is a value, we spend some effort to make it look nice.
+        if let ConstKind::Value(_) = this.data.kind() {
+            return ty::tls::with(move |tcx| {
+                // Somehow trying to lift the valtree results in lifetime errors, so we lift the
+                // entire constant.
+                let lifted = tcx.lift(*this.data).unwrap();
+                let ConstKind::Value(valtree) = lifted.kind() else {
+                    bug!("we checked that this is a valtree")
+                };
+                let cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+                let cx =
+                    cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?;
+                f.write_str(&cx.into_buffer())
+            });
+        }
+        // Fall back to something verbose.
         write!(
             f,
-            "Const {{ ty: {:?}, kind: {:?} }}",
-            &this.map(|data| data.ty()),
-            &this.map(|data| data.kind())
+            "{kind:?}: {ty:?}",
+            ty = &this.map(|data| data.ty()),
+            kind = &this.map(|data| data.kind())
         )
     }
 }
@@ -442,22 +453,16 @@ impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty:
 
 // For things for which the type library provides traversal implementations
 // for all Interners, we only need to provide a Lift implementation:
-CloneLiftImpls! {
-    (),
-    bool,
-    usize,
-    u16,
-    u32,
-    u64,
-    String,
-    rustc_type_ir::DebruijnIndex,
-}
-
-// For things about which the type library does not know, or does not
-// provide any traversal implementations, we need to provide both a Lift
-// implementation and traversal implementations (the latter only for
-// TyCtxt<'_> interners).
-TrivialTypeTraversalAndLiftImpls! {
+TrivialLiftImpls! {
+     (),
+     bool,
+     usize,
+}
+
+// For some things about which the type library does not know, or does not
+// provide any traversal implementations, we need to provide a traversal
+// implementation (only for TyCtxt<'_> interners).
+TrivialTypeTraversalImpls! {
     ::rustc_target::abi::FieldIdx,
     ::rustc_target::abi::VariantIdx,
     crate::middle::region::Scope,
@@ -467,14 +472,10 @@ TrivialTypeTraversalAndLiftImpls! {
     ::rustc_ast::NodeId,
     ::rustc_span::symbol::Symbol,
     ::rustc_hir::def::Res,
-    ::rustc_hir::def_id::DefId,
     ::rustc_hir::def_id::LocalDefId,
     ::rustc_hir::HirId,
     ::rustc_hir::MatchSource,
-    ::rustc_hir::Mutability,
-    ::rustc_hir::Unsafety,
     ::rustc_target::asm::InlineAsmRegOrRegClass,
-    ::rustc_target::spec::abi::Abi,
     crate::mir::coverage::CounterId,
     crate::mir::coverage::ExpressionId,
     crate::mir::coverage::MappedExpressionIndex,
@@ -492,16 +493,12 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::AssocItem,
     crate::ty::AssocKind,
     crate::ty::AliasKind,
-    crate::ty::AliasRelationDirection,
     crate::ty::Placeholder<crate::ty::BoundRegion>,
     crate::ty::Placeholder<crate::ty::BoundTy>,
     crate::ty::Placeholder<ty::BoundVar>,
-    crate::ty::ClosureKind,
     crate::ty::FreeRegion,
     crate::ty::InferTy,
     crate::ty::IntVarValue,
-    crate::ty::ParamConst,
-    crate::ty::ParamTy,
     crate::ty::adjustment::PointerCoercion,
     crate::ty::RegionVid,
     crate::ty::UniverseIndex,
@@ -509,33 +506,30 @@ TrivialTypeTraversalAndLiftImpls! {
     ::rustc_span::Span,
     ::rustc_span::symbol::Ident,
     ::rustc_errors::ErrorGuaranteed,
-    interpret::Scalar,
-    interpret::AllocId,
-    rustc_target::abi::Size,
     ty::BoundVar,
+    ty::ValTree<'tcx>,
 }
-
+// For some things about which the type library does not know, or does not
+// provide any traversal implementations, we need to provide a traversal
+// implementation and a lift implementation (the former only for TyCtxt<'_>
+// interners).
 TrivialTypeTraversalAndLiftImpls! {
-    ty::ValTree<'tcx>,
+    ::rustc_hir::def_id::DefId,
+    ::rustc_hir::Mutability,
+    ::rustc_hir::Unsafety,
+    ::rustc_target::spec::abi::Abi,
+    crate::ty::AliasRelationDirection,
+    crate::ty::ClosureKind,
+    crate::ty::ParamConst,
+    crate::ty::ParamTy,
+    interpret::Scalar,
+    interpret::AllocId,
+    rustc_target::abi::Size,
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
-impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
-    type Lifted = (A::Lifted, B::Lifted);
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some((tcx.lift(self.0)?, tcx.lift(self.1)?))
-    }
-}
-
-impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) {
-    type Lifted = (A::Lifted, B::Lifted, C::Lifted);
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?))
-    }
-}
-
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
     type Lifted = Option<T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -546,50 +540,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
     }
 }
 
-impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
-    type Lifted = Result<T::Lifted, E::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match self {
-            Ok(x) => tcx.lift(x).map(Ok),
-            Err(e) => tcx.lift(e).map(Err),
-        }
-    }
-}
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
-    type Lifted = Box<T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(Box::new(tcx.lift(*self)?))
-    }
-}
-
-impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> {
-    type Lifted = Rc<T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(Rc::new(tcx.lift(self.as_ref().clone())?))
-    }
-}
-
-impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
-    type Lifted = Arc<T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(Arc::new(tcx.lift(self.as_ref().clone())?))
-    }
-}
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> {
-    type Lifted = Vec<T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        self.into_iter().map(|v| tcx.lift(v)).collect()
-    }
-}
-
-impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> {
-    type Lifted = IndexVec<I, T::Lifted>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        self.into_iter().map(|e| tcx.lift(e)).collect()
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
     type Lifted = ty::Term<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -602,13 +552,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
         )
     }
 }
-impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
-    type Lifted = ty::ParamEnv<'tcx>;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.caller_bounds())
-            .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
-    }
-}
 
 ///////////////////////////////////////////////////////////////////////////
 // Traversal implementations.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 2502e303f7a..edab7fe58ba 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -351,7 +351,7 @@ impl<'tcx> ClosureArgs<'tcx> {
 }
 
 /// Similar to `ClosureArgs`; see the above documentation for more.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
 pub struct GeneratorArgs<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
@@ -1305,7 +1305,7 @@ impl<'tcx> AliasTy<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct GenSig<'tcx> {
     pub resume_ty: Ty<'tcx>,
     pub yield_ty: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 7ecc7e6014d..69c4c588c44 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -165,7 +165,7 @@ pub struct TypeckResults<'tcx> {
     /// reading places that are mentioned in a closure (because of _ patterns). However,
     /// to ensure the places are initialized, we introduce fake reads.
     /// Consider these two examples:
-    /// ``` (discriminant matching with only wildcard arm)
+    /// ```ignore (discriminant matching with only wildcard arm)
     /// let x: u8;
     /// let c = || match x { _ => () };
     /// ```
@@ -173,7 +173,7 @@ pub struct TypeckResults<'tcx> {
     /// want to capture it. However, we do still want an error here, because `x` should have
     /// to be initialized at the point where c is created. Therefore, we add a "fake read"
     /// instead.
-    /// ``` (destructured assignments)
+    /// ```ignore (destructured assignments)
     /// let c = || {
     ///     let (t1, t2) = t;
     /// }
@@ -654,7 +654,7 @@ rustc_index::newtype_index! {
 pub type CanonicalUserTypeAnnotations<'tcx> =
     IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct CanonicalUserTypeAnnotation<'tcx> {
     pub user_ty: Box<CanonicalUserType<'tcx>>,
     pub span: Span,
@@ -714,7 +714,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub enum UserType<'tcx> {
     Ty(Ty<'tcx>),
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 0ea61ec8d40..71e6e6f3a7a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     pattern
                 }
             }
-            Err(ErrorHandled::TooGeneric) => {
+            Err(ErrorHandled::TooGeneric(_)) => {
                 // While `Reported | Linted` cases will have diagnostics emitted already
                 // it is not true for TooGeneric case, so we need to give user more information.
                 self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
@@ -640,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             .kind
         } else {
             // If that fails, convert it to an opaque constant pattern.
-            match tcx.const_eval_resolve(self.param_env, uneval, None) {
+            match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
                 Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
-                Err(ErrorHandled::TooGeneric) => {
+                Err(ErrorHandled::TooGeneric(_)) => {
                     // If we land here it means the const can't be evaluated because it's `TooGeneric`.
                     self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                     PatKind::Wild
                 }
-                Err(ErrorHandled::Reported(_)) => PatKind::Wild,
+                Err(ErrorHandled::Reported(..)) => PatKind::Wild,
             }
         }
     }
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index b52827a1e88..fb33b3b49d3 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -105,25 +105,12 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
 
         trace!("ConstProp starting for {:?}", def_id);
 
-        let dummy_body = &Body::new(
-            body.source,
-            (*body.basic_blocks).to_owned(),
-            body.source_scopes.clone(),
-            body.local_decls.clone(),
-            Default::default(),
-            body.arg_count,
-            Default::default(),
-            body.span,
-            body.generator_kind(),
-            body.tainted_by_errors,
-        );
-
         // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
         // constants, instead of just checking for const-folding succeeding.
         // That would require a uniform one-def no-mutation analysis
         // and RPO (or recursing when needing the value of a local).
-        let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
-        optimization_finder.visit_body(body);
+        let mut linter = ConstPropagator::new(body, tcx);
+        linter.visit_body(body);
 
         trace!("ConstProp done for {:?}", def_id);
     }
@@ -169,11 +156,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
 }
 
 impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
-    fn new(
-        body: &Body<'tcx>,
-        dummy_body: &'mir Body<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> ConstPropagator<'mir, 'tcx> {
+    fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
         let def_id = body.source.def_id();
         let args = &GenericArgs::identity_for_item(tcx, def_id);
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
@@ -204,7 +187,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
         ecx.push_stack_frame(
             Instance::new(def_id, args),
-            dummy_body,
+            body,
             &ret,
             StackPopCleanup::Root { cleanup: false },
         )
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index af616c498fd..bb1f16aa8be 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -44,7 +44,7 @@
 //! points, which can be enabled via environment variable:
 //!
 //! ```shell
-//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug
+//! RUSTC_LOG=rustc_mir_transform::coverage=debug
 //! ```
 //!
 //! Other module paths with coverage-related debug logs may also be of interest, particularly for
@@ -52,7 +52,7 @@
 //! code generation pass). For example:
 //!
 //! ```shell
-//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
+//! RUSTC_LOG=rustc_mir_transform::coverage,rustc_codegen_llvm::coverageinfo=debug
 //! ```
 //!
 //! Coverage Debug Options
@@ -108,24 +108,23 @@
 //!         recursively, generating labels with nested operations, enclosed in parentheses
 //!         (for example: `bcb2 + (bcb0 - bcb1)`).
 
-use super::counters::{BcbCounter, CoverageCounters};
-use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
-use super::spans::CoverageSpan;
+use std::iter;
+use std::ops::Deref;
+use std::sync::OnceLock;
 
 use itertools::Itertools;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::create_dump_file;
 use rustc_middle::mir::generic_graphviz::GraphvizWriter;
 use rustc_middle::mir::spanview::{self, SpanViewable};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{self, BasicBlock};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 
-use std::iter;
-use std::ops::Deref;
-use std::sync::OnceLock;
+use super::counters::{BcbCounter, CoverageCounters};
+use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
+use super::spans::CoverageSpan;
 
 pub const NESTED_INDENT: &str = "    ";
 
@@ -259,36 +258,42 @@ impl Default for ExpressionFormat {
 /// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
 /// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
 pub(super) struct DebugCounters {
-    some_counters: Option<FxHashMap<Operand, DebugCounter>>,
+    state: Option<DebugCountersState>,
+}
+
+#[derive(Default)]
+struct DebugCountersState {
+    counters: FxHashMap<Operand, DebugCounter>,
 }
 
 impl DebugCounters {
     pub fn new() -> Self {
-        Self { some_counters: None }
+        Self { state: None }
     }
 
     pub fn enable(&mut self) {
         debug_assert!(!self.is_enabled());
-        self.some_counters.replace(FxHashMap::default());
+        self.state = Some(DebugCountersState::default());
     }
 
     pub fn is_enabled(&self) -> bool {
-        self.some_counters.is_some()
+        self.state.is_some()
     }
 
     pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option<String>) {
-        if let Some(counters) = &mut self.some_counters {
-            let id = counter_kind.as_operand();
-            counters
-                .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
-                .expect("attempt to add the same counter_kind to DebugCounters more than once");
-        }
+        let Some(state) = &mut self.state else { return };
+
+        let id = counter_kind.as_operand();
+        state
+            .counters
+            .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
+            .expect("attempt to add the same counter_kind to DebugCounters more than once");
     }
 
     pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
-        self.some_counters.as_ref().and_then(|counters| {
-            counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
-        })
+        let Some(state) = &self.state else { return None };
+
+        state.counters.get(&operand)?.some_block_label.as_ref()
     }
 
     pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
@@ -308,7 +313,7 @@ impl DebugCounters {
             if counter_format.operation {
                 return format!(
                     "{}{} {} {}",
-                    if counter_format.id || self.some_counters.is_none() {
+                    if counter_format.id || !self.is_enabled() {
                         format!("#{} = ", id.index())
                     } else {
                         String::new()
@@ -324,10 +329,9 @@ impl DebugCounters {
         }
 
         let id = counter_kind.as_operand();
-        if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
-            let counters = self.some_counters.as_ref().unwrap();
+        if let Some(state) = &self.state && (counter_format.block || !counter_format.id) {
             if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
-                counters.get(&id)
+                state.counters.get(&id)
             {
                 return if counter_format.id {
                     format!("{}#{:?}", block_label, id)
@@ -343,8 +347,10 @@ impl DebugCounters {
         if matches!(operand, Operand::Zero) {
             return String::from("0");
         }
-        if let Some(counters) = &self.some_counters {
-            if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) {
+        if let Some(state) = &self.state {
+            if let Some(DebugCounter { counter_kind, some_block_label }) =
+                state.counters.get(&operand)
+            {
                 if let BcbCounter::Expression { .. } = counter_kind {
                     if let Some(label) = some_block_label && debug_options().counter_format.block {
                         return format!(
@@ -378,30 +384,29 @@ impl DebugCounter {
 /// If enabled, this data structure captures additional debugging information used when generating
 /// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
 pub(super) struct GraphvizData {
-    some_bcb_to_coverage_spans_with_counters:
-        Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>>,
-    some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>>,
-    some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>>,
+    state: Option<GraphvizDataState>,
+}
+
+#[derive(Default)]
+struct GraphvizDataState {
+    bcb_to_coverage_spans_with_counters:
+        FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>,
+    bcb_to_dependency_counters: FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>,
+    edge_to_counter: FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>,
 }
 
 impl GraphvizData {
     pub fn new() -> Self {
-        Self {
-            some_bcb_to_coverage_spans_with_counters: None,
-            some_bcb_to_dependency_counters: None,
-            some_edge_to_counter: None,
-        }
+        Self { state: None }
     }
 
     pub fn enable(&mut self) {
         debug_assert!(!self.is_enabled());
-        self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default());
-        self.some_bcb_to_dependency_counters = Some(FxHashMap::default());
-        self.some_edge_to_counter = Some(FxHashMap::default());
+        self.state = Some(GraphvizDataState::default());
     }
 
     pub fn is_enabled(&self) -> bool {
-        self.some_bcb_to_coverage_spans_with_counters.is_some()
+        self.state.is_some()
     }
 
     pub fn add_bcb_coverage_span_with_counter(
@@ -410,27 +415,22 @@ impl GraphvizData {
         coverage_span: &CoverageSpan,
         counter_kind: &BcbCounter,
     ) {
-        if let Some(bcb_to_coverage_spans_with_counters) =
-            self.some_bcb_to_coverage_spans_with_counters.as_mut()
-        {
-            bcb_to_coverage_spans_with_counters
-                .entry(bcb)
-                .or_insert_with(Vec::new)
-                .push((coverage_span.clone(), counter_kind.clone()));
-        }
+        let Some(state) = &mut self.state else { return };
+
+        state
+            .bcb_to_coverage_spans_with_counters
+            .entry(bcb)
+            .or_insert_with(Vec::new)
+            .push((coverage_span.clone(), counter_kind.clone()));
     }
 
     pub fn get_bcb_coverage_spans_with_counters(
         &self,
         bcb: BasicCoverageBlock,
     ) -> Option<&[(CoverageSpan, BcbCounter)]> {
-        if let Some(bcb_to_coverage_spans_with_counters) =
-            self.some_bcb_to_coverage_spans_with_counters.as_ref()
-        {
-            bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
-        } else {
-            None
-        }
+        let Some(state) = &self.state else { return None };
+
+        state.bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
     }
 
     pub fn add_bcb_dependency_counter(
@@ -438,20 +438,19 @@ impl GraphvizData {
         bcb: BasicCoverageBlock,
         counter_kind: &BcbCounter,
     ) {
-        if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
-            bcb_to_dependency_counters
-                .entry(bcb)
-                .or_insert_with(Vec::new)
-                .push(counter_kind.clone());
-        }
+        let Some(state) = &mut self.state else { return };
+
+        state
+            .bcb_to_dependency_counters
+            .entry(bcb)
+            .or_insert_with(Vec::new)
+            .push(counter_kind.clone());
     }
 
     pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> {
-        if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
-            bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
-        } else {
-            None
-        }
+        let Some(state) = &self.state else { return None };
+
+        state.bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
     }
 
     pub fn set_edge_counter(
@@ -460,11 +459,12 @@ impl GraphvizData {
         to_bb: BasicBlock,
         counter_kind: &BcbCounter,
     ) {
-        if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
-            edge_to_counter
-                .try_insert((from_bcb, to_bb), counter_kind.clone())
-                .expect("invalid attempt to insert more than one edge counter for the same edge");
-        }
+        let Some(state) = &mut self.state else { return };
+
+        state
+            .edge_to_counter
+            .try_insert((from_bcb, to_bb), counter_kind.clone())
+            .expect("invalid attempt to insert more than one edge counter for the same edge");
     }
 
     pub fn get_edge_counter(
@@ -472,11 +472,9 @@ impl GraphvizData {
         from_bcb: BasicCoverageBlock,
         to_bb: BasicBlock,
     ) -> Option<&BcbCounter> {
-        if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
-            edge_to_counter.get(&(from_bcb, to_bb))
-        } else {
-            None
-        }
+        let Some(state) = &self.state else { return None };
+
+        state.edge_to_counter.get(&(from_bcb, to_bb))
     }
 }
 
@@ -485,41 +483,42 @@ impl GraphvizData {
 /// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
 /// and/or a `CoverageGraph` graphviz output).
 pub(super) struct UsedExpressions {
-    some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
-    some_unused_expressions:
-        Option<Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
+    state: Option<UsedExpressionsState>,
+}
+
+#[derive(Default)]
+struct UsedExpressionsState {
+    used_expression_operands: FxHashSet<Operand>,
+    unused_expressions: Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>,
 }
 
 impl UsedExpressions {
     pub fn new() -> Self {
-        Self { some_used_expression_operands: None, some_unused_expressions: None }
+        Self { state: None }
     }
 
     pub fn enable(&mut self) {
         debug_assert!(!self.is_enabled());
-        self.some_used_expression_operands = Some(FxHashMap::default());
-        self.some_unused_expressions = Some(Vec::new());
+        self.state = Some(UsedExpressionsState::default())
     }
 
     pub fn is_enabled(&self) -> bool {
-        self.some_used_expression_operands.is_some()
+        self.state.is_some()
     }
 
     pub fn add_expression_operands(&mut self, expression: &BcbCounter) {
-        if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
-            if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression {
-                used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
-                used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
-            }
+        let Some(state) = &mut self.state else { return };
+
+        if let BcbCounter::Expression { lhs, rhs, .. } = *expression {
+            state.used_expression_operands.insert(lhs);
+            state.used_expression_operands.insert(rhs);
         }
     }
 
     pub fn expression_is_used(&self, expression: &BcbCounter) -> bool {
-        if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
-            used_expression_operands.contains_key(&expression.as_operand())
-        } else {
-            false
-        }
+        let Some(state) = &self.state else { return false };
+
+        state.used_expression_operands.contains(&expression.as_operand())
     }
 
     pub fn add_unused_expression_if_not_found(
@@ -528,14 +527,10 @@ impl UsedExpressions {
         edge_from_bcb: Option<BasicCoverageBlock>,
         target_bcb: BasicCoverageBlock,
     ) {
-        if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
-            if !used_expression_operands.contains_key(&expression.as_operand()) {
-                self.some_unused_expressions.as_mut().unwrap().push((
-                    expression.clone(),
-                    edge_from_bcb,
-                    target_bcb,
-                ));
-            }
+        let Some(state) = &mut self.state else { return };
+
+        if !state.used_expression_operands.contains(&expression.as_operand()) {
+            state.unused_expressions.push((expression.clone(), edge_from_bcb, target_bcb));
         }
     }
 
@@ -544,11 +539,9 @@ impl UsedExpressions {
     pub fn get_unused_expressions(
         &self,
     ) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
-        if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
-            unused_expressions.clone()
-        } else {
-            Vec::new()
-        }
+        let Some(state) = &self.state else { return Vec::new() };
+
+        state.unused_expressions.clone()
     }
 
     /// If enabled, validate that every BCB or edge counter not directly associated with a coverage
@@ -562,51 +555,53 @@ impl UsedExpressions {
             BcbCounter,
         )],
     ) {
-        if self.is_enabled() {
-            let mut not_validated = bcb_counters_without_direct_coverage_spans
-                .iter()
-                .map(|(_, _, counter_kind)| counter_kind)
-                .collect::<Vec<_>>();
-            let mut validating_count = 0;
-            while not_validated.len() != validating_count {
-                let to_validate = not_validated.split_off(0);
-                validating_count = to_validate.len();
-                for counter_kind in to_validate {
-                    if self.expression_is_used(counter_kind) {
-                        self.add_expression_operands(counter_kind);
-                    } else {
-                        not_validated.push(counter_kind);
-                    }
+        if !self.is_enabled() {
+            return;
+        }
+
+        let mut not_validated = bcb_counters_without_direct_coverage_spans
+            .iter()
+            .map(|(_, _, counter_kind)| counter_kind)
+            .collect::<Vec<_>>();
+        let mut validating_count = 0;
+        while not_validated.len() != validating_count {
+            let to_validate = not_validated.split_off(0);
+            validating_count = to_validate.len();
+            for counter_kind in to_validate {
+                if self.expression_is_used(counter_kind) {
+                    self.add_expression_operands(counter_kind);
+                } else {
+                    not_validated.push(counter_kind);
                 }
             }
         }
     }
 
     pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) {
-        if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
-            for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions {
-                let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
-                    format!(
-                        "non-coverage edge counter found without a dependent expression, in \
+        let Some(state) = &self.state else { return };
+
+        for (counter_kind, edge_from_bcb, target_bcb) in &state.unused_expressions {
+            let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
+                format!(
+                    "non-coverage edge counter found without a dependent expression, in \
                         {:?}->{:?}; counter={}",
-                        from_bcb,
-                        target_bcb,
-                        debug_counters.format_counter(&counter_kind),
-                    )
-                } else {
-                    format!(
-                        "non-coverage counter found without a dependent expression, in {:?}; \
+                    from_bcb,
+                    target_bcb,
+                    debug_counters.format_counter(&counter_kind),
+                )
+            } else {
+                format!(
+                    "non-coverage counter found without a dependent expression, in {:?}; \
                         counter={}",
-                        target_bcb,
-                        debug_counters.format_counter(&counter_kind),
-                    )
-                };
-
-                if debug_options().allow_unused_expressions {
-                    debug!("WARNING: {}", unused_counter_message);
-                } else {
-                    bug!("{}", unused_counter_message);
-                }
+                    target_bcb,
+                    debug_counters.format_counter(&counter_kind),
+                )
+            };
+
+            if debug_options().allow_unused_expressions {
+                debug!("WARNING: {}", unused_counter_message);
+            } else {
+                bug!("{}", unused_counter_message);
             }
         }
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 60461691e7f..b6b0463614d 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -199,12 +199,8 @@ impl CoverageGraph {
     }
 
     #[inline(always)]
-    pub fn rank_partial_cmp(
-        &self,
-        a: BasicCoverageBlock,
-        b: BasicCoverageBlock,
-    ) -> Option<Ordering> {
-        self.dominators.as_ref().unwrap().rank_partial_cmp(a, b)
+    pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering {
+        self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 717763a94a0..32e8ca25d31 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -12,7 +12,6 @@ use rustc_span::source_map::original_sp;
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
 
 use std::cell::OnceCell;
-use std::cmp::Ordering;
 
 #[derive(Debug, Copy, Clone)]
 pub(super) enum CoverageStatement {
@@ -333,30 +332,21 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
 
         initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span));
 
-        initial_spans.sort_unstable_by(|a, b| {
-            if a.span.lo() == b.span.lo() {
-                if a.span.hi() == b.span.hi() {
-                    if a.is_in_same_bcb(b) {
-                        Some(Ordering::Equal)
-                    } else {
-                        // Sort equal spans by dominator relationship (so dominators always come
-                        // before the dominated equal spans). When later comparing two spans in
-                        // order, the first will either dominate the second, or they will have no
-                        // dominator relationship.
-                        self.basic_coverage_blocks.rank_partial_cmp(a.bcb, b.bcb)
-                    }
-                } else {
-                    // Sort hi() in reverse order so shorter spans are attempted after longer spans.
-                    // This guarantees that, if a `prev` span overlaps, and is not equal to, a
-                    // `curr` span, the prev span either extends further left of the curr span, or
-                    // they start at the same position and the prev span extends further right of
-                    // the end of the curr span.
-                    b.span.hi().partial_cmp(&a.span.hi())
-                }
-            } else {
-                a.span.lo().partial_cmp(&b.span.lo())
-            }
-            .unwrap()
+        initial_spans.sort_by(|a, b| {
+            // First sort by span start.
+            Ord::cmp(&a.span.lo(), &b.span.lo())
+                // If span starts are the same, sort by span end in reverse order.
+                // This ensures that if spans A and B are adjacent in the list,
+                // and they overlap but are not equal, then either:
+                // - Span A extends further left, or
+                // - Both have the same start and span A extends further right
+                .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse())
+                // If both spans are equal, sort the BCBs in dominator order,
+                // so that dominating BCBs come before other BCBs they dominate.
+                .then_with(|| self.basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb))
+                // If two spans are otherwise identical, put closure spans first,
+                // as this seems to be what the refinement step expects.
+                .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
         });
 
         initial_spans
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index f5cfc4153b8..92abd0c3b6e 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -752,8 +752,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         let param_env = ty::ParamEnv::reveal_all();
         let val = match literal.eval(self.tcx, param_env, None) {
             Ok(v) => v,
-            Err(ErrorHandled::Reported(_)) => return,
-            Err(ErrorHandled::TooGeneric) => span_bug!(
+            Err(ErrorHandled::Reported(..)) => return,
+            Err(ErrorHandled::TooGeneric(..)) => span_bug!(
                 self.body.source_info(location).span,
                 "collection encountered polymorphic constant: {:?}",
                 literal
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index a6c7eb8d912..90ac436a91f 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -210,7 +210,17 @@ pub struct ParseError {
     pub label: string::String,
     pub span: InnerSpan,
     pub secondary_label: Option<(string::String, InnerSpan)>,
-    pub should_be_replaced_with_positional_argument: bool,
+    pub suggestion: Suggestion,
+}
+
+pub enum Suggestion {
+    None,
+    /// Replace inline argument with positional argument:
+    /// `format!("{foo.bar}")` -> `format!("{}", foo.bar)`
+    UsePositional,
+    /// Remove `r#` from identifier:
+    /// `format!("{r#foo}")` -> `format!("{foo}")`
+    RemoveRawIdent(InnerSpan),
 }
 
 /// The parser structure for interpreting the input format string. This is
@@ -365,7 +375,7 @@ impl<'a> Parser<'a> {
             label: label.into(),
             span,
             secondary_label: None,
-            should_be_replaced_with_positional_argument: false,
+            suggestion: Suggestion::None,
         });
     }
 
@@ -389,7 +399,7 @@ impl<'a> Parser<'a> {
             label: label.into(),
             span,
             secondary_label: None,
-            should_be_replaced_with_positional_argument: false,
+            suggestion: Suggestion::None,
         });
     }
 
@@ -493,7 +503,7 @@ impl<'a> Parser<'a> {
             label,
             span: pos.to(pos),
             secondary_label,
-            should_be_replaced_with_positional_argument: false,
+            suggestion: Suggestion::None,
         });
 
         None
@@ -573,7 +583,37 @@ impl<'a> Parser<'a> {
             Some(ArgumentIs(i))
         } else {
             match self.cur.peek() {
-                Some(&(_, c)) if rustc_lexer::is_id_start(c) => Some(ArgumentNamed(self.word())),
+                Some(&(lo, c)) if rustc_lexer::is_id_start(c) => {
+                    let word = self.word();
+
+                    // Recover from `r#ident` in format strings.
+                    // FIXME: use a let chain
+                    if word == "r" {
+                        if let Some((pos, '#')) = self.cur.peek() {
+                            if self.input[pos + 1..]
+                                .chars()
+                                .next()
+                                .is_some_and(rustc_lexer::is_id_start)
+                            {
+                                self.cur.next();
+                                let word = self.word();
+                                let prefix_span = self.span(lo, lo + 2);
+                                let full_span = self.span(lo, lo + 2 + word.len());
+                                self.errors.insert(0, ParseError {
+                                    description: "raw identifiers are not supported".to_owned(),
+                                    note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()),
+                                    label: "raw identifier used here".to_owned(),
+                                    span: full_span,
+                                    secondary_label: None,
+                                    suggestion: Suggestion::RemoveRawIdent(prefix_span),
+                                });
+                                return Some(ArgumentNamed(word));
+                            }
+                        }
+                    }
+
+                    Some(ArgumentNamed(word))
+                }
 
                 // This is an `ArgumentNext`.
                 // Record the fact and do the resolution after parsing the
@@ -841,7 +881,7 @@ impl<'a> Parser<'a> {
                     label: "expected `?` to occur after `:`".to_owned(),
                     span: pos.to(pos),
                     secondary_label: None,
-                    should_be_replaced_with_positional_argument: false,
+                    suggestion: Suggestion::None,
                 },
             );
         }
@@ -867,7 +907,7 @@ impl<'a> Parser<'a> {
                             label: "not supported".to_string(),
                             span: InnerSpan::new(arg.position_span.start, field.position_span.end),
                             secondary_label: None,
-                            should_be_replaced_with_positional_argument: true,
+                            suggestion: Suggestion::UsePositional,
                         },
                     );
                 }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 56f4b387df8..4f8ce99417a 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -153,6 +153,9 @@ passes_deprecated_annotation_has_no_effect =
 passes_deprecated_attribute =
     deprecated attribute must be paired with either stable or unstable attribute
 
+passes_diagnostic_diagnostic_on_unimplemented_only_for_traits =
+    `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
+
 passes_diagnostic_item_first_defined =
     the diagnostic item is first defined here
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 879d1dd680c..2d94354e3e1 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -16,6 +16,7 @@ use rustc_hir::{
     self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
 use rustc_hir::{MethodKind, Target, Unsafety};
+use rustc_macros::LintDiagnostic;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::query::Providers;
@@ -24,7 +25,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
-    UNUSED_ATTRIBUTES,
+    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -36,6 +37,10 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
 
+#[derive(LintDiagnostic)]
+#[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
+pub struct DiagnosticOnUnimplementedOnlyForTraits;
+
 pub(crate) fn target_from_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_item: &hir::ImplItem<'_>,
@@ -104,6 +109,9 @@ impl CheckAttrVisitor<'_> {
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
+            if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) {
+                self.check_diagnostic_on_unimplemented(attr.span, hir_id, target);
+            }
             match attr.name_or_empty() {
                 sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
                 sym::inline => self.check_inline(hir_id, attr, span, target),
@@ -139,6 +147,9 @@ impl CheckAttrVisitor<'_> {
                     self.check_rustc_std_internal_symbol(&attr, span, target)
                 }
                 sym::naked => self.check_naked(hir_id, attr, span, target),
+                sym::rustc_never_returns_null_ptr => {
+                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                }
                 sym::rustc_legacy_const_generics => {
                     self.check_rustc_legacy_const_generics(hir_id, &attr, span, target, item)
                 }
@@ -284,6 +295,18 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
+    fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
+        if !matches!(target, Target::Trait) {
+            self.tcx.emit_spanned_lint(
+                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                DiagnosticOnUnimplementedOnlyForTraits,
+            );
+        }
+    }
+
     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
     fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
         match target {
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 4ba0cb31d0b..213e5c8ba68 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -43,9 +43,11 @@ use rustc_data_structures::fingerprint::PackedFingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_index::{Idx, IndexVec};
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use std::iter;
 use std::marker::PhantomData;
 
 // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
@@ -81,8 +83,9 @@ pub struct SerializedDepGraph<K: DepKind> {
     /// A flattened list of all edge targets in the graph, stored in the same
     /// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
     edge_list_data: Vec<u8>,
-    /// Reciprocal map to `nodes`.
-    index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
+    /// Stores a map from fingerprints to nodes per dep node kind.
+    /// This is the reciprocal of `nodes`.
+    index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
 }
 
 impl<K: DepKind> Default for SerializedDepGraph<K> {
@@ -137,7 +140,7 @@ impl<K: DepKind> SerializedDepGraph<K> {
 
     #[inline]
     pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
-        self.index.get(dep_node).cloned()
+        self.index.get(dep_node.kind.to_u16() as usize)?.get(&dep_node.hash).cloned()
     }
 
     #[inline]
@@ -147,7 +150,7 @@ impl<K: DepKind> SerializedDepGraph<K> {
 
     #[inline]
     pub fn node_count(&self) -> usize {
-        self.index.len()
+        self.nodes.len()
     }
 }
 
@@ -220,7 +223,8 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
         for _index in 0..node_count {
             // Decode the header for this edge; the header packs together as many of the fixed-size
             // fields as possible to limit the number of times we update decoder state.
-            let node_header = SerializedNodeHeader { bytes: d.read_array(), _marker: PhantomData };
+            let node_header =
+                SerializedNodeHeader::<K> { bytes: d.read_array(), _marker: PhantomData };
 
             let _i: SerializedDepNodeIndex = nodes.push(node_header.node());
             debug_assert_eq!(_i.index(), _index);
@@ -251,8 +255,14 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
         // end of the array. This padding ensure it doesn't.
         edge_list_data.extend(&[0u8; DEP_NODE_PAD]);
 
-        let index: FxHashMap<_, _> =
-            nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
+        // Read the number of each dep kind and use it to create an hash map with a suitable size.
+        let mut index: Vec<_> = (0..(K::MAX as usize + 1))
+            .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
+            .collect();
+
+        for (idx, node) in nodes.iter_enumerated() {
+            index[node.kind.to_u16() as usize].insert(node.hash, idx);
+        }
 
         SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
     }
@@ -419,6 +429,9 @@ struct EncoderState<K: DepKind> {
     total_node_count: usize,
     total_edge_count: usize,
     stats: Option<FxHashMap<K, Stat<K>>>,
+
+    /// Stores the number of times we've encoded each dep kind.
+    kind_stats: Vec<u32>,
 }
 
 impl<K: DepKind> EncoderState<K> {
@@ -428,6 +441,7 @@ impl<K: DepKind> EncoderState<K> {
             total_edge_count: 0,
             total_node_count: 0,
             stats: record_stats.then(FxHashMap::default),
+            kind_stats: iter::repeat(0).take(K::MAX as usize + 1).collect(),
         }
     }
 
@@ -438,6 +452,7 @@ impl<K: DepKind> EncoderState<K> {
     ) -> DepNodeIndex {
         let index = DepNodeIndex::new(self.total_node_count);
         self.total_node_count += 1;
+        self.kind_stats[node.node.kind.to_u16() as usize] += 1;
 
         let edge_count = node.edges.len();
         self.total_edge_count += edge_count;
@@ -463,11 +478,16 @@ impl<K: DepKind> EncoderState<K> {
     }
 
     fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
-        let Self { mut encoder, total_node_count, total_edge_count, stats: _ } = self;
+        let Self { mut encoder, total_node_count, total_edge_count, stats: _, kind_stats } = self;
 
         let node_count = total_node_count.try_into().unwrap();
         let edge_count = total_edge_count.try_into().unwrap();
 
+        // Encode the number of each dep kind encountered
+        for count in kind_stats.iter() {
+            count.encode(&mut encoder);
+        }
+
         debug!(?node_count, ?edge_count);
         debug!("position: {:?}", encoder.position());
         IntEncodedWithFixedSize(node_count).encode(&mut encoder);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 82060716575..90ae08ce37c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -26,7 +26,7 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::RegisteredTools;
 use rustc_middle::ty::{TyCtxt, Visibility};
 use rustc_session::lint::builtin::{
-    LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+    LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
 };
 use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -610,9 +610,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && path.segments.len() >= 2
             && path.segments[0].ident.name == sym::diagnostic
+            && path.segments[1].ident.name != sym::on_unimplemented
         {
             self.tcx.sess.parse_sess.buffer_lint(
-                UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
+                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                 path.segments[1].span(),
                 node_id,
                 "unknown diagnostic attribute",
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ba82ee95caa..956ae149e55 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -898,6 +898,9 @@ impl OutFileName {
 #[derive(Clone, Hash, Debug, HashStable_Generic)]
 pub struct OutputFilenames {
     pub out_directory: PathBuf,
+    /// Crate name. Never contains '-'.
+    crate_stem: String,
+    /// Typically based on `.rs` input file name. Any '-' is preserved.
     filestem: String,
     pub single_output_file: Option<OutFileName>,
     pub temps_directory: Option<PathBuf>,
@@ -911,6 +914,7 @@ pub const DWARF_OBJECT_EXT: &str = "dwo";
 impl OutputFilenames {
     pub fn new(
         out_directory: PathBuf,
+        out_crate_name: String,
         out_filestem: String,
         single_output_file: Option<OutFileName>,
         temps_directory: Option<PathBuf>,
@@ -922,6 +926,7 @@ impl OutputFilenames {
             single_output_file,
             temps_directory,
             outputs,
+            crate_stem: format!("{out_crate_name}{extra}"),
             filestem: format!("{out_filestem}{extra}"),
         }
     }
@@ -938,7 +943,12 @@ impl OutputFilenames {
     /// should be placed on disk.
     pub fn output_path(&self, flavor: OutputType) -> PathBuf {
         let extension = flavor.extension();
-        self.with_directory_and_extension(&self.out_directory, extension)
+        match flavor {
+            OutputType::Metadata => {
+                self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
+            }
+            _ => self.with_directory_and_extension(&self.out_directory, extension),
+        }
     }
 
     /// Gets the path where a compilation artifact of the given type for the
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index c0884fb21cd..7a57b0621cd 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -119,26 +119,11 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
     }
 }
 
-pub fn filename_for_metadata(
-    sess: &Session,
-    crate_name: Symbol,
-    outputs: &OutputFilenames,
-) -> OutFileName {
-    // If the command-line specified the path, use that directly.
-    if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
-        return out_filename.clone();
-    }
-
-    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
-
-    let out_filename = outputs.single_output_file.clone().unwrap_or_else(|| {
-        OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rmeta")))
-    });
-
+pub fn filename_for_metadata(sess: &Session, outputs: &OutputFilenames) -> OutFileName {
+    let out_filename = outputs.path(OutputType::Metadata);
     if let OutFileName::Real(ref path) = out_filename {
         check_file_is_writeable(path, sess);
     }
-
     out_filename
 }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 448314cd9e1..382754be2ca 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -592,6 +592,7 @@ symbols! {
         cttz,
         cttz_nonzero,
         custom_attribute,
+        custom_code_classes_in_docs,
         custom_derive,
         custom_inner_attributes,
         custom_mir,
@@ -1178,7 +1179,6 @@ symbols! {
         ptr_cast_const,
         ptr_cast_mut,
         ptr_const_is_null,
-        ptr_from_mut,
         ptr_from_ref,
         ptr_guaranteed_cmp,
         ptr_is_null,
@@ -1337,6 +1337,7 @@ symbols! {
         rustc_main,
         rustc_mir,
         rustc_must_implement_one_of,
+        rustc_never_returns_null_ptr,
         rustc_nonnull_optimization_guaranteed,
         rustc_nounwind,
         rustc_object_lifetime_default,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 1a4a46ceb40..5efd171b9dd 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -2,6 +2,7 @@ use crate::abi::{self, Abi, Align, FieldsShape, Size};
 use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
 use crate::spec::{self, HasTargetSpec};
 use rustc_span::Symbol;
+use std::fmt;
 use std::str::FromStr;
 
 mod aarch64;
@@ -45,17 +46,17 @@ pub enum PassMode {
     ///
     /// The argument has a layout abi of `ScalarPair`.
     Pair(ArgAttributes, ArgAttributes),
-    /// Pass the argument after casting it, to either a single uniform or a
-    /// pair of registers. The bool indicates if a `Reg::i32()` dummy argument
-    /// is emitted before the real argument.
-    Cast(Box<CastTarget>, bool),
+    /// Pass the argument after casting it. See the `CastTarget` docs for details. The bool
+    /// indicates if a `Reg::i32()` dummy argument is emitted before the real argument.
+    Cast { pad_i32: bool, cast: Box<CastTarget> },
     /// Pass the argument indirectly via a hidden pointer.
-    /// The `extra_attrs` value, if any, is for the extra data (vtable or length)
-    /// which indicates that it refers to an unsized rvalue.
-    /// `on_stack` defines that the value should be passed at a fixed
-    /// stack offset in accordance to the ABI rather than passed using a
-    /// pointer. This corresponds to the `byval` LLVM argument attribute.
-    Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
+    /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized
+    /// argument. (This is the only mode that supports unsized arguments.)
+    /// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to
+    /// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument
+    /// attribute (using the Rust type of this argument). `on_stack` cannot be true for unsized
+    /// arguments, i.e., when `meta_attrs` is `Some`.
+    Indirect { attrs: ArgAttributes, meta_attrs: Option<ArgAttributes>, on_stack: bool },
 }
 
 impl PassMode {
@@ -64,17 +65,20 @@ impl PassMode {
     /// so that needs to be compared as well!
     pub fn eq_abi(&self, other: &Self) -> bool {
         match (self, other) {
-            (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type
+            (PassMode::Ignore, PassMode::Ignore) => true,
             (PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2),
             (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2),
-            (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1.eq_abi(c2) && pad1 == pad2,
             (
-                PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 },
-                PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 },
+                PassMode::Cast { cast: c1, pad_i32: pad1 },
+                PassMode::Cast { cast: c2, pad_i32: pad2 },
+            ) => c1.eq_abi(c2) && pad1 == pad2,
+            (
+                PassMode::Indirect { attrs: a1, meta_attrs: None, on_stack: s1 },
+                PassMode::Indirect { attrs: a2, meta_attrs: None, on_stack: s2 },
             ) => a1.eq_abi(a2) && s1 == s2,
             (
-                PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 },
-                PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 },
+                PassMode::Indirect { attrs: a1, meta_attrs: Some(e1), on_stack: s1 },
+                PassMode::Indirect { attrs: a2, meta_attrs: Some(e2), on_stack: s2 },
             ) => a1.eq_abi(a2) && e1.eq_abi(e2) && s1 == s2,
             _ => false,
         }
@@ -255,6 +259,13 @@ impl Uniform {
     }
 }
 
+/// Describes the type used for `PassMode::Cast`.
+///
+/// Passing arguments in this mode works as follows: the registers in the `prefix` (the ones that
+/// are `Some`) get laid out one after the other (using `repr(C)` layout rules). Then the
+/// `rest.unit` register type gets repeated often enough to cover `rest.size`. This describes the
+/// actual type used for the call; the Rust type of the argument is then transmuted to this ABI type
+/// (and all data in the padding between the registers is dropped).
 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct CastTarget {
     pub prefix: [Option<Reg>; 8],
@@ -515,12 +526,20 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
 
 /// Information about how to pass an argument to,
 /// or return a value from, a function, under some ABI.
-#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct ArgAbi<'a, Ty> {
     pub layout: TyAndLayout<'a, Ty>,
     pub mode: PassMode,
 }
 
+// Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl.
+impl<'a, Ty: fmt::Display> fmt::Debug for ArgAbi<'a, Ty> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let ArgAbi { layout, mode } = self;
+        f.debug_struct("ArgAbi").field("layout", layout).field("mode", mode).finish()
+    }
+}
+
 impl<'a, Ty> ArgAbi<'a, Ty> {
     /// This defines the "default ABI" for that type, that is then later adjusted in `fn_abi_adjust_for_abi`.
     pub fn new(
@@ -556,15 +575,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
         attrs.pointee_size = layout.size;
         attrs.pointee_align = Some(layout.align.abi);
 
-        let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new());
+        let meta_attrs = layout.is_unsized().then_some(ArgAttributes::new());
 
-        PassMode::Indirect { attrs, extra_attrs, on_stack: false }
+        PassMode::Indirect { attrs, meta_attrs, on_stack: false }
     }
 
     pub fn make_indirect(&mut self) {
         match self.mode {
             PassMode::Direct(_) | PassMode::Pair(_, _) => {}
-            PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return,
+            PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: false } => return,
             _ => panic!("Tried to make {:?} indirect", self.mode),
         }
 
@@ -574,7 +593,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     pub fn make_indirect_byval(&mut self, byval_align: Option<Align>) {
         self.make_indirect();
         match self.mode {
-            PassMode::Indirect { ref mut attrs, extra_attrs: _, ref mut on_stack } => {
+            PassMode::Indirect { ref mut attrs, meta_attrs: _, ref mut on_stack } => {
                 *on_stack = true;
 
                 // Some platforms, like 32-bit x86, change the alignment of the type when passing
@@ -607,11 +626,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     }
 
     pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
-        self.mode = PassMode::Cast(Box::new(target.into()), false);
+        self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32: false };
     }
 
     pub fn cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool) {
-        self.mode = PassMode::Cast(Box::new(target.into()), pad_i32);
+        self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32 };
     }
 
     pub fn is_indirect(&self) -> bool {
@@ -619,11 +638,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     }
 
     pub fn is_sized_indirect(&self) -> bool {
-        matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ })
+        matches!(self.mode, PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ })
     }
 
     pub fn is_unsized_indirect(&self) -> bool {
-        matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ })
+        matches!(self.mode, PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ })
     }
 
     pub fn is_ignore(&self) -> bool {
@@ -694,7 +713,7 @@ impl RiscvInterruptKind {
 ///
 /// I will do my best to describe this structure, but these
 /// comments are reverse-engineered and may be inaccurate. -NDM
-#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct FnAbi<'a, Ty> {
     /// The LLVM types of each argument.
     pub args: Box<[ArgAbi<'a, Ty>]>,
@@ -715,6 +734,21 @@ pub struct FnAbi<'a, Ty> {
     pub can_unwind: bool,
 }
 
+// Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl.
+impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let FnAbi { args, ret, c_variadic, fixed_count, conv, can_unwind } = self;
+        f.debug_struct("FnAbi")
+            .field("args", args)
+            .field("ret", ret)
+            .field("c_variadic", c_variadic)
+            .field("fixed_count", fixed_count)
+            .field("conv", conv)
+            .field("can_unwind", can_unwind)
+            .finish()
+    }
+}
+
 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum AdjustForForeignAbiError {
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index b738c3133d9..afa1b70efc2 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -142,13 +142,13 @@ where
         for arg in fn_abi.args.iter_mut() {
             let attrs = match arg.mode {
                 PassMode::Ignore
-                | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+                | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
                     continue;
                 }
                 PassMode::Direct(ref mut attrs) => attrs,
                 PassMode::Pair(..)
-                | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
-                | PassMode::Cast(..) => {
+                | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
+                | PassMode::Cast { .. } => {
                     unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
                 }
             };
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index a335585dbf3..636adcf6b17 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -3,6 +3,7 @@ pub use Primitive::*;
 
 use crate::json::{Json, ToJson};
 
+use std::fmt;
 use std::ops::Deref;
 
 use rustc_macros::HashStable_Generic;
@@ -24,12 +25,22 @@ impl ToJson for Endian {
 /// to that obtained from `layout_of(ty)`, as we need to produce
 /// layouts for which Rust types do not exist, such as enum variants
 /// or synthetic fields of enums (i.e., discriminants) and fat pointers.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct TyAndLayout<'a, Ty> {
     pub ty: Ty,
     pub layout: Layout<'a>,
 }
 
+impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Print the type in a readable way, not its debug representation.
+        f.debug_struct("TyAndLayout")
+            .field("ty", &format_args!("{}", self.ty))
+            .field("layout", &self.layout)
+            .finish()
+    }
+}
+
 impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
     type Target = &'a LayoutS;
     fn deref(&self) -> &&'a LayoutS {
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index e2df7e0bdcc..b29ab14e7f2 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -1,5 +1,5 @@
 use super::apple_base::{opts, Arch};
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let llvm_target = "arm64-apple-ios14.0-macabi";
@@ -7,6 +7,7 @@ pub fn target() -> Target {
     let arch = Arch::Arm64_macabi;
     let mut base = opts("ios", arch);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     Target {
         llvm_target: llvm_target.into(),
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index 956a5cb5c2f..a99cccd42c4 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -68,7 +68,7 @@ pub enum Abi {
 impl Abi {
     pub fn supports_varargs(self) -> bool {
         // * C and Cdecl obviously support varargs.
-        // * C can be based on SysV64 or Win64, so they must support varargs.
+        // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
         // * EfiApi is based on Win64 or C, so it also supports it.
         //
         // * Stdcall does not, because it would be impossible for the callee to clean
@@ -79,6 +79,7 @@ impl Abi {
         match self {
             Self::C { .. }
             | Self::Cdecl { .. }
+            | Self::Aapcs { .. }
             | Self::Win64 { .. }
             | Self::SysV64 { .. }
             | Self::EfiApi => true,
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index 50f359c357b..fd1926f2945 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,5 +1,5 @@
 use super::apple_base::{opts, Arch};
-use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let llvm_target = "x86_64-apple-ios14.0-macabi";
@@ -7,6 +7,7 @@ pub fn target() -> Target {
     let arch = Arch::X86_64_macabi;
     let mut base = opts("ios", arch);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     Target {
         llvm_target: llvm_target.into(),
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 2db24c43734..20253b32add 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -27,6 +27,8 @@ trait_selection_inherent_projection_normalization_overflow = overflow evaluating
 trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
     .label = invalid on-clause here
 
+trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute
+
 trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
         [none] {""}
        *[default] {" "}for type `{$self_desc}`
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 307c0516f70..7941f64873b 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -28,8 +28,8 @@ use std::ops::ControlFlow;
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
 
 use super::inspect::ProofTreeBuilder;
-use super::search_graph;
 use super::SolverMode;
+use super::{search_graph, GoalEvaluationKind};
 use super::{search_graph::SearchGraph, Goal};
 pub use select::InferCtxtSelectExt;
 
@@ -85,7 +85,7 @@ pub struct EvalCtxt<'a, 'tcx> {
     // evaluation code.
     tainted: Result<(), NoSolution>,
 
-    inspect: ProofTreeBuilder<'tcx>,
+    pub(super) inspect: ProofTreeBuilder<'tcx>,
 }
 
 #[derive(Debug, Clone)]
@@ -164,7 +164,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
         Option<inspect::GoalEvaluation<'tcx>>,
     ) {
         EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
-            ecx.evaluate_goal(IsNormalizesToHack::No, goal)
+            ecx.evaluate_goal(GoalEvaluationKind::Root, goal)
         })
     }
 }
@@ -340,11 +340,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     /// been constrained and the certainty of the result.
     fn evaluate_goal(
         &mut self,
-        is_normalizes_to_hack: IsNormalizesToHack,
+        goal_evaluation_kind: GoalEvaluationKind,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
     ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
         let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
-        let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack);
+        let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, goal_evaluation_kind);
         let encountered_overflow = self.search_graph.encountered_overflow();
         let canonical_response = EvalCtxt::evaluate_canonical_goal(
             self.tcx(),
@@ -389,7 +389,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         // solver cycle.
         if cfg!(debug_assertions)
             && has_changed
-            && is_normalizes_to_hack == IsNormalizesToHack::No
+            && !matches!(
+                goal_evaluation_kind,
+                GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }
+            )
             && !self.search_graph.in_cycle()
         {
             // The nested evaluation has to happen with the original state
@@ -561,8 +564,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 },
             );
 
-            let (_, certainty, instantiate_goals) =
-                self.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal)?;
+            let (_, certainty, instantiate_goals) = self.evaluate_goal(
+                GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes },
+                unconstrained_goal,
+            )?;
             self.add_goals(instantiate_goals);
 
             // Finally, equate the goal's RHS with the unconstrained var.
@@ -596,8 +601,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         }
 
         for goal in goals.goals.drain(..) {
-            let (has_changed, certainty, instantiate_goals) =
-                self.evaluate_goal(IsNormalizesToHack::No, goal)?;
+            let (has_changed, certainty, instantiate_goals) = self.evaluate_goal(
+                GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No },
+                goal,
+            )?;
             self.add_goals(instantiate_goals);
             if has_changed {
                 unchanged_certainty = None;
@@ -949,8 +956,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         use rustc_middle::mir::interpret::ErrorHandled;
         match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) {
             Ok(ct) => Some(ct),
-            Err(ErrorHandled::Reported(e)) => Some(ty::Const::new_error(self.tcx(), e.into(), ty)),
-            Err(ErrorHandled::TooGeneric) => None,
+            Err(ErrorHandled::Reported(e, _)) => {
+                Some(ty::Const::new_error(self.tcx(), e.into(), ty))
+            }
+            Err(ErrorHandled::TooGeneric(_)) => None,
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index f88cfbac3f3..6087b916790 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -24,13 +24,13 @@ where
             search_graph: outer_ecx.search_graph,
             nested_goals: outer_ecx.nested_goals.clone(),
             tainted: outer_ecx.tainted,
-            inspect: outer_ecx.inspect.new_goal_candidate(),
+            inspect: outer_ecx.inspect.new_probe(),
         };
         let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx));
         if !outer_ecx.inspect.is_noop() {
             let probe_kind = probe_kind(&r);
             nested_ecx.inspect.probe_kind(probe_kind);
-            outer_ecx.inspect.goal_candidate(nested_ecx.inspect);
+            outer_ecx.inspect.finish_probe(nested_ecx.inspect);
         }
         r
     }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs
index 46025da7683..749bba33c9b 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect.rs
@@ -7,13 +7,13 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::DumpSolverProofTree;
 
 use super::eval_ctxt::UseGlobalCache;
-use super::GenerateProofTree;
+use super::{GenerateProofTree, GoalEvaluationKind};
 
 #[derive(Eq, PartialEq, Debug)]
 pub struct WipGoalEvaluation<'tcx> {
     pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    pub kind: WipGoalEvaluationKind,
     pub evaluation: Option<WipCanonicalGoalEvaluation<'tcx>>,
-    pub is_normalizes_to_hack: IsNormalizesToHack,
     pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
 }
 
@@ -21,8 +21,13 @@ impl<'tcx> WipGoalEvaluation<'tcx> {
     pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> {
         inspect::GoalEvaluation {
             uncanonicalized_goal: self.uncanonicalized_goal,
+            kind: match self.kind {
+                WipGoalEvaluationKind::Root => inspect::GoalEvaluationKind::Root,
+                WipGoalEvaluationKind::Nested { is_normalizes_to_hack } => {
+                    inspect::GoalEvaluationKind::Nested { is_normalizes_to_hack }
+                }
+            },
             evaluation: self.evaluation.unwrap().finalize(),
-            is_normalizes_to_hack: self.is_normalizes_to_hack,
             returned_goals: self.returned_goals,
         }
     }
@@ -30,6 +35,12 @@ impl<'tcx> WipGoalEvaluation<'tcx> {
 
 #[derive(Eq, PartialEq, Debug)]
 pub enum WipGoalEvaluationKind {
+    Root,
+    Nested { is_normalizes_to_hack: IsNormalizesToHack },
+}
+
+#[derive(Eq, PartialEq, Debug)]
+pub enum WipCanonicalGoalEvaluationKind {
     Overflow,
     CacheHit(CacheHit),
 }
@@ -37,7 +48,7 @@ pub enum WipGoalEvaluationKind {
 #[derive(Eq, PartialEq, Debug)]
 pub struct WipCanonicalGoalEvaluation<'tcx> {
     pub goal: CanonicalInput<'tcx>,
-    pub kind: Option<WipGoalEvaluationKind>,
+    pub kind: Option<WipCanonicalGoalEvaluationKind>,
     pub revisions: Vec<WipGoalEvaluationStep<'tcx>>,
     pub result: Option<QueryResult<'tcx>>,
 }
@@ -45,11 +56,13 @@ pub struct WipCanonicalGoalEvaluation<'tcx> {
 impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
     pub fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> {
         let kind = match self.kind {
-            Some(WipGoalEvaluationKind::Overflow) => inspect::GoalEvaluationKind::Overflow,
-            Some(WipGoalEvaluationKind::CacheHit(hit)) => {
-                inspect::GoalEvaluationKind::CacheHit(hit)
+            Some(WipCanonicalGoalEvaluationKind::Overflow) => {
+                inspect::CanonicalGoalEvaluationKind::Overflow
             }
-            None => inspect::GoalEvaluationKind::Uncached {
+            Some(WipCanonicalGoalEvaluationKind::CacheHit(hit)) => {
+                inspect::CanonicalGoalEvaluationKind::CacheHit(hit)
+            }
+            None => inspect::CanonicalGoalEvaluationKind::Uncached {
                 revisions: self
                     .revisions
                     .into_iter()
@@ -87,7 +100,7 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> {
 pub struct WipGoalEvaluationStep<'tcx> {
     pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
 
-    pub evaluation: WipGoalCandidate<'tcx>,
+    pub evaluation: WipProbe<'tcx>,
 }
 
 impl<'tcx> WipGoalEvaluationStep<'tcx> {
@@ -102,26 +115,37 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> {
 }
 
 #[derive(Eq, PartialEq, Debug)]
-pub struct WipGoalCandidate<'tcx> {
-    pub added_goals_evaluations: Vec<WipAddedGoalsEvaluation<'tcx>>,
-    pub candidates: Vec<WipGoalCandidate<'tcx>>,
+pub struct WipProbe<'tcx> {
+    pub steps: Vec<WipProbeStep<'tcx>>,
     pub kind: Option<ProbeKind<'tcx>>,
 }
 
-impl<'tcx> WipGoalCandidate<'tcx> {
-    pub fn finalize(self) -> inspect::GoalCandidate<'tcx> {
-        inspect::GoalCandidate {
-            added_goals_evaluations: self
-                .added_goals_evaluations
-                .into_iter()
-                .map(WipAddedGoalsEvaluation::finalize)
-                .collect(),
-            candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(),
+impl<'tcx> WipProbe<'tcx> {
+    pub fn finalize(self) -> inspect::Probe<'tcx> {
+        inspect::Probe {
+            steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(),
             kind: self.kind.unwrap(),
         }
     }
 }
 
+#[derive(Eq, PartialEq, Debug)]
+pub enum WipProbeStep<'tcx> {
+    AddGoal(Goal<'tcx, ty::Predicate<'tcx>>),
+    EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
+    NestedProbe(WipProbe<'tcx>),
+}
+
+impl<'tcx> WipProbeStep<'tcx> {
+    pub fn finalize(self) -> inspect::ProbeStep<'tcx> {
+        match self {
+            WipProbeStep::AddGoal(goal) => inspect::ProbeStep::AddGoal(goal),
+            WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
+            WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
+        }
+    }
+}
+
 #[derive(Debug)]
 pub enum DebugSolver<'tcx> {
     Root,
@@ -129,7 +153,7 @@ pub enum DebugSolver<'tcx> {
     CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>),
     AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>),
     GoalEvaluationStep(WipGoalEvaluationStep<'tcx>),
-    GoalCandidate(WipGoalCandidate<'tcx>),
+    Probe(WipProbe<'tcx>),
 }
 
 impl<'tcx> From<WipGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
@@ -156,9 +180,9 @@ impl<'tcx> From<WipGoalEvaluationStep<'tcx>> for DebugSolver<'tcx> {
     }
 }
 
-impl<'tcx> From<WipGoalCandidate<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipGoalCandidate<'tcx>) -> DebugSolver<'tcx> {
-        DebugSolver::GoalCandidate(g)
+impl<'tcx> From<WipProbe<'tcx>> for DebugSolver<'tcx> {
+    fn from(p: WipProbe<'tcx>) -> DebugSolver<'tcx> {
+        DebugSolver::Probe(p)
     }
 }
 
@@ -249,15 +273,20 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         self.state.is_none()
     }
 
-    pub fn new_goal_evaluation(
+    pub(super) fn new_goal_evaluation(
         &mut self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
-        is_normalizes_to_hack: IsNormalizesToHack,
+        kind: GoalEvaluationKind,
     ) -> ProofTreeBuilder<'tcx> {
         self.nested(|| WipGoalEvaluation {
             uncanonicalized_goal: goal,
+            kind: match kind {
+                GoalEvaluationKind::Root => WipGoalEvaluationKind::Root,
+                GoalEvaluationKind::Nested { is_normalizes_to_hack } => {
+                    WipGoalEvaluationKind::Nested { is_normalizes_to_hack }
+                }
+            },
             evaluation: None,
-            is_normalizes_to_hack,
             returned_goals: vec![],
         })
     }
@@ -286,7 +315,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn goal_evaluation_kind(&mut self, kind: WipGoalEvaluationKind) {
+    pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
@@ -329,11 +358,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
     ) -> ProofTreeBuilder<'tcx> {
         self.nested(|| WipGoalEvaluationStep {
             instantiated_goal,
-            evaluation: WipGoalCandidate {
-                added_goals_evaluations: vec![],
-                candidates: vec![],
-                kind: None,
-            },
+            evaluation: WipProbe { steps: vec![], kind: None },
         })
     }
     pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) {
@@ -350,18 +375,14 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> {
-        self.nested(|| WipGoalCandidate {
-            added_goals_evaluations: vec![],
-            candidates: vec![],
-            kind: None,
-        })
+    pub fn new_probe(&mut self) -> ProofTreeBuilder<'tcx> {
+        self.nested(|| WipProbe { steps: vec![], kind: None })
     }
 
     pub fn probe_kind(&mut self, probe_kind: ProbeKind<'tcx>) {
         if let Some(this) = self.as_mut() {
             match this {
-                DebugSolver::GoalCandidate(this) => {
+                DebugSolver::Probe(this) => {
                     assert_eq!(this.kind.replace(probe_kind), None)
                 }
                 _ => unreachable!(),
@@ -369,17 +390,32 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) {
+    pub fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
         if let Some(this) = self.as_mut() {
-            match (this, candidate.state.unwrap().tree) {
+            match this {
+                DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
+                    evaluation: WipProbe { steps, .. },
+                    ..
+                })
+                | DebugSolver::Probe(WipProbe { steps, .. }) => {
+                    steps.push(WipProbeStep::AddGoal(goal))
+                }
+                _ => unreachable!(),
+            }
+        }
+    }
+
+    pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) {
+        if let Some(this) = self.as_mut() {
+            match (this, probe.state.unwrap().tree) {
                 (
-                    DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. })
+                    DebugSolver::Probe(WipProbe { steps, .. })
                     | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
-                        evaluation: WipGoalCandidate { candidates, .. },
+                        evaluation: WipProbe { steps, .. },
                         ..
                     }),
-                    DebugSolver::GoalCandidate(candidate),
-                ) => candidates.push(candidate),
+                    DebugSolver::Probe(probe),
+                ) => steps.push(WipProbeStep::NestedProbe(probe)),
                 _ => unreachable!(),
             }
         }
@@ -416,14 +452,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
             match (this, added_goals_evaluation.state.unwrap().tree) {
                 (
                     DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
-                        evaluation: WipGoalCandidate { added_goals_evaluations, .. },
+                        evaluation: WipProbe { steps, .. },
                         ..
                     })
-                    | DebugSolver::GoalCandidate(WipGoalCandidate {
-                        added_goals_evaluations, ..
-                    }),
+                    | DebugSolver::Probe(WipProbe { steps, .. }),
                     DebugSolver::AddedGoalsEvaluation(added_goals_evaluation),
-                ) => added_goals_evaluations.push(added_goals_evaluation),
+                ) => steps.push(WipProbeStep::EvaluateGoals(added_goals_evaluation)),
                 _ => unreachable!(),
             }
         }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index c492408bc76..bd612ce4778 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -19,7 +19,8 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::traits::solve::{
-    CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response,
+    CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult,
+    Response,
 };
 use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{
@@ -59,6 +60,12 @@ enum SolverMode {
     Coherence,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum GoalEvaluationKind {
+    Root,
+    Nested { is_normalizes_to_hack: IsNormalizesToHack },
+}
+
 trait CanonicalResponseExt {
     fn has_no_inference_or_external_constraints(&self) -> bool;
 
@@ -228,6 +235,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+        self.inspect.add_goal(goal);
         self.nested_goals.goals.push(goal);
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index c816b51f67a..16de518e8e0 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -187,7 +187,7 @@ impl<'tcx> SearchGraph<'tcx> {
                 last.encountered_overflow = true;
             }
 
-            inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::Overflow);
+            inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
             return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
         };
 
@@ -203,7 +203,7 @@ impl<'tcx> SearchGraph<'tcx> {
                     available_depth,
                 )
             {
-                inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit(
+                inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit(
                     CacheHit::Global,
                 ));
                 self.on_cache_hit(reached_depth, encountered_overflow);
@@ -240,7 +240,7 @@ impl<'tcx> SearchGraph<'tcx> {
             // Finally we can return either the provisional response for that goal if we have a
             // coinductive cycle or an ambiguous result if the cycle is inductive.
             Entry::Occupied(entry_index) => {
-                inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit(
+                inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit(
                     CacheHit::Provisional,
                 ));
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index ba5000da6cd..8096d7969f3 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -793,7 +793,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                                             span: tcx.def_span(unevaluated.def),
                                             unevaluated: unevaluated,
                                         });
-                                    Err(ErrorHandled::Reported(reported.into()))
+                                    Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
                                 }
                                 Err(err) => Err(err),
                             }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 3d0d3812d0c..62ab1e1049b 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -73,13 +73,13 @@ pub fn is_const_evaluatable<'tcx>(
             ty::ConstKind::Unevaluated(uv) => {
                 let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
                 match concrete {
-                    Err(ErrorHandled::TooGeneric) => {
+                    Err(ErrorHandled::TooGeneric(_)) => {
                         Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
                             span,
                             "Missing value for constant, but no error reported?",
                         )))
                     }
-                    Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
+                    Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
                     Ok(_) => Ok(()),
                 }
             }
@@ -132,7 +132,7 @@ pub fn is_const_evaluatable<'tcx>(
                     .emit()
             }
 
-            Err(ErrorHandled::TooGeneric) => {
+            Err(ErrorHandled::TooGeneric(_)) => {
                 let err = if uv.has_non_region_infer() {
                     NotConstEvaluatable::MentionsInfer
                 } else if uv.has_non_region_param() {
@@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>(
 
                 Err(err)
             }
-            Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
+            Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
             Ok(_) => Ok(()),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index fe71a9f07df..4086db2ab55 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -9,6 +9,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use std::iter;
@@ -336,6 +337,10 @@ pub enum AppendConstMessage {
     Custom(Symbol),
 }
 
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_malformed_on_unimplemented_attr)]
+pub struct NoValueInOnUnimplementedLint;
+
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
         tcx: TyCtxt<'tcx>,
@@ -343,7 +348,8 @@ impl<'tcx> OnUnimplementedDirective {
         items: &[NestedMetaItem],
         span: Span,
         is_root: bool,
-    ) -> Result<Self, ErrorGuaranteed> {
+        is_diagnostic_namespace_variant: bool,
+    ) -> Result<Option<Self>, ErrorGuaranteed> {
         let mut errored = None;
         let mut item_iter = items.iter();
 
@@ -391,7 +397,10 @@ impl<'tcx> OnUnimplementedDirective {
                     note = parse_value(note_)?;
                     continue;
                 }
-            } else if item.has_name(sym::parent_label) && parent_label.is_none() {
+            } else if item.has_name(sym::parent_label)
+                && parent_label.is_none()
+                && !is_diagnostic_namespace_variant
+            {
                 if let Some(parent_label_) = item.value_str() {
                     parent_label = parse_value(parent_label_)?;
                     continue;
@@ -401,15 +410,30 @@ impl<'tcx> OnUnimplementedDirective {
                 && message.is_none()
                 && label.is_none()
                 && note.is_none()
+                && !is_diagnostic_namespace_variant
+            // FIXME(diagnostic_namespace): disallow filters for now
             {
                 if let Some(items) = item.meta_item_list() {
-                    match Self::parse(tcx, item_def_id, &items, item.span(), false) {
-                        Ok(subcommand) => subcommands.push(subcommand),
+                    match Self::parse(
+                        tcx,
+                        item_def_id,
+                        &items,
+                        item.span(),
+                        false,
+                        is_diagnostic_namespace_variant,
+                    ) {
+                        Ok(Some(subcommand)) => subcommands.push(subcommand),
+                        Ok(None) => bug!(
+                            "This cannot happen for now as we only reach that if `is_diagnostic_namespace_variant` is false"
+                        ),
                         Err(reported) => errored = Some(reported),
                     };
                     continue;
                 }
-            } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+            } else if item.has_name(sym::append_const_msg)
+                && append_const_msg.is_none()
+                && !is_diagnostic_namespace_variant
+            {
                 if let Some(msg) = item.value_str() {
                     append_const_msg = Some(AppendConstMessage::Custom(msg));
                     continue;
@@ -419,14 +443,23 @@ impl<'tcx> OnUnimplementedDirective {
                 }
             }
 
-            // nothing found
-            tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+            if is_diagnostic_namespace_variant {
+                tcx.emit_spanned_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+                    vec![item.span()],
+                    NoValueInOnUnimplementedLint,
+                );
+            } else {
+                // nothing found
+                tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+            }
         }
 
         if let Some(reported) = errored {
-            Err(reported)
+            if is_diagnostic_namespace_variant { Ok(None) } else { Err(reported) }
         } else {
-            Ok(OnUnimplementedDirective {
+            Ok(Some(OnUnimplementedDirective {
                 condition,
                 subcommands,
                 message,
@@ -434,32 +467,58 @@ impl<'tcx> OnUnimplementedDirective {
                 note,
                 parent_label,
                 append_const_msg,
-            })
+            }))
         }
     }
 
     pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
-        let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
+        let mut is_diagnostic_namespace_variant = false;
+        let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| {
+            if tcx.features().diagnostic_namespace {
+                is_diagnostic_namespace_variant = true;
+                tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next()
+            } else {
+                None
+            }
+        }) else {
             return Ok(None);
         };
 
         let result = if let Some(items) = attr.meta_item_list() {
-            Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
+            Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
         } else if let Some(value) = attr.value_str() {
-            Ok(Some(OnUnimplementedDirective {
-                condition: None,
-                message: None,
-                subcommands: vec![],
-                label: Some(OnUnimplementedFormatString::try_parse(
-                    tcx,
-                    item_def_id,
-                    value,
+            if !is_diagnostic_namespace_variant {
+                Ok(Some(OnUnimplementedDirective {
+                    condition: None,
+                    message: None,
+                    subcommands: vec![],
+                    label: Some(OnUnimplementedFormatString::try_parse(
+                        tcx,
+                        item_def_id,
+                        value,
+                        attr.span,
+                    )?),
+                    note: None,
+                    parent_label: None,
+                    append_const_msg: None,
+                }))
+            } else {
+                tcx.emit_spanned_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
                     attr.span,
-                )?),
-                note: None,
-                parent_label: None,
-                append_const_msg: None,
-            }))
+                    NoValueInOnUnimplementedLint,
+                );
+                Ok(None)
+            }
+        } else if is_diagnostic_namespace_variant {
+            tcx.emit_spanned_lint(
+                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+                attr.span,
+                NoValueInOnUnimplementedLint,
+            );
+            Ok(None)
         } else {
             let reported =
                 tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index f1779451bc5..da357dac415 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -560,30 +560,31 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
 
                     let stalled_on = &mut pending_obligation.stalled_on;
 
-                    let mut evaluate =
-                        |c: Const<'tcx>| {
-                            if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                                match self.selcx.infcx.try_const_eval_resolve(
-                                    obligation.param_env,
-                                    unevaluated,
-                                    c.ty(),
-                                    Some(obligation.cause.span),
-                                ) {
-                                    Ok(val) => Ok(val),
-                                    Err(e) => match e {
-                                        ErrorHandled::TooGeneric => {
+                    let mut evaluate = |c: Const<'tcx>| {
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+                            match self.selcx.infcx.try_const_eval_resolve(
+                                obligation.param_env,
+                                unevaluated,
+                                c.ty(),
+                                Some(obligation.cause.span),
+                            ) {
+                                Ok(val) => Ok(val),
+                                Err(e) => {
+                                    match e {
+                                        ErrorHandled::TooGeneric(..) => {
                                             stalled_on.extend(unevaluated.args.iter().filter_map(
                                                 TyOrConstInferVar::maybe_from_generic_arg,
                                             ));
-                                            Err(ErrorHandled::TooGeneric)
                                         }
-                                        _ => Err(e),
-                                    },
+                                        _ => {}
+                                    }
+                                    Err(e)
                                 }
-                            } else {
-                                Ok(c)
                             }
-                        };
+                        } else {
+                            Ok(c)
+                        }
+                    };
 
                     match (evaluate(c1), evaluate(c2)) {
                         (Ok(c1), Ok(c2)) => {
@@ -603,13 +604,14 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 ),
                             }
                         }
-                        (Err(ErrorHandled::Reported(reported)), _)
-                        | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error(
+                        (Err(ErrorHandled::Reported(reported, _)), _)
+                        | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
                             CodeSelectionError(SelectionError::NotConstEvaluatable(
                                 NotConstEvaluatable::Error(reported.into()),
                             )),
                         ),
-                        (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+                        (Err(ErrorHandled::TooGeneric(_)), _)
+                        | (_, Err(ErrorHandled::TooGeneric(_))) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                 ProcessResult::Unchanged
                             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 979498fb6e6..e415d70479e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -13,7 +13,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::DUMMY_SP;
 use smallvec::{smallvec, SmallVec};
 
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct ImpliedOutlivesBounds<'tcx> {
     pub ty: Ty<'tcx>,
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 59f4a22ac75..f2c1243f931 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -6,7 +6,7 @@ use crate::traits::ObligationCtxt;
 use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
 use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct DropckOutlives<'tcx> {
     dropped_ty: Ty<'tcx>,
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0d84fee8309..24d31633850 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -989,9 +989,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 Err(_) => Ok(EvaluatedToErr),
                             }
                         }
-                        (Err(ErrorHandled::Reported(_)), _)
-                        | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr),
-                        (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+                        (Err(ErrorHandled::Reported(..)), _)
+                        | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr),
+                        (Err(ErrorHandled::TooGeneric(..)), _)
+                        | (_, Err(ErrorHandled::TooGeneric(..))) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                 Ok(EvaluatedToAmbig)
                             } else {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 904f1b38740..a03b82305f0 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -36,6 +36,9 @@ fn layout_of<'tcx>(
     let (param_env, ty) = query.into_parts();
     debug!(?ty);
 
+    // Optimization: We convert to RevealAll and convert opaque types in the where bounds
+    // to their hidden types. This reduces overall uncached invocations of `layout_of` and
+    // is thus a small performance improvement.
     let param_env = param_env.with_reveal_all_normalized(tcx);
     let unnormalized_ty = ty;
 
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index e348591ebba..5df068de1f8 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -41,7 +41,12 @@ pub trait HashStableContext {}
 
 pub trait Interner: Sized {
     type AdtDef: Clone + Debug + Hash + Ord;
-    type GenericArgsRef: Clone + DebugWithInfcx<Self> + Hash + Ord;
+    type GenericArgsRef: Clone
+        + DebugWithInfcx<Self>
+        + Hash
+        + Ord
+        + IntoIterator<Item = Self::GenericArg>;
+    type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
     type DefId: Clone + Debug + Hash + Ord;
     type Binder<T>;
     type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 72bd50ace6d..b574cdcc879 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -517,7 +517,21 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
             Int(i) => write!(f, "{i:?}"),
             Uint(u) => write!(f, "{u:?}"),
             Float(float) => write!(f, "{float:?}"),
-            Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, &this.wrap(s)),
+            Adt(d, s) => {
+                write!(f, "{d:?}")?;
+                let mut s = s.clone().into_iter();
+                let first = s.next();
+                match first {
+                    Some(first) => write!(f, "<{:?}", first)?,
+                    None => return Ok(()),
+                };
+
+                for arg in s {
+                    write!(f, ", {:?}", arg)?;
+                }
+
+                write!(f, ">")
+            }
             Foreign(d) => f.debug_tuple_field1_finish("Foreign", d),
             Str => write!(f, "str"),
             Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
diff --git a/config.example.toml b/config.example.toml
index 2e0558c3f1b..f3c2366d674 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -458,7 +458,6 @@ changelog-seen = 2
 # Sets the number of codegen units to build the standard library with,
 # regardless of what the codegen-unit setting for the rest of the compiler is.
 # NOTE: building with anything other than 1 is known to occasionally have bugs.
-# See https://github.com/rust-lang/rust/issues/83600.
 #codegen-units-std = codegen-units
 
 # Whether or not debug assertions are enabled for the compiler and standard library.
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 5965ec2affa..4ef8af9b034 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1015,8 +1015,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// Shortens the deque, keeping the first `len` elements and dropping
     /// the rest.
     ///
-    /// If `len` is greater than the deque's current length, this has no
-    /// effect.
+    /// If `len` is greater or equal to the deque's current length, this has
+    /// no effect.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index fb8d00e8d87..1e2c35bf735 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -177,8 +177,8 @@
 //! These are all flags altering the behavior of the formatter.
 //!
 //! * `+` - This is intended for numeric types and indicates that the sign
-//!         should always be printed. Positive signs are never printed by
-//!         default, and the negative sign is only printed by default for signed values.
+//!         should always be printed. By default only the negative sign of signed values
+//!         is printed, and the sign of positive or unsigned values is omitted.
 //!         This flag indicates that the correct sign (`+` or `-`) should always be printed.
 //! * `-` - Currently not used
 //! * `#` - This flag indicates that the "alternate" form of printing should
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index e43b6ac4039..f435f503fc1 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -144,7 +144,6 @@
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
 #![feature(receiver_trait)]
-#![feature(saturating_int_impl)]
 #![feature(set_ptr_value)]
 #![feature(sized_type_properties)]
 #![feature(slice_from_ptr_range)]
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index 3f19561e1ac..0f767df6063 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -88,15 +88,19 @@ macro_rules! vec {
 ///
 /// A common use for `format!` is concatenation and interpolation of strings.
 /// The same convention is used with [`print!`] and [`write!`] macros,
-/// depending on the intended destination of the string.
+/// depending on the intended destination of the string; all these macros internally use [`format_args!`].
 ///
 /// To convert a single value to a string, use the [`to_string`] method. This
 /// will use the [`Display`] formatting trait.
 ///
+/// To concatenate literals into a `&'static str`, use the [`concat!`] macro.
+///
 /// [`print!`]: ../std/macro.print.html
 /// [`write!`]: core::write
+/// [`format_args!`]: core::format_args
 /// [`to_string`]: crate::string::ToString
 /// [`Display`]: core::fmt::Display
+/// [`concat!`]: core::concat
 ///
 /// # Panics
 ///
@@ -107,11 +111,11 @@ macro_rules! vec {
 /// # Examples
 ///
 /// ```
-/// format!("test");
-/// format!("hello {}", "world!");
-/// format!("x = {}, y = {y}", 10, y = 30);
+/// format!("test");                             // => "test"
+/// format!("hello {}", "world!");               // => "hello world!"
+/// format!("x = {}, y = {val}", 10, val = 30);  // => "x = 10, y = 30"
 /// let (x, y) = (1, 2);
-/// format!("{x} + {y} = 3");
+/// format!("{x} + {y} = 3");                    // => "1 + 2 = 3"
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index c485680f92e..0fb06b16655 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1304,6 +1304,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
     /// ```
     #[stable(feature = "rc_raw", since = "1.17.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn into_raw(this: Self) -> *const T {
         let ptr = Self::as_ptr(&this);
         mem::forget(this);
@@ -1327,6 +1328,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
     /// ```
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn as_ptr(this: &Self) -> *const T {
         let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr);
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index d3b7558440c..c53e9a5dd7a 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1454,6 +1454,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// ```
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn into_raw(this: Self) -> *const T {
         let ptr = Self::as_ptr(&this);
         mem::forget(this);
@@ -1478,6 +1479,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rc_as_ptr", since = "1.45.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn as_ptr(this: &Self) -> *const T {
         let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr);
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index ae7bac0c85f..02331db3341 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1110,8 +1110,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// Shortens the vector, keeping the first `len` elements and dropping
     /// the rest.
     ///
-    /// If `len` is greater than the vector's current length, this has no
-    /// effect.
+    /// If `len` is greater or equal to the vector's current length, this has
+    /// no effect.
     ///
     /// The [`drain`] method can emulate `truncate`, but causes the excess
     /// elements to be returned instead of dropped.
@@ -1258,6 +1258,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_mut_ptr`]: Vec::as_mut_ptr
     /// [`as_ptr`]: Vec::as_ptr
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline]
     pub fn as_ptr(&self) -> *const T {
         // We shadow the slice method of the same name to avoid going through
@@ -1317,6 +1318,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// [`as_mut_ptr`]: Vec::as_mut_ptr
     /// [`as_ptr`]: Vec::as_ptr
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut T {
         // We shadow the slice method of the same name to avoid going through
diff --git a/library/core/primitive_docs/box_into_raw.md b/library/core/primitive_docs/box_into_raw.md
deleted file mode 100644
index 9dd0344c7c7..00000000000
--- a/library/core/primitive_docs/box_into_raw.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/boxed/struct.Box.html#method.into_raw
diff --git a/library/core/primitive_docs/fs_file.md b/library/core/primitive_docs/fs_file.md
deleted file mode 100644
index 4023e340a51..00000000000
--- a/library/core/primitive_docs/fs_file.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/fs/struct.File.html
diff --git a/library/core/primitive_docs/io_bufread.md b/library/core/primitive_docs/io_bufread.md
deleted file mode 100644
index 7beda2cd390..00000000000
--- a/library/core/primitive_docs/io_bufread.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/io/trait.BufRead.html
diff --git a/library/core/primitive_docs/io_read.md b/library/core/primitive_docs/io_read.md
deleted file mode 100644
index b7ecf5e273c..00000000000
--- a/library/core/primitive_docs/io_read.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/io/trait.Read.html
diff --git a/library/core/primitive_docs/io_seek.md b/library/core/primitive_docs/io_seek.md
deleted file mode 100644
index db0274d291c..00000000000
--- a/library/core/primitive_docs/io_seek.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/io/trait.Seek.html
diff --git a/library/core/primitive_docs/io_write.md b/library/core/primitive_docs/io_write.md
deleted file mode 100644
index 92a3b88a79c..00000000000
--- a/library/core/primitive_docs/io_write.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/io/trait.Write.html
diff --git a/library/core/primitive_docs/net_tosocketaddrs.md b/library/core/primitive_docs/net_tosocketaddrs.md
deleted file mode 100644
index 4daa10ddbe2..00000000000
--- a/library/core/primitive_docs/net_tosocketaddrs.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/net/trait.ToSocketAddrs.html
diff --git a/library/core/primitive_docs/process_exit.md b/library/core/primitive_docs/process_exit.md
deleted file mode 100644
index cae34d12d52..00000000000
--- a/library/core/primitive_docs/process_exit.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/process/fn.exit.html
diff --git a/library/core/primitive_docs/string_string.md b/library/core/primitive_docs/string_string.md
deleted file mode 100644
index 303dc07b185..00000000000
--- a/library/core/primitive_docs/string_string.md
+++ /dev/null
@@ -1 +0,0 @@
-../std/string/struct.String.html
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 5378b210e67..cc872a5343d 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -3,7 +3,7 @@
 //! suggestions from rustc if you get anything slightly wrong in here, and overall
 //! helps with clarity as we're also referring to `char` intentionally in here.
 
-use crate::fmt;
+use crate::fmt::{self, Write};
 use crate::mem::transmute;
 
 /// One of the 128 Unicode characters from U+0000 through U+007F,
@@ -54,7 +54,7 @@ use crate::mem::transmute;
 /// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf
 /// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf
 /// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[unstable(feature = "ascii_char", issue = "110998")]
 #[repr(u8)]
 pub enum AsciiChar {
@@ -563,3 +563,40 @@ impl fmt::Display for AsciiChar {
         <str as fmt::Display>::fmt(self.as_str(), f)
     }
 }
+
+#[unstable(feature = "ascii_char", issue = "110998")]
+impl fmt::Debug for AsciiChar {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        #[inline]
+        fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) {
+            ([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2)
+        }
+
+        let (buf, len) = match self {
+            AsciiChar::Null => backslash(AsciiChar::Digit0),
+            AsciiChar::CharacterTabulation => backslash(AsciiChar::SmallT),
+            AsciiChar::CarriageReturn => backslash(AsciiChar::SmallR),
+            AsciiChar::LineFeed => backslash(AsciiChar::SmallN),
+            AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus),
+            AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe),
+            _ => {
+                let byte = self.to_u8();
+                if !byte.is_ascii_control() {
+                    ([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1)
+                } else {
+                    const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
+
+                    let hi = HEX_DIGITS[usize::from(byte >> 4)];
+                    let lo = HEX_DIGITS[usize::from(byte & 0xf)];
+                    ([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4)
+                }
+            }
+        };
+
+        f.write_char('\'')?;
+        for byte in &buf[..len as usize] {
+            f.write_str(byte.as_str())?;
+        }
+        f.write_char('\'')
+    }
+}
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index e6c793a6516..3b4d99221f2 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -556,6 +556,7 @@ impl<T: ?Sized> Cell<T> {
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
     #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *mut T {
         self.value.get()
     }
@@ -1111,6 +1112,7 @@ impl<T: ?Sized> RefCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub fn as_ptr(&self) -> *mut T {
         self.value.get()
     }
@@ -2105,6 +2107,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn get(&self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
         // #[repr(transparent)]. This exploits std's special status, there is
@@ -2248,6 +2251,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> {
     /// when casting to `&mut T`, and ensure that there are no mutations
     /// or mutable aliases going on when casting to `&T`
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn get(&self) -> *mut T {
         self.value.get()
     }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 6d5133646b5..33226b07e04 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -63,6 +63,11 @@ use self::Ordering::*;
 /// (transitive) impls are not forced to exist, but these requirements apply
 /// whenever they do exist.
 ///
+/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
+/// methods.
+///
 /// ## Derivable
 ///
 /// This trait can be used with `#[derive]`. When `derive`d on structs, two
@@ -250,6 +255,11 @@ pub macro PartialEq($item:item) {
 /// This property cannot be checked by the compiler, and therefore `Eq` implies
 /// [`PartialEq`], and has no extra methods.
 ///
+/// Violating this property is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
+/// methods.
+///
 /// ## Derivable
 ///
 /// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
@@ -659,6 +669,11 @@ impl<T: Clone> Clone for Reverse<T> {
 /// It's easy to accidentally make `cmp` and `partial_cmp` disagree by
 /// deriving some of the traits and manually implementing others.
 ///
+/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
+/// methods.
+///
 /// ## Corollaries
 ///
 /// From the above and the requirements of `PartialOrd`, it follows that `<` defines a strict total order.
@@ -892,6 +907,11 @@ pub macro Ord($item:item) {
 /// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
 /// PartialOrd<V>`.
 ///
+/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
+/// methods.
+///
 /// ## Corollaries
 ///
 /// The following corollaries follow from the above requirements:
@@ -1269,6 +1289,91 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
     max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
 }
 
+/// Compares and sorts two values, returning minimum and maximum.
+///
+/// Returns `[v1, v2]` if the comparison determines them to be equal.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(cmp_minmax)]
+/// use std::cmp;
+///
+/// assert_eq!(cmp::minmax(1, 2), [1, 2]);
+/// assert_eq!(cmp::minmax(2, 2), [2, 2]);
+///
+/// // You can destructure the result using array patterns
+/// let [min, max] = cmp::minmax(42, 17);
+/// assert_eq!(min, 17);
+/// assert_eq!(max, 42);
+/// ```
+#[inline]
+#[must_use]
+#[unstable(feature = "cmp_minmax", issue = "115939")]
+pub fn minmax<T>(v1: T, v2: T) -> [T; 2]
+where
+    T: Ord,
+{
+    if v1 <= v2 { [v1, v2] } else { [v2, v1] }
+}
+
+/// Returns minimum and maximum values with respect to the specified comparison function.
+///
+/// Returns `[v1, v2]` if the comparison determines them to be equal.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(cmp_minmax)]
+/// use std::cmp;
+///
+/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]);
+/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]);
+///
+/// // You can destructure the result using array patterns
+/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
+/// assert_eq!(min, 17);
+/// assert_eq!(max, -42);
+/// ```
+#[inline]
+#[must_use]
+#[unstable(feature = "cmp_minmax", issue = "115939")]
+pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
+where
+    F: FnOnce(&T, &T) -> Ordering,
+{
+    if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] }
+}
+
+/// Returns minimum and maximum values with respect to the specified key function.
+///
+/// Returns `[v1, v2]` if the comparison determines them to be equal.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(cmp_minmax)]
+/// use std::cmp;
+///
+/// assert_eq!(cmp::minmax_by_key(-2, 1, |x: &i32| x.abs()), [1, -2]);
+/// assert_eq!(cmp::minmax_by_key(-2, 2, |x: &i32| x.abs()), [-2, 2]);
+///
+/// // You can destructure the result using array patterns
+/// let [min, max] = cmp::minmax_by_key(-42, 17, |x: &i32| x.abs());
+/// assert_eq!(min, 17);
+/// assert_eq!(max, -42);
+/// ```
+#[inline]
+#[must_use]
+#[unstable(feature = "cmp_minmax", issue = "115939")]
+pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2]
+where
+    F: FnMut(&T) -> K,
+    K: Ord,
+{
+    minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+}
+
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
 mod impls {
     use crate::cmp::Ordering::{self, Equal, Greater, Less};
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 163a65c909e..7e4077db935 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -511,6 +511,7 @@ impl CStr {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *const c_char {
         self.inner.as_ptr()
     }
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index d2c9f980042..9227248041e 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -40,6 +40,14 @@ impl fmt::Write for PadAdapter<'_, '_> {
 
         Ok(())
     }
+
+    fn write_char(&mut self, c: char) -> fmt::Result {
+        if self.state.on_newline {
+            self.buf.write_str("    ")?;
+        }
+        self.state.on_newline = c == '\n';
+        self.buf.write_char(c)
+    }
 }
 
 /// A struct to help with [`fmt::Debug`](Debug) implementations.
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 9ce6093f1d1..8204b3855bd 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -188,8 +188,28 @@ pub trait Write {
     /// assert_eq!(&buf, "world");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn write_fmt(mut self: &mut Self, args: Arguments<'_>) -> Result {
-        write(&mut self, args)
+    fn write_fmt(&mut self, args: Arguments<'_>) -> Result {
+        // We use a specialization for `Sized` types to avoid an indirection
+        // through `&mut self`
+        trait SpecWriteFmt {
+            fn spec_write_fmt(self, args: Arguments<'_>) -> Result;
+        }
+
+        impl<W: Write + ?Sized> SpecWriteFmt for &mut W {
+            #[inline]
+            default fn spec_write_fmt(mut self, args: Arguments<'_>) -> Result {
+                write(&mut self, args)
+            }
+        }
+
+        impl<W: Write> SpecWriteFmt for &mut W {
+            #[inline]
+            fn spec_write_fmt(self, args: Arguments<'_>) -> Result {
+                write(self, args)
+            }
+        }
+
+        self.spec_write_fmt(args)
     }
 }
 
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 794a57f0922..35b757dc1ee 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -153,6 +153,11 @@ mod sip;
 /// Thankfully, you won't need to worry about upholding this property when
 /// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`.
 ///
+/// Violating this property is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
+/// methods.
+///
 /// ## Prefix collisions
 ///
 /// Implementations of `hash` should ensure that the data they
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 75c104ce2fa..4bf3da07354 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -175,34 +175,27 @@ pub fn spin_loop() {
         unsafe { crate::arch::x86_64::_mm_pause() };
     }
 
-    // RISC-V platform spin loop hint implementation
+    #[cfg(target_arch = "riscv32")]
     {
-        // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different
-        // modules in `core::arch`.
-        // In this case, here we call `pause` function in each core arch module.
-        #[cfg(target_arch = "riscv32")]
-        {
-            crate::arch::riscv32::pause();
-        }
-        #[cfg(target_arch = "riscv64")]
-        {
-            crate::arch::riscv64::pause();
-        }
+        crate::arch::riscv32::pause();
     }
 
-    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
+    #[cfg(target_arch = "riscv64")]
     {
-        #[cfg(target_arch = "aarch64")]
-        {
-            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
-            unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
-        }
-        #[cfg(target_arch = "arm")]
-        {
-            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
-            // with support for the v6 feature.
-            unsafe { crate::arch::arm::__yield() };
-        }
+        crate::arch::riscv64::pause();
+    }
+
+    #[cfg(target_arch = "aarch64")]
+    {
+        // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
+        unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
+    }
+
+    #[cfg(all(target_arch = "arm", target_feature = "v6"))]
+    {
+        // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
+        // with support for the v6 feature.
+        unsafe { crate::arch::arm::__yield() };
     }
 }
 
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 44feb0a5638..0e03d0c2d4e 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -1,6 +1,7 @@
 use crate::ascii::Char as AsciiChar;
 use crate::convert::TryFrom;
 use crate::mem;
+use crate::net::{Ipv4Addr, Ipv6Addr};
 use crate::num::NonZeroUsize;
 use crate::ops::{self, Try};
 
@@ -15,7 +16,7 @@ macro_rules! unsafe_impl_trusted_step {
         unsafe impl TrustedStep for $type {}
     )*};
 }
-unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
+unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize Ipv4Addr Ipv6Addr];
 
 /// Objects that have a notion of *successor* and *predecessor* operations.
 ///
@@ -527,6 +528,70 @@ impl Step for AsciiChar {
     }
 }
 
+#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+impl Step for Ipv4Addr {
+    #[inline]
+    fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> Option<usize> {
+        u32::steps_between(&start.to_bits(), &end.to_bits())
+    }
+
+    #[inline]
+    fn forward_checked(start: Ipv4Addr, count: usize) -> Option<Ipv4Addr> {
+        u32::forward_checked(start.to_bits(), count).map(Ipv4Addr::from_bits)
+    }
+
+    #[inline]
+    fn backward_checked(start: Ipv4Addr, count: usize) -> Option<Ipv4Addr> {
+        u32::backward_checked(start.to_bits(), count).map(Ipv4Addr::from_bits)
+    }
+
+    #[inline]
+    unsafe fn forward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr {
+        // SAFETY: Since u32 and Ipv4Addr are losslessly convertible,
+        //   this is as safe as the u32 version.
+        Ipv4Addr::from_bits(unsafe { u32::forward_unchecked(start.to_bits(), count) })
+    }
+
+    #[inline]
+    unsafe fn backward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr {
+        // SAFETY: Since u32 and Ipv4Addr are losslessly convertible,
+        //   this is as safe as the u32 version.
+        Ipv4Addr::from_bits(unsafe { u32::backward_unchecked(start.to_bits(), count) })
+    }
+}
+
+#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+impl Step for Ipv6Addr {
+    #[inline]
+    fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> Option<usize> {
+        u128::steps_between(&start.to_bits(), &end.to_bits())
+    }
+
+    #[inline]
+    fn forward_checked(start: Ipv6Addr, count: usize) -> Option<Ipv6Addr> {
+        u128::forward_checked(start.to_bits(), count).map(Ipv6Addr::from_bits)
+    }
+
+    #[inline]
+    fn backward_checked(start: Ipv6Addr, count: usize) -> Option<Ipv6Addr> {
+        u128::backward_checked(start.to_bits(), count).map(Ipv6Addr::from_bits)
+    }
+
+    #[inline]
+    unsafe fn forward_unchecked(start: Ipv6Addr, count: usize) -> Ipv6Addr {
+        // SAFETY: Since u128 and Ipv6Addr are losslessly convertible,
+        //   this is as safe as the u128 version.
+        Ipv6Addr::from_bits(unsafe { u128::forward_unchecked(start.to_bits(), count) })
+    }
+
+    #[inline]
+    unsafe fn backward_unchecked(start: Ipv6Addr, count: usize) -> Ipv6Addr {
+        // SAFETY: Since u128 and Ipv6Addr are losslessly convertible,
+        //   this is as safe as the u128 version.
+        Ipv6Addr::from_bits(unsafe { u128::backward_unchecked(start.to_bits(), count) })
+    }
+}
+
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -766,6 +831,15 @@ impl<A: Step> Iterator for ops::Range<A> {
     }
 
     #[inline]
+    fn count(self) -> usize {
+        if self.start < self.end {
+            Step::steps_between(&self.start, &self.end).expect("count overflowed usize")
+        } else {
+            0
+        }
+    }
+
+    #[inline]
     fn nth(&mut self, n: usize) -> Option<A> {
         self.spec_nth(n)
     }
@@ -1163,6 +1237,17 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
     }
 
     #[inline]
+    fn count(self) -> usize {
+        if self.is_empty() {
+            return 0;
+        }
+
+        Step::steps_between(&self.start, &self.end)
+            .and_then(|steps| steps.checked_add(1))
+            .expect("count overflowed usize")
+    }
+
+    #[inline]
     fn nth(&mut self, n: usize) -> Option<A> {
         if self.is_empty() {
             return None;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 7c08d1703cc..b5458e667ed 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -166,7 +166,6 @@
 #![feature(const_slice_split_at_mut)]
 #![feature(const_str_from_utf8_unchecked_mut)]
 #![feature(const_swap)]
-#![feature(const_transmute_copy)]
 #![feature(const_try)]
 #![feature(const_type_id)]
 #![feature(const_type_name)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 46628bcea00..646100fe27b 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1044,7 +1044,7 @@ pub(crate) mod builtin {
     /// expression of type `&'static str` which represents all of the literals
     /// concatenated left-to-right.
     ///
-    /// Integer and floating point literals are stringified in order to be
+    /// Integer and floating point literals are [stringified](core::stringify) in order to be
     /// concatenated.
     ///
     /// # Examples
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index bc701d97bbb..d7abc9a0e23 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1051,7 +1051,7 @@ pub const fn copy<T: Copy>(x: &T) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
+#[rustc_const_stable(feature = "const_transmute_copy", since = "CURRENT_RUSTC_VERSION")]
 pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst {
     assert!(
         size_of::<Src>() >= size_of::<Dst>(),
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 95dcaf5dd73..4232319fecb 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -44,11 +44,10 @@ mod uint_macros; // import uint_impl!
 mod error;
 mod int_log10;
 mod nonzero;
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
 mod saturating;
 mod wrapping;
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 pub use saturating::Saturating;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use wrapping::Wrapping;
diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs
index e9f794e7d62..5757e7498ad 100644
--- a/library/core/src/num/saturating.rs
+++ b/library/core/src/num/saturating.rs
@@ -4,7 +4,7 @@ use crate::fmt;
 use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign};
 use crate::ops::{BitXor, BitXorAssign, Div, DivAssign};
 use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign};
-use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
+use crate::ops::{Sub, SubAssign};
 
 /// Provides intentionally-saturating arithmetic on `T`.
 ///
@@ -24,7 +24,6 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
 /// # Examples
 ///
 /// ```
-/// #![feature(saturating_int_impl)]
 /// use std::num::Saturating;
 ///
 /// let max = Saturating(u32::MAX);
@@ -32,181 +31,186 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
 ///
 /// assert_eq!(u32::MAX, (max + one).0);
 /// ```
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
 #[repr(transparent)]
 #[rustc_diagnostic_item = "Saturating"]
-pub struct Saturating<T>(#[unstable(feature = "saturating_int_impl", issue = "87920")] pub T);
+pub struct Saturating<T>(
+    #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub T,
+);
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 impl<T: fmt::Debug> fmt::Debug for Saturating<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 impl<T: fmt::Display> fmt::Display for Saturating<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 impl<T: fmt::Binary> fmt::Binary for Saturating<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 impl<T: fmt::Octal> fmt::Octal for Saturating<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 impl<T: fmt::LowerHex> fmt::LowerHex for Saturating<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
 }
-#[allow(unused_macros)]
-macro_rules! sh_impl_signed {
-    ($t:ident, $f:ident) => {
-        // FIXME what is the correct implementation here? see discussion https://github.com/rust-lang/rust/pull/87921#discussion_r695870065
-        //
-        // #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        // impl Shl<$f> for Saturating<$t> {
-        //     type Output = Saturating<$t>;
-        //
-        //     #[inline]
-        //     fn shl(self, other: $f) -> Saturating<$t> {
-        //         if other < 0 {
-        //             Saturating(self.0.shr((-other & self::shift_max::$t as $f) as u32))
-        //         } else {
-        //             Saturating(self.0.shl((other & self::shift_max::$t as $f) as u32))
-        //         }
-        //     }
-        // }
-        // forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f,
-        // #[unstable(feature = "saturating_int_impl", issue = "87920")] }
-        //
-        // #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        // impl ShlAssign<$f> for Saturating<$t> {
-        //     #[inline]
-        //     fn shl_assign(&mut self, other: $f) {
-        //         *self = *self << other;
-        //     }
-        // }
-        // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f }
-
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        impl Shr<$f> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn shr(self, other: $f) -> Saturating<$t> {
-                if other < 0 {
-                    Saturating(self.0.shl((-other & self::shift_max::$t as $f) as u32))
-                } else {
-                    Saturating(self.0.shr((other & self::shift_max::$t as $f) as u32))
-                }
-            }
-        }
-        forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f,
-        #[unstable(feature = "saturating_int_impl", issue = "87920")] }
-
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        impl ShrAssign<$f> for Saturating<$t> {
-            #[inline]
-            fn shr_assign(&mut self, other: $f) {
-                *self = *self >> other;
-            }
-        }
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f }
-    };
-}
-
-macro_rules! sh_impl_unsigned {
-    ($t:ident, $f:ident) => {
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        impl Shl<$f> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn shl(self, other: $f) -> Saturating<$t> {
-                Saturating(self.0.wrapping_shl(other as u32))
-            }
-        }
-        forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f,
-        #[unstable(feature = "saturating_int_impl", issue = "87920")] }
-
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        impl ShlAssign<$f> for Saturating<$t> {
-            #[inline]
-            fn shl_assign(&mut self, other: $f) {
-                *self = *self << other;
-            }
-        }
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f }
-
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        impl Shr<$f> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn shr(self, other: $f) -> Saturating<$t> {
-                Saturating(self.0.wrapping_shr(other as u32))
-            }
-        }
-        forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f,
-        #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
-        impl ShrAssign<$f> for Saturating<$t> {
-            #[inline]
-            fn shr_assign(&mut self, other: $f) {
-                *self = *self >> other;
-            }
-        }
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f }
-    };
-}
-
-// FIXME (#23545): uncomment the remaining impls
-macro_rules! sh_impl_all {
-    ($($t:ident)*) => ($(
-        //sh_impl_unsigned! { $t, u8 }
-        //sh_impl_unsigned! { $t, u16 }
-        //sh_impl_unsigned! { $t, u32 }
-        //sh_impl_unsigned! { $t, u64 }
-        //sh_impl_unsigned! { $t, u128 }
-        sh_impl_unsigned! { $t, usize }
-
-        //sh_impl_signed! { $t, i8 }
-        //sh_impl_signed! { $t, i16 }
-        //sh_impl_signed! { $t, i32 }
-        //sh_impl_signed! { $t, i64 }
-        //sh_impl_signed! { $t, i128 }
-        //sh_impl_signed! { $t, isize }
-    )*)
-}
-
-sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
+// FIXME the correct implementation is not clear. Waiting for a real world use case at https://github.com/rust-lang/libs-team/issues/230
+//
+// #[allow(unused_macros)]
+// macro_rules! sh_impl_signed {
+//     ($t:ident, $f:ident) => {
+//         // FIXME what is the correct implementation here? see discussion https://github.com/rust-lang/rust/pull/87921#discussion_r695870065
+//         //
+//         // #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         // impl Shl<$f> for Saturating<$t> {
+//         //     type Output = Saturating<$t>;
+//         //
+//         //     #[inline]
+//         //     fn shl(self, other: $f) -> Saturating<$t> {
+//         //         if other < 0 {
+//         //             Saturating(self.0.shr((-other & self::shift_max::$t as $f) as u32))
+//         //         } else {
+//         //             Saturating(self.0.shl((other & self::shift_max::$t as $f) as u32))
+//         //         }
+//         //     }
+//         // }
+//         // forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f,
+//         // #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+//         //
+//         // #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         // impl ShlAssign<$f> for Saturating<$t> {
+//         //     #[inline]
+//         //     fn shl_assign(&mut self, other: $f) {
+//         //         *self = *self << other;
+//         //     }
+//         // }
+//         // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f }
+//
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         impl Shr<$f> for Saturating<$t> {
+//             type Output = Saturating<$t>;
+//
+//             #[inline]
+//             fn shr(self, other: $f) -> Saturating<$t> {
+//                 if other < 0 {
+//                     Saturating(self.0.shl((-other & self::shift_max::$t as $f) as u32))
+//                 } else {
+//                     Saturating(self.0.shr((other & self::shift_max::$t as $f) as u32))
+//                 }
+//             }
+//         }
+//         forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f,
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+//
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         impl ShrAssign<$f> for Saturating<$t> {
+//             #[inline]
+//             fn shr_assign(&mut self, other: $f) {
+//                 *self = *self >> other;
+//             }
+//         }
+//         forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f }
+//     };
+// }
+//
+// macro_rules! sh_impl_unsigned {
+//     ($t:ident, $f:ident) => {
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         impl Shl<$f> for Saturating<$t> {
+//             type Output = Saturating<$t>;
+//
+//             #[inline]
+//             fn shl(self, other: $f) -> Saturating<$t> {
+//                 Saturating(self.0.wrapping_shl(other as u32))
+//             }
+//         }
+//         forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f,
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+//
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         impl ShlAssign<$f> for Saturating<$t> {
+//             #[inline]
+//             fn shl_assign(&mut self, other: $f) {
+//                 *self = *self << other;
+//             }
+//         }
+//         forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f }
+//
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         impl Shr<$f> for Saturating<$t> {
+//             type Output = Saturating<$t>;
+//
+//             #[inline]
+//             fn shr(self, other: $f) -> Saturating<$t> {
+//                 Saturating(self.0.wrapping_shr(other as u32))
+//             }
+//         }
+//         forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f,
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+//
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")]
+//         impl ShrAssign<$f> for Saturating<$t> {
+//             #[inline]
+//             fn shr_assign(&mut self, other: $f) {
+//                 *self = *self >> other;
+//             }
+//         }
+//         forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f }
+//     };
+// }
+//
+// // FIXME (#23545): uncomment the remaining impls
+// macro_rules! sh_impl_all {
+//     ($($t:ident)*) => ($(
+//         //sh_impl_unsigned! { $t, u8 }
+//         //sh_impl_unsigned! { $t, u16 }
+//         //sh_impl_unsigned! { $t, u32 }
+//         //sh_impl_unsigned! { $t, u64 }
+//         //sh_impl_unsigned! { $t, u128 }
+//         sh_impl_unsigned! { $t, usize }
+//
+//         //sh_impl_signed! { $t, i8 }
+//         //sh_impl_signed! { $t, i16 }
+//         //sh_impl_signed! { $t, i32 }
+//         //sh_impl_signed! { $t, i64 }
+//         //sh_impl_signed! { $t, i128 }
+//         //sh_impl_signed! { $t, isize }
+//     )*)
+// }
+//
+// sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 
 // FIXME(30524): impl Op<T> for Saturating<T>, impl OpAssign<T> for Saturating<T>
 macro_rules! saturating_impl {
     ($($t:ty)*) => ($(
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Add for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -216,9 +220,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl AddAssign for Saturating<$t> {
             #[inline]
             fn add_assign(&mut self, other: Saturating<$t>) {
@@ -227,7 +231,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl AddAssign<$t> for Saturating<$t> {
             #[inline]
             fn add_assign(&mut self, other: $t) {
@@ -236,7 +240,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Sub for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -246,9 +250,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl SubAssign for Saturating<$t> {
             #[inline]
             fn sub_assign(&mut self, other: Saturating<$t>) {
@@ -257,7 +261,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl SubAssign<$t> for Saturating<$t> {
             #[inline]
             fn sub_assign(&mut self, other: $t) {
@@ -266,7 +270,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Mul for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -276,9 +280,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl MulAssign for Saturating<$t> {
             #[inline]
             fn mul_assign(&mut self, other: Saturating<$t>) {
@@ -287,7 +291,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl MulAssign<$t> for Saturating<$t> {
             #[inline]
             fn mul_assign(&mut self, other: $t) {
@@ -301,7 +305,6 @@ macro_rules! saturating_impl {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(saturating_int_impl)]
         /// use std::num::Saturating;
         ///
         #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / Saturating(2));")]
@@ -310,12 +313,11 @@ macro_rules! saturating_impl {
         /// ```
         ///
         /// ```should_panic
-        /// #![feature(saturating_int_impl)]
         /// use std::num::Saturating;
         ///
         #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")]
         /// ```
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Div for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -325,10 +327,10 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl DivAssign for Saturating<$t> {
             #[inline]
             fn div_assign(&mut self, other: Saturating<$t>) {
@@ -337,7 +339,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl DivAssign<$t> for Saturating<$t> {
             #[inline]
             fn div_assign(&mut self, other: $t) {
@@ -346,7 +348,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Rem for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -356,9 +358,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl RemAssign for Saturating<$t> {
             #[inline]
             fn rem_assign(&mut self, other: Saturating<$t>) {
@@ -367,7 +369,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl RemAssign<$t> for Saturating<$t> {
             #[inline]
             fn rem_assign(&mut self, other: $t) {
@@ -376,7 +378,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Not for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -386,9 +388,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_unop! { impl Not, not for Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitXor for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -398,9 +400,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitXorAssign for Saturating<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: Saturating<$t>) {
@@ -409,7 +411,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitXorAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: $t) {
@@ -418,7 +420,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitOr for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -428,9 +430,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitOrAssign for Saturating<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: Saturating<$t>) {
@@ -439,7 +441,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitOrAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: $t) {
@@ -448,7 +450,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitAnd for Saturating<$t> {
             type Output = Saturating<$t>;
 
@@ -458,9 +460,9 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitAndAssign for Saturating<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: Saturating<$t>) {
@@ -469,7 +471,7 @@ macro_rules! saturating_impl {
         }
         forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")]
         impl BitAndAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: $t) {
@@ -493,12 +495,11 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::MIN, Saturating(", stringify!($t), "::MIN));")]
             /// ```
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const MIN: Self = Self(<$t>::MIN);
 
             /// Returns the largest value that can be represented by this integer type.
@@ -508,12 +509,11 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::MAX, Saturating(", stringify!($t), "::MAX));")]
             /// ```
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const MAX: Self = Self(<$t>::MAX);
 
             /// Returns the size of this integer type in bits.
@@ -523,12 +523,11 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::BITS, ", stringify!($t), "::BITS);")]
             /// ```
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const BITS: u32 = <$t>::BITS;
 
             /// Returns the number of ones in the binary representation of `self`.
@@ -538,7 +537,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(0b01001100", stringify!($t), ");")]
@@ -550,7 +548,8 @@ macro_rules! saturating_int_impl {
             #[doc(alias = "popcnt")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn count_ones(self) -> u32 {
                 self.0.count_ones()
             }
@@ -562,7 +561,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(Saturating(!0", stringify!($t), ").count_zeros(), 0);")]
@@ -570,7 +568,8 @@ macro_rules! saturating_int_impl {
             #[inline]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn count_zeros(self) -> u32 {
                 self.0.count_zeros()
             }
@@ -582,7 +581,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(0b0101000", stringify!($t), ");")]
@@ -592,7 +590,8 @@ macro_rules! saturating_int_impl {
             #[inline]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn trailing_zeros(self) -> u32 {
                 self.0.trailing_zeros()
             }
@@ -609,7 +608,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             /// let n: Saturating<i64> = Saturating(0x0123456789ABCDEF);
@@ -620,7 +618,8 @@ macro_rules! saturating_int_impl {
             #[inline]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn rotate_left(self, n: u32) -> Self {
                 Saturating(self.0.rotate_left(n))
             }
@@ -637,7 +636,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             /// let n: Saturating<i64> = Saturating(0x0123456789ABCDEF);
@@ -648,7 +646,8 @@ macro_rules! saturating_int_impl {
             #[inline]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn rotate_right(self, n: u32) -> Self {
                 Saturating(self.0.rotate_right(n))
             }
@@ -660,7 +659,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             /// let n: Saturating<i16> = Saturating(0b0000000_01010101);
@@ -674,7 +672,8 @@ macro_rules! saturating_int_impl {
             #[inline]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn swap_bytes(self) -> Self {
                 Saturating(self.0.swap_bytes())
             }
@@ -689,7 +688,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             /// let n = Saturating(0b0000000_01010101i16);
@@ -701,8 +699,8 @@ macro_rules! saturating_int_impl {
             /// assert_eq!(m, Saturating(-22016));
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
-            #[rustc_const_unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             pub const fn reverse_bits(self) -> Self {
@@ -719,7 +717,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")]
@@ -732,7 +729,8 @@ macro_rules! saturating_int_impl {
             /// ```
             #[inline]
             #[must_use]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn from_be(x: Self) -> Self {
                 Saturating(<$t>::from_be(x.0))
             }
@@ -747,7 +745,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")]
@@ -760,7 +757,8 @@ macro_rules! saturating_int_impl {
             /// ```
             #[inline]
             #[must_use]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn from_le(x: Self) -> Self {
                 Saturating(<$t>::from_le(x.0))
             }
@@ -775,7 +773,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")]
@@ -787,7 +784,8 @@ macro_rules! saturating_int_impl {
             /// }
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             pub const fn to_be(self) -> Self {
@@ -804,7 +802,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")]
@@ -816,7 +813,8 @@ macro_rules! saturating_int_impl {
             /// }
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             pub const fn to_le(self) -> Self {
@@ -830,7 +828,6 @@ macro_rules! saturating_int_impl {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(Saturating(3", stringify!($t), ").pow(4), Saturating(81));")]
@@ -839,17 +836,17 @@ macro_rules! saturating_int_impl {
             /// Results that are too large are saturated:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             /// assert_eq!(Saturating(3i8).pow(5), Saturating(127));
             /// assert_eq!(Saturating(3i8).pow(6), Saturating(127));
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            pub fn pow(self, exp: u32) -> Self {
+            pub const fn pow(self, exp: u32) -> Self {
                 Saturating(self.0.saturating_pow(exp))
             }
         }
@@ -868,7 +865,6 @@ macro_rules! saturating_int_impl_signed {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(", stringify!($t), "::MAX >> 2);")]
@@ -876,7 +872,8 @@ macro_rules! saturating_int_impl_signed {
             /// assert_eq!(n.leading_zeros(), 3);
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             pub const fn leading_zeros(self) -> u32 {
@@ -891,7 +888,6 @@ macro_rules! saturating_int_impl_signed {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(Saturating(100", stringify!($t), ").abs(), Saturating(100));")]
@@ -901,10 +897,11 @@ macro_rules! saturating_int_impl_signed {
             #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN).abs(), Saturating(", stringify!($t), "::MAX));")]
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            pub fn abs(self) -> Saturating<$t> {
+            pub const fn abs(self) -> Saturating<$t> {
                 Saturating(self.0.saturating_abs())
             }
 
@@ -919,7 +916,6 @@ macro_rules! saturating_int_impl_signed {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert_eq!(Saturating(10", stringify!($t), ").signum(), Saturating(1));")]
@@ -927,10 +923,11 @@ macro_rules! saturating_int_impl_signed {
             #[doc = concat!("assert_eq!(Saturating(-10", stringify!($t), ").signum(), Saturating(-1));")]
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            pub fn signum(self) -> Saturating<$t> {
+            pub const fn signum(self) -> Saturating<$t> {
                 Saturating(self.0.signum())
             }
 
@@ -942,7 +939,6 @@ macro_rules! saturating_int_impl_signed {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert!(Saturating(10", stringify!($t), ").is_positive());")]
@@ -950,7 +946,8 @@ macro_rules! saturating_int_impl_signed {
             /// ```
             #[must_use]
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn is_positive(self) -> bool {
                 self.0.is_positive()
             }
@@ -963,7 +960,6 @@ macro_rules! saturating_int_impl_signed {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert!(Saturating(-10", stringify!($t), ").is_negative());")]
@@ -971,13 +967,14 @@ macro_rules! saturating_int_impl_signed {
             /// ```
             #[must_use]
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             pub const fn is_negative(self) -> bool {
                 self.0.is_negative()
             }
         }
 
-        #[unstable(feature = "saturating_int_impl", issue = "87920")]
+        #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
         impl Neg for Saturating<$t> {
             type Output = Self;
             #[inline]
@@ -986,7 +983,7 @@ macro_rules! saturating_int_impl_signed {
             }
         }
         forward_ref_unop! { impl Neg, neg for Saturating<$t>,
-                #[unstable(feature = "saturating_int_impl", issue = "87920")] }
+                #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] }
     )*)
 }
 
@@ -1002,7 +999,6 @@ macro_rules! saturating_int_impl_unsigned {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("let n = Saturating(", stringify!($t), "::MAX >> 2);")]
@@ -1010,7 +1006,8 @@ macro_rules! saturating_int_impl_unsigned {
             /// assert_eq!(n.leading_zeros(), 2);
             /// ```
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             pub const fn leading_zeros(self) -> u32 {
@@ -1024,7 +1021,6 @@ macro_rules! saturating_int_impl_unsigned {
             /// Basic usage:
             ///
             /// ```
-            /// #![feature(saturating_int_impl)]
             /// use std::num::Saturating;
             ///
             #[doc = concat!("assert!(Saturating(16", stringify!($t), ").is_power_of_two());")]
@@ -1032,8 +1028,9 @@ macro_rules! saturating_int_impl_unsigned {
             /// ```
             #[must_use]
             #[inline]
-            #[unstable(feature = "saturating_int_impl", issue = "87920")]
-            pub fn is_power_of_two(self) -> bool {
+            #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
+            pub const fn is_power_of_two(self) -> bool {
                 self.0.is_power_of_two()
             }
 
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 08c35b6dac3..911761c6edd 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -14,6 +14,11 @@
 /// For similar reasons, **this trait should never fail**. Failure during
 /// dereferencing can be extremely confusing when `Deref` is invoked implicitly.
 ///
+/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this
+/// method.
+///
 /// # More on `Deref` coercion
 ///
 /// If `T` implements `Deref<Target = U>`, and `x` is a value of type `T`, then:
@@ -114,6 +119,11 @@ impl<T: ?Sized> Deref for &mut T {
 /// dereferencing can be extremely confusing when `DerefMut` is invoked
 /// implicitly.
 ///
+/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this
+/// method.
+///
 /// # More on `Deref` coercion
 ///
 /// If `T` implements `DerefMut<Target = U>`, and `x` is a value of type `T`,
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 80289ca08c3..fd5fe5a04f4 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1,6 +1,3 @@
-// `library/{std,core}/src/primitive_docs.rs` should have the same contents.
-// These are different files so that relative links work properly without
-// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
 #[rustc_doc_primitive = "bool"]
 #[doc(alias = "true")]
 #[doc(alias = "false")]
@@ -106,7 +103,7 @@ mod prim_bool {}
 /// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
 ///
 /// [`u32`]: prim@u32
-#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))]
+/// [`exit`]: ../std/process/fn.exit.html
 ///
 /// # `!` and generics
 ///
@@ -191,7 +188,7 @@ mod prim_bool {}
 /// because `!` coerces to `Result<!, ConnectionError>` automatically.
 ///
 /// [`String::from_str`]: str::FromStr::from_str
-#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))]
+/// [`String`]: ../std/string/struct.String.html
 /// [`FromStr`]: str::FromStr
 ///
 /// # `!` and traits
@@ -267,7 +264,7 @@ mod prim_bool {}
 /// `impl` for this which simply panics, but the same is true for any type (we could `impl
 /// Default` for (eg.) [`File`] by just making [`default()`] panic.)
 ///
-#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))]
+/// [`File`]: ../std/fs/struct.File.html
 /// [`Debug`]: fmt::Debug
 /// [`default()`]: Default::default
 ///
@@ -355,7 +352,7 @@ mod prim_never {}
 /// assert_eq!(5, s.len() * std::mem::size_of::<u8>());
 /// ```
 ///
-#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))]
+/// [`String`]: ../std/string/struct.String.html
 ///
 /// As always, remember that a human intuition for 'character' might not map to
 /// Unicode's definitions. For example, despite looking similar, the 'é'
@@ -572,7 +569,7 @@ impl Copy for () {
 /// [`null_mut`]: ptr::null_mut
 /// [`is_null`]: pointer::is_null
 /// [`offset`]: pointer::offset
-#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))]
+/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw
 /// [`write`]: ptr::write
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_pointer {}
@@ -612,7 +609,7 @@ mod prim_pointer {}
 /// statically generated up to size 32.
 ///
 /// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple`
-/// is a homogenous [prim@tuple] of appropriate length.
+/// is a homogeneous [prim@tuple] of appropriate length.
 ///
 /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
 /// an array. Indeed, this provides most of the API for working with arrays.
@@ -676,7 +673,7 @@ mod prim_pointer {}
 /// move_away(roa);
 /// ```
 ///
-/// Arrays can be created from homogenous tuples of appropriate length:
+/// Arrays can be created from homogeneous tuples of appropriate length:
 ///
 /// ```
 /// let tuple: (u32, u32, u32) = (1, 2, 3);
@@ -1065,7 +1062,7 @@ mod prim_str {}
 /// assert_eq!(y, 5);
 /// ```
 ///
-/// Homogenous tuples can be created from arrays of appropriate length:
+/// Homogeneous tuples can be created from arrays of appropriate length:
 ///
 /// ```
 /// let array: [u32; 3] = [1, 2, 3];
@@ -1361,7 +1358,7 @@ mod prim_usize {}
 ///
 /// [`std::fmt`]: fmt
 /// [`Hash`]: hash::Hash
-#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))]
+/// [`ToSocketAddrs`]: ../std/net/trait.ToSocketAddrs.html
 ///
 /// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T`
 /// implements that trait:
@@ -1381,10 +1378,10 @@ mod prim_usize {}
 ///
 /// [`FusedIterator`]: iter::FusedIterator
 /// [`TrustedLen`]: iter::TrustedLen
-#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))]
-#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))]
-#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))]
-#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))]
+/// [`Seek`]: ../std/io/trait.Seek.html
+/// [`BufRead`]: ../std/io/trait.BufRead.html
+/// [`Read`]: ../std/io/trait.Read.html
+/// [`io::Write`]: ../std/io/trait.Write.html
 ///
 /// Note that due to method call deref coercion, simply calling a trait method will act like they
 /// work on references as well as they do on owned values! The implementations described here are
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 41e67fd8435..d1286a1dea7 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -698,6 +698,7 @@ where
 #[inline(always)]
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
 #[rustc_diagnostic_item = "ptr_from_ref"]
 pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
     r
@@ -710,7 +711,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 #[inline(always)]
 #[must_use]
 #[unstable(feature = "ptr_from_ref", issue = "106116")]
-#[rustc_diagnostic_item = "ptr_from_mut"]
+#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
 pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
     r
 }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 6b3c4343ed3..d5bd54fd59a 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -338,6 +338,7 @@ impl<T: ?Sized> NonNull<T> {
     /// ```
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_ptr(self) -> *mut T {
@@ -597,6 +598,7 @@ impl<T> NonNull<[T]> {
     #[must_use]
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
     #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_mut_ptr(self) -> *mut T {
         self.as_non_null_ptr().as_ptr()
     }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index d95662afddd..0d635aced85 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -730,6 +730,7 @@ impl<T> [T] {
     /// [`as_mut_ptr`]: slice::as_mut_ptr
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_ptr(&self) -> *const T {
@@ -760,6 +761,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[rustc_allow_const_fn_unstable(const_mut_refs)]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[inline(always)]
     #[must_use]
     pub const fn as_mut_ptr(&mut self) -> *mut T {
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index d5b0ab92c09..eb0c424e2d2 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -386,6 +386,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[must_use]
     #[inline(always)]
     pub const fn as_ptr(&self) -> *const u8 {
@@ -401,6 +402,7 @@ impl str {
     /// It is your responsibility to make sure that the string slice only gets
     /// modified in a way that it remains valid UTF-8.
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     #[must_use]
     #[inline(always)]
     pub fn as_mut_ptr(&mut self) -> *mut u8 {
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 22a1c09782c..cf1fbe2d389 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1018,6 +1018,7 @@ impl AtomicBool {
     #[inline]
     #[stable(feature = "atomic_as_ptr", since = "1.70.0")]
     #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *mut bool {
         self.v.get().cast()
     }
@@ -1953,6 +1954,7 @@ impl<T> AtomicPtr<T> {
     #[inline]
     #[stable(feature = "atomic_as_ptr", since = "1.70.0")]
     #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
+    #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
     pub const fn as_ptr(&self) -> *mut *mut T {
         self.p.get()
     }
@@ -2891,6 +2893,7 @@ macro_rules! atomic_int {
             #[inline]
             #[stable(feature = "atomic_as_ptr", since = "1.70.0")]
             #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
+            #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)]
             pub const fn as_ptr(&self) -> *mut $int_type {
                 self.v.get()
             }
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 7782ace69c1..ff292ff2dcb 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,4 +1,4 @@
-// See src/libstd/primitive_docs.rs for documentation.
+// See core/src/primitive_docs.rs for documentation.
 
 use crate::cmp::Ordering::{self, *};
 use crate::marker::ConstParamTy;
diff --git a/library/std/primitive_docs/box_into_raw.md b/library/std/primitive_docs/box_into_raw.md
deleted file mode 100644
index 307b9c85bd6..00000000000
--- a/library/std/primitive_docs/box_into_raw.md
+++ /dev/null
@@ -1 +0,0 @@
-Box::into_raw
diff --git a/library/std/primitive_docs/fs_file.md b/library/std/primitive_docs/fs_file.md
deleted file mode 100644
index 13e4540835e..00000000000
--- a/library/std/primitive_docs/fs_file.md
+++ /dev/null
@@ -1 +0,0 @@
-fs::File
diff --git a/library/std/primitive_docs/io_bufread.md b/library/std/primitive_docs/io_bufread.md
deleted file mode 100644
index bb688e3a5cc..00000000000
--- a/library/std/primitive_docs/io_bufread.md
+++ /dev/null
@@ -1 +0,0 @@
-io::BufRead
diff --git a/library/std/primitive_docs/io_read.md b/library/std/primitive_docs/io_read.md
deleted file mode 100644
index 5118d7c4888..00000000000
--- a/library/std/primitive_docs/io_read.md
+++ /dev/null
@@ -1 +0,0 @@
-io::Read
diff --git a/library/std/primitive_docs/io_seek.md b/library/std/primitive_docs/io_seek.md
deleted file mode 100644
index 122e6df77b6..00000000000
--- a/library/std/primitive_docs/io_seek.md
+++ /dev/null
@@ -1 +0,0 @@
-io::Seek
diff --git a/library/std/primitive_docs/io_write.md b/library/std/primitive_docs/io_write.md
deleted file mode 100644
index 15dfc907a65..00000000000
--- a/library/std/primitive_docs/io_write.md
+++ /dev/null
@@ -1 +0,0 @@
-io::Write
diff --git a/library/std/primitive_docs/net_tosocketaddrs.md b/library/std/primitive_docs/net_tosocketaddrs.md
deleted file mode 100644
index a01f318e887..00000000000
--- a/library/std/primitive_docs/net_tosocketaddrs.md
+++ /dev/null
@@ -1 +0,0 @@
-net::ToSocketAddrs
diff --git a/library/std/primitive_docs/process_exit.md b/library/std/primitive_docs/process_exit.md
deleted file mode 100644
index 565a71375cd..00000000000
--- a/library/std/primitive_docs/process_exit.md
+++ /dev/null
@@ -1 +0,0 @@
-process::exit
diff --git a/library/std/primitive_docs/string_string.md b/library/std/primitive_docs/string_string.md
deleted file mode 100644
index ce7815ff91b..00000000000
--- a/library/std/primitive_docs/string_string.md
+++ /dev/null
@@ -1 +0,0 @@
-string::String
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 1955ef815ff..55c112c7b80 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -152,6 +152,31 @@
 //! contains further primitive shared memory types, including [`atomic`] and
 //! [`mpsc`], which contains the channel types for message passing.
 //!
+//! # Use before and after `main()`
+//!
+//! Many parts of the standard library are expected to work before and after `main()`;
+//! but this is not guaranteed or ensured by tests. It is recommended that you write your own tests
+//! and run them on each platform you wish to support.
+//! This means that use of `std` before/after main, especially of features that interact with the
+//! OS or global state, is exempted from stability and portability guarantees and instead only
+//! provided on a best-effort basis. Nevertheless bug reports are appreciated.
+//!
+//! On the other hand `core` and `alloc` are most likely to work in such environments with
+//! the caveat that any hookable behavior such as panics, oom handling or allocators will also
+//! depend on the compatibility of the hooks.
+//!
+//! Some features may also behave differently outside main, e.g. stdio could become unbuffered,
+//! some panics might turn into aborts, backtraces might not get symbolicated or similar.
+//!
+//! Non-exhaustive list of known limitations:
+//!
+//! - after-main use of thread-locals, which also affects additional features:
+//!   - [`thread::current()`]
+//!   - [`thread::scope()`]
+//!   - [`sync::mpsc`]
+//! - before-main stdio file descriptors are not guaranteed to be open on unix platforms
+//!
+//!
 //! [I/O]: io
 //! [`MIN`]: i32::MIN
 //! [`MAX`]: i32::MAX
@@ -187,7 +212,6 @@
 //! [rust-discord]: https://discord.gg/rust-lang
 //! [array]: prim@array
 //! [slice]: prim@slice
-
 // To run std tests without x.py without ending up with two copies of std, Miri needs to be
 // able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
 // rustc itself never sets the feature, so this line has no effect there.
@@ -351,7 +375,6 @@
 #![feature(get_many_mut)]
 #![feature(lazy_cell)]
 #![feature(log_syntax)]
-#![feature(saturating_int_impl)]
 #![feature(stdsimd)]
 #![feature(test)]
 #![feature(trace_macros)]
@@ -650,7 +673,7 @@ pub use core::primitive;
 // Include a number of private modules that exist solely to provide
 // the rustdoc documentation for primitive types. Using `include!`
 // because rustdoc only looks for these modules at the crate level.
-include!("primitive_docs.rs");
+include!("../../core/src/primitive_docs.rs");
 
 // Include a number of private modules that exist solely to provide
 // the rustdoc documentation for the existing keywords. Using `include!`
diff --git a/library/std/src/num.rs b/library/std/src/num.rs
index 46064bd2837..9e021b23fec 100644
--- a/library/std/src/num.rs
+++ b/library/std/src/num.rs
@@ -12,7 +12,7 @@ mod tests;
 #[cfg(test)]
 mod benches;
 
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")]
 pub use core::num::Saturating;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::Wrapping;
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index b6dc1a062ed..0eb4e88cfad 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -155,7 +155,7 @@ pub trait FileExt {
     /// flag fail to respect the offset parameter, always appending to the end
     /// of the file instead.
     ///
-    /// It is possible to inadvertantly set this flag, like in the example below.
+    /// It is possible to inadvertently set this flag, like in the example below.
     /// Therefore, it is important to be vigilant while changing options to mitigate
     /// unexpected behaviour.
     ///
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
deleted file mode 100644
index 80289ca08c3..00000000000
--- a/library/std/src/primitive_docs.rs
+++ /dev/null
@@ -1,1593 +0,0 @@
-// `library/{std,core}/src/primitive_docs.rs` should have the same contents.
-// These are different files so that relative links work properly without
-// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
-#[rustc_doc_primitive = "bool"]
-#[doc(alias = "true")]
-#[doc(alias = "false")]
-/// The boolean type.
-///
-/// The `bool` represents a value, which could only be either [`true`] or [`false`]. If you cast
-/// a `bool` into an integer, [`true`] will be 1 and [`false`] will be 0.
-///
-/// # Basic usage
-///
-/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
-/// which allow us to perform boolean operations using `&`, `|` and `!`.
-///
-/// [`if`] requires a `bool` value as its conditional. [`assert!`], which is an
-/// important macro in testing, checks whether an expression is [`true`] and panics
-/// if it isn't.
-///
-/// ```
-/// let bool_val = true & false | false;
-/// assert!(!bool_val);
-/// ```
-///
-/// [`true`]: ../std/keyword.true.html
-/// [`false`]: ../std/keyword.false.html
-/// [`BitAnd`]: ops::BitAnd
-/// [`BitOr`]: ops::BitOr
-/// [`Not`]: ops::Not
-/// [`if`]: ../std/keyword.if.html
-///
-/// # Examples
-///
-/// A trivial example of the usage of `bool`:
-///
-/// ```
-/// let praise_the_borrow_checker = true;
-///
-/// // using the `if` conditional
-/// if praise_the_borrow_checker {
-///     println!("oh, yeah!");
-/// } else {
-///     println!("what?!!");
-/// }
-///
-/// // ... or, a match pattern
-/// match praise_the_borrow_checker {
-///     true => println!("keep praising!"),
-///     false => println!("you should praise!"),
-/// }
-/// ```
-///
-/// Also, since `bool` implements the [`Copy`] trait, we don't
-/// have to worry about the move semantics (just like the integer and float primitives).
-///
-/// Now an example of `bool` cast to integer type:
-///
-/// ```
-/// assert_eq!(true as i32, 1);
-/// assert_eq!(false as i32, 0);
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_bool {}
-
-#[rustc_doc_primitive = "never"]
-#[doc(alias = "!")]
-//
-/// The `!` type, also called "never".
-///
-/// `!` represents the type of computations which never resolve to any value at all. For example,
-/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and
-/// so returns `!`.
-///
-/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to
-/// write:
-///
-/// ```
-/// #![feature(never_type)]
-/// # fn foo() -> u32 {
-/// let x: ! = {
-///     return 123
-/// };
-/// # }
-/// ```
-///
-/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never
-/// assigned a value (because `return` returns from the entire function), `x` can be given type
-/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code
-/// would still be valid.
-///
-/// A more realistic usage of `!` is in this code:
-///
-/// ```
-/// # fn get_a_number() -> Option<u32> { None }
-/// # loop {
-/// let num: u32 = match get_a_number() {
-///     Some(num) => num,
-///     None => break,
-/// };
-/// # }
-/// ```
-///
-/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
-/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
-/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
-///
-/// [`u32`]: prim@u32
-#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))]
-///
-/// # `!` and generics
-///
-/// ## Infallible errors
-///
-/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
-/// trait:
-///
-/// ```
-/// trait FromStr: Sized {
-///     type Err;
-///     fn from_str(s: &str) -> Result<Self, Self::Err>;
-/// }
-/// ```
-///
-/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since
-/// converting a string into a string will never result in an error, the appropriate type is `!`.
-/// (Currently the type actually used is an enum with no variants, though this is only because `!`
-/// was added to Rust at a later date and it may change in the future.) With an [`Err`] type of
-/// `!`, if we have to call [`String::from_str`] for some reason the result will be a
-/// [`Result<String, !>`] which we can unpack like this:
-///
-/// ```
-/// #![feature(exhaustive_patterns)]
-/// use std::str::FromStr;
-/// let Ok(s) = String::from_str("hello");
-/// ```
-///
-/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
-/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
-/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
-/// enum variants from generic types like `Result`.
-///
-/// ## Infinite loops
-///
-/// While [`Result<T, !>`] is very useful for removing errors, `!` can also be used to remove
-/// successes as well. If we think of [`Result<T, !>`] as "if this function returns, it has not
-/// errored," we get a very intuitive idea of [`Result<!, E>`] as well: if the function returns, it
-/// *has* errored.
-///
-/// For example, consider the case of a simple web server, which can be simplified to:
-///
-/// ```ignore (hypothetical-example)
-/// loop {
-///     let (client, request) = get_request().expect("disconnected");
-///     let response = request.process();
-///     response.send(client);
-/// }
-/// ```
-///
-/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection.
-/// Instead, we'd like to keep track of this error, like this:
-///
-/// ```ignore (hypothetical-example)
-/// loop {
-///     match get_request() {
-///         Err(err) => break err,
-///         Ok((client, request)) => {
-///             let response = request.process();
-///             response.send(client);
-///         },
-///     }
-/// }
-/// ```
-///
-/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it
-/// might be intuitive to simply return the error, we might want to wrap it in a [`Result<!, E>`]
-/// instead:
-///
-/// ```ignore (hypothetical-example)
-/// fn server_loop() -> Result<!, ConnectionError> {
-///     loop {
-///         let (client, request) = get_request()?;
-///         let response = request.process();
-///         response.send(client);
-///     }
-/// }
-/// ```
-///
-/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop
-/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok`
-/// because `!` coerces to `Result<!, ConnectionError>` automatically.
-///
-/// [`String::from_str`]: str::FromStr::from_str
-#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))]
-/// [`FromStr`]: str::FromStr
-///
-/// # `!` and traits
-///
-/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
-/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!`
-/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other
-/// words, they can't return `!` from every code path. As an example, this code doesn't compile:
-///
-/// ```compile_fail
-/// use std::ops::Add;
-///
-/// fn foo() -> impl Add<u32> {
-///     unimplemented!()
-/// }
-/// ```
-///
-/// But this code does:
-///
-/// ```
-/// use std::ops::Add;
-///
-/// fn foo() -> impl Add<u32> {
-///     if true {
-///         unimplemented!()
-///     } else {
-///         0
-///     }
-/// }
-/// ```
-///
-/// The reason is that, in the first example, there are many possible types that `!` could coerce
-/// to, because many types implement `Add<u32>`. However, in the second example,
-/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type
-/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375]
-/// for more information on this quirk of `!`.
-///
-/// [#36375]: https://github.com/rust-lang/rust/issues/36375
-///
-/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`]
-/// for example:
-///
-/// ```
-/// #![feature(never_type)]
-/// # use std::fmt;
-/// # trait Debug {
-/// #     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
-/// # }
-/// impl Debug for ! {
-///     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-///         *self
-///     }
-/// }
-/// ```
-///
-/// Once again we're using `!`'s ability to coerce into any other type, in this case
-/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
-/// called (because there is no value of type `!` for it to be called with). Writing `*self`
-/// essentially tells the compiler "We know that this code can never be run, so just treat the
-/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when
-/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
-/// parameter should have such an impl.
-///
-/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
-///
-/// ```
-/// trait Default {
-///     fn default() -> Self;
-/// }
-/// ```
-///
-/// Since `!` has no values, it has no default value either. It's true that we could write an
-/// `impl` for this which simply panics, but the same is true for any type (we could `impl
-/// Default` for (eg.) [`File`] by just making [`default()`] panic.)
-///
-#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))]
-/// [`Debug`]: fmt::Debug
-/// [`default()`]: Default::default
-///
-#[unstable(feature = "never_type", issue = "35121")]
-mod prim_never {}
-
-#[rustc_doc_primitive = "char"]
-#[allow(rustdoc::invalid_rust_codeblocks)]
-/// A character type.
-///
-/// The `char` type represents a single character. More specifically, since
-/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
-/// scalar value]'.
-///
-/// This documentation describes a number of methods and trait implementations on the
-/// `char` type. For technical reasons, there is additional, separate
-/// documentation in [the `std::char` module](char/index.html) as well.
-///
-/// # Validity
-///
-/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]'
-/// other than a [surrogate code point]. This has a fixed numerical definition:
-/// code points are in the range 0 to 0x10FFFF, inclusive.
-/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF.
-///
-/// No `char` may be constructed, whether as a literal or at runtime, that is not a
-/// Unicode scalar value:
-///
-/// ```compile_fail
-/// // Each of these is a compiler error
-/// ['\u{D800}', '\u{DFFF}', '\u{110000}'];
-/// ```
-///
-/// ```should_panic
-/// // Panics; from_u32 returns None.
-/// char::from_u32(0xDE01).unwrap();
-/// ```
-///
-/// ```no_run
-/// // Undefined behaviour
-/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
-/// ```
-///
-/// USVs are also the exact set of values that may be encoded in UTF-8. Because
-/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store
-/// any `char` in a `str` or read any character from a `str` as a `char`.
-///
-/// The gap in valid `char` values is understood by the compiler, so in the
-/// below example the two ranges are understood to cover the whole range of
-/// possible `char` values and there is no error for a [non-exhaustive match].
-///
-/// ```
-/// let c: char = 'a';
-/// match c {
-///     '\0' ..= '\u{D7FF}' => false,
-///     '\u{E000}' ..= '\u{10FFFF}' => true,
-/// };
-/// ```
-///
-/// All USVs are valid `char` values, but not all of them represent a real
-/// character. Many USVs are not currently assigned to a character, but may be
-/// in the future ("reserved"); some will never be a character
-/// ("noncharacters"); and some may be given different meanings by different
-/// users ("private use").
-///
-/// [Unicode code point]: https://www.unicode.org/glossary/#code_point
-/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
-/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive
-/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point
-///
-/// # Representation
-///
-/// `char` is always four bytes in size. This is a different representation than
-/// a given character would have as part of a [`String`]. For example:
-///
-/// ```
-/// let v = vec!['h', 'e', 'l', 'l', 'o'];
-///
-/// // five elements times four bytes for each element
-/// assert_eq!(20, v.len() * std::mem::size_of::<char>());
-///
-/// let s = String::from("hello");
-///
-/// // five elements times one byte per element
-/// assert_eq!(5, s.len() * std::mem::size_of::<u8>());
-/// ```
-///
-#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))]
-///
-/// As always, remember that a human intuition for 'character' might not map to
-/// Unicode's definitions. For example, despite looking similar, the 'é'
-/// character is one Unicode code point while 'é' is two Unicode code points:
-///
-/// ```
-/// let mut chars = "é".chars();
-/// // U+00e9: 'latin small letter e with acute'
-/// assert_eq!(Some('\u{00e9}'), chars.next());
-/// assert_eq!(None, chars.next());
-///
-/// let mut chars = "é".chars();
-/// // U+0065: 'latin small letter e'
-/// assert_eq!(Some('\u{0065}'), chars.next());
-/// // U+0301: 'combining acute accent'
-/// assert_eq!(Some('\u{0301}'), chars.next());
-/// assert_eq!(None, chars.next());
-/// ```
-///
-/// This means that the contents of the first string above _will_ fit into a
-/// `char` while the contents of the second string _will not_. Trying to create
-/// a `char` literal with the contents of the second string gives an error:
-///
-/// ```text
-/// error: character literal may only contain one codepoint: 'é'
-/// let c = 'é';
-///         ^^^
-/// ```
-///
-/// Another implication of the 4-byte fixed size of a `char` is that
-/// per-`char` processing can end up using a lot more memory:
-///
-/// ```
-/// let s = String::from("love: ❤️");
-/// let v: Vec<char> = s.chars().collect();
-///
-/// assert_eq!(12, std::mem::size_of_val(&s[..]));
-/// assert_eq!(32, std::mem::size_of_val(&v[..]));
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_char {}
-
-#[rustc_doc_primitive = "unit"]
-#[doc(alias = "(")]
-#[doc(alias = ")")]
-#[doc(alias = "()")]
-//
-/// The `()` type, also called "unit".
-///
-/// The `()` type has exactly one value `()`, and is used when there
-/// is no other meaningful value that could be returned. `()` is most
-/// commonly seen implicitly: functions without a `-> ...` implicitly
-/// have return type `()`, that is, these are equivalent:
-///
-/// ```rust
-/// fn long() -> () {}
-///
-/// fn short() {}
-/// ```
-///
-/// The semicolon `;` can be used to discard the result of an
-/// expression at the end of a block, making the expression (and thus
-/// the block) evaluate to `()`. For example,
-///
-/// ```rust
-/// fn returns_i64() -> i64 {
-///     1i64
-/// }
-/// fn returns_unit() {
-///     1i64;
-/// }
-///
-/// let is_i64 = {
-///     returns_i64()
-/// };
-/// let is_unit = {
-///     returns_i64();
-/// };
-/// ```
-///
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_unit {}
-
-// Required to make auto trait impls render.
-// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
-#[doc(hidden)]
-impl () {}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Clone for () {
-    fn clone(&self) -> Self {
-        loop {}
-    }
-}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Copy for () {
-    // empty
-}
-
-#[rustc_doc_primitive = "pointer"]
-#[doc(alias = "ptr")]
-#[doc(alias = "*")]
-#[doc(alias = "*const")]
-#[doc(alias = "*mut")]
-//
-/// Raw, unsafe pointers, `*const T`, and `*mut T`.
-///
-/// *[See also the `std::ptr` module](ptr).*
-///
-/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns.
-/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is
-/// dereferenced (using the `*` operator), it must be non-null and aligned.
-///
-/// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so
-/// [`write`] must be used if the type has drop glue and memory is not already
-/// initialized - otherwise `drop` would be called on the uninitialized memory.
-///
-/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the
-/// [`is_null`] method of the `*const T` and `*mut T` types to check for null.
-/// The `*const T` and `*mut T` types also define the [`offset`] method, for
-/// pointer math.
-///
-/// # Common ways to create raw pointers
-///
-/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
-///
-/// ```
-/// let my_num: i32 = 10;
-/// let my_num_ptr: *const i32 = &my_num;
-/// let mut my_speed: i32 = 88;
-/// let my_speed_ptr: *mut i32 = &mut my_speed;
-/// ```
-///
-/// To get a pointer to a boxed value, dereference the box:
-///
-/// ```
-/// let my_num: Box<i32> = Box::new(10);
-/// let my_num_ptr: *const i32 = &*my_num;
-/// let mut my_speed: Box<i32> = Box::new(88);
-/// let my_speed_ptr: *mut i32 = &mut *my_speed;
-/// ```
-///
-/// This does not take ownership of the original allocation
-/// and requires no resource management later,
-/// but you must not use the pointer after its lifetime.
-///
-/// ## 2. Consume a box (`Box<T>`).
-///
-/// The [`into_raw`] function consumes a box and returns
-/// the raw pointer. It doesn't destroy `T` or deallocate any memory.
-///
-/// ```
-/// let my_speed: Box<i32> = Box::new(88);
-/// let my_speed: *mut i32 = Box::into_raw(my_speed);
-///
-/// // By taking ownership of the original `Box<T>` though
-/// // we are obligated to put it together later to be destroyed.
-/// unsafe {
-///     drop(Box::from_raw(my_speed));
-/// }
-/// ```
-///
-/// Note that here the call to [`drop`] is for clarity - it indicates
-/// that we are done with the given value and it should be destroyed.
-///
-/// ## 3. Create it using `ptr::addr_of!`
-///
-/// Instead of coercing a reference to a raw pointer, you can use the macros
-/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
-/// These macros allow you to create raw pointers to fields to which you cannot
-/// create a reference (without causing undefined behaviour), such as an
-/// unaligned field. This might be necessary if packed structs or uninitialized
-/// memory is involved.
-///
-/// ```
-/// #[derive(Debug, Default, Copy, Clone)]
-/// #[repr(C, packed)]
-/// struct S {
-///     aligned: u8,
-///     unaligned: u32,
-/// }
-/// let s = S::default();
-/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion
-/// ```
-///
-/// ## 4. Get it from C.
-///
-/// ```
-/// # #![feature(rustc_private)]
-/// #[allow(unused_extern_crates)]
-/// extern crate libc;
-///
-/// use std::mem;
-///
-/// unsafe {
-///     let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
-///     if my_num.is_null() {
-///         panic!("failed to allocate memory");
-///     }
-///     libc::free(my_num as *mut libc::c_void);
-/// }
-/// ```
-///
-/// Usually you wouldn't literally use `malloc` and `free` from Rust,
-/// but C APIs hand out a lot of pointers generally, so are a common source
-/// of raw pointers in Rust.
-///
-/// [`null`]: ptr::null
-/// [`null_mut`]: ptr::null_mut
-/// [`is_null`]: pointer::is_null
-/// [`offset`]: pointer::offset
-#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))]
-/// [`write`]: ptr::write
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_pointer {}
-
-#[rustc_doc_primitive = "array"]
-#[doc(alias = "[]")]
-#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
-#[doc(alias = "[T; N]")]
-/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the
-/// non-negative compile-time constant size, `N`.
-///
-/// There are two syntactic forms for creating an array:
-///
-/// * A list with each element, i.e., `[x, y, z]`.
-/// * A repeat expression `[expr; N]` where `N` is how many times to repeat `expr` in the array. `expr` must either be:
-///
-///   * A value of a type implementing the [`Copy`] trait
-///   * A `const` value
-///
-/// Note that `[expr; 0]` is allowed, and produces an empty array.
-/// This will still evaluate `expr`, however, and immediately drop the resulting value, so
-/// be mindful of side effects.
-///
-/// Arrays of *any* size implement the following traits if the element type allows it:
-///
-/// - [`Copy`]
-/// - [`Clone`]
-/// - [`Debug`]
-/// - [`IntoIterator`] (implemented for `[T; N]`, `&[T; N]` and `&mut [T; N]`)
-/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`]
-/// - [`Hash`]
-/// - [`AsRef`], [`AsMut`]
-/// - [`Borrow`], [`BorrowMut`]
-///
-/// Arrays of sizes from 0 to 32 (inclusive) implement the [`Default`] trait
-/// if the element type allows it. As a stopgap, trait implementations are
-/// statically generated up to size 32.
-///
-/// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple`
-/// is a homogenous [prim@tuple] of appropriate length.
-///
-/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
-/// an array. Indeed, this provides most of the API for working with arrays.
-///
-/// Slices have a dynamic size and do not coerce to arrays. Instead, use
-/// `slice.try_into().unwrap()` or `<ArrayType>::try_from(slice).unwrap()`.
-///
-/// Array's `try_from(slice)` implementations (and the corresponding `slice.try_into()`
-/// array implementations) succeed if the input slice length is the same as the result
-/// array length. They optimize especially well when the optimizer can easily determine
-/// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements
-/// [TryFrom](crate::convert::TryFrom) returning:
-///
-/// - `[T; N]` copies from the slice's elements
-/// - `&[T; N]` references the original slice's elements
-/// - `&mut [T; N]` references the original slice's elements
-///
-/// You can move elements out of an array with a [slice pattern]. If you want
-/// one element, see [`mem::replace`].
-///
-/// # Examples
-///
-/// ```
-/// let mut array: [i32; 3] = [0; 3];
-///
-/// array[1] = 1;
-/// array[2] = 2;
-///
-/// assert_eq!([1, 2], &array[1..]);
-///
-/// // This loop prints: 0 1 2
-/// for x in array {
-///     print!("{x} ");
-/// }
-/// ```
-///
-/// You can also iterate over reference to the array's elements:
-///
-/// ```
-/// let array: [i32; 3] = [0; 3];
-///
-/// for x in &array { }
-/// ```
-///
-/// You can use `<ArrayType>::try_from(slice)` or `slice.try_into()` to get an array from
-/// a slice:
-///
-/// ```
-/// let bytes: [u8; 3] = [1, 0, 2];
-/// assert_eq!(1, u16::from_le_bytes(<[u8; 2]>::try_from(&bytes[0..2]).unwrap()));
-/// assert_eq!(512, u16::from_le_bytes(bytes[1..3].try_into().unwrap()));
-/// ```
-///
-/// You can use a [slice pattern] to move elements out of an array:
-///
-/// ```
-/// fn move_away(_: String) { /* Do interesting things. */ }
-///
-/// let [john, roa] = ["John".to_string(), "Roa".to_string()];
-/// move_away(john);
-/// move_away(roa);
-/// ```
-///
-/// Arrays can be created from homogenous tuples of appropriate length:
-///
-/// ```
-/// let tuple: (u32, u32, u32) = (1, 2, 3);
-/// let array: [u32; 3] = tuple.into();
-/// ```
-///
-/// # Editions
-///
-/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call
-/// `array.into_iter()` auto-referenced into a [slice iterator](slice::iter). Right now, the old
-/// behavior is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring
-/// [`IntoIterator`] by value. In the future, the behavior on the 2015 and 2018 edition
-/// might be made consistent to the behavior of later editions.
-///
-/// ```rust,edition2018
-/// // Rust 2015 and 2018:
-///
-/// # #![allow(array_into_iter)] // override our `deny(warnings)`
-/// let array: [i32; 3] = [0; 3];
-///
-/// // This creates a slice iterator, producing references to each value.
-/// for item in array.into_iter().enumerate() {
-///     let (i, x): (usize, &i32) = item;
-///     println!("array[{i}] = {x}");
-/// }
-///
-/// // The `array_into_iter` lint suggests this change for future compatibility:
-/// for item in array.iter().enumerate() {
-///     let (i, x): (usize, &i32) = item;
-///     println!("array[{i}] = {x}");
-/// }
-///
-/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
-/// for item in IntoIterator::into_iter(array).enumerate() {
-///     let (i, x): (usize, i32) = item;
-///     println!("array[{i}] = {x}");
-/// }
-/// ```
-///
-/// Starting in the 2021 edition, `array.into_iter()` uses `IntoIterator` normally to iterate
-/// by value, and `iter()` should be used to iterate by reference like previous editions.
-///
-/// ```rust,edition2021
-/// // Rust 2021:
-///
-/// let array: [i32; 3] = [0; 3];
-///
-/// // This iterates by reference:
-/// for item in array.iter().enumerate() {
-///     let (i, x): (usize, &i32) = item;
-///     println!("array[{i}] = {x}");
-/// }
-///
-/// // This iterates by value:
-/// for item in array.into_iter().enumerate() {
-///     let (i, x): (usize, i32) = item;
-///     println!("array[{i}] = {x}");
-/// }
-/// ```
-///
-/// Future language versions might start treating the `array.into_iter()`
-/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using
-/// those older editions should still be written with this change in mind, to
-/// prevent breakage in the future. The safest way to accomplish this is to
-/// avoid the `into_iter` syntax on those editions. If an edition update is not
-/// viable/desired, there are multiple alternatives:
-/// * use `iter`, equivalent to the old behavior, creating references
-/// * use [`IntoIterator::into_iter`], equivalent to the post-2021 behavior (Rust 1.53+)
-/// * replace `for ... in array.into_iter() {` with `for ... in array {`,
-///   equivalent to the post-2021 behavior (Rust 1.53+)
-///
-/// ```rust,edition2018
-/// // Rust 2015 and 2018:
-///
-/// let array: [i32; 3] = [0; 3];
-///
-/// // This iterates by reference:
-/// for item in array.iter() {
-///     let x: &i32 = item;
-///     println!("{x}");
-/// }
-///
-/// // This iterates by value:
-/// for item in IntoIterator::into_iter(array) {
-///     let x: i32 = item;
-///     println!("{x}");
-/// }
-///
-/// // This iterates by value:
-/// for item in array {
-///     let x: i32 = item;
-///     println!("{x}");
-/// }
-///
-/// // IntoIter can also start a chain.
-/// // This iterates by value:
-/// for item in IntoIterator::into_iter(array).enumerate() {
-///     let (i, x): (usize, i32) = item;
-///     println!("array[{i}] = {x}");
-/// }
-/// ```
-///
-/// [slice]: prim@slice
-/// [`Debug`]: fmt::Debug
-/// [`Hash`]: hash::Hash
-/// [`Borrow`]: borrow::Borrow
-/// [`BorrowMut`]: borrow::BorrowMut
-/// [slice pattern]: ../reference/patterns.html#slice-patterns
-/// [`From<Tuple>`]: convert::From
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_array {}
-
-#[rustc_doc_primitive = "slice"]
-#[doc(alias = "[")]
-#[doc(alias = "]")]
-#[doc(alias = "[]")]
-/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here
-/// means that elements are laid out so that every element is the same
-/// distance from its neighbors.
-///
-/// *[See also the `std::slice` module](crate::slice).*
-///
-/// Slices are a view into a block of memory represented as a pointer and a
-/// length.
-///
-/// ```
-/// // slicing a Vec
-/// let vec = vec![1, 2, 3];
-/// let int_slice = &vec[..];
-/// // coercing an array to a slice
-/// let str_slice: &[&str] = &["one", "two", "three"];
-/// ```
-///
-/// Slices are either mutable or shared. The shared slice type is `&[T]`,
-/// while the mutable slice type is `&mut [T]`, where `T` represents the element
-/// type. For example, you can mutate the block of memory that a mutable slice
-/// points to:
-///
-/// ```
-/// let mut x = [1, 2, 3];
-/// let x = &mut x[..]; // Take a full slice of `x`.
-/// x[1] = 7;
-/// assert_eq!(x, &[1, 7, 3]);
-/// ```
-///
-/// As slices store the length of the sequence they refer to, they have twice
-/// the size of pointers to [`Sized`](marker/trait.Sized.html) types.
-/// Also see the reference on
-/// [dynamically sized types](../reference/dynamically-sized-types.html).
-///
-/// ```
-/// # use std::rc::Rc;
-/// let pointer_size = std::mem::size_of::<&u8>();
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
-/// ```
-///
-/// ## Trait Implementations
-///
-/// Some traits are implemented for slices if the element type implements
-/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`].
-///
-/// ## Iteration
-///
-/// The slices implement `IntoIterator`. The iterator yields references to the
-/// slice elements.
-///
-/// ```
-/// let numbers: &[i32] = &[0, 1, 2];
-/// for n in numbers {
-///     println!("{n} is a number!");
-/// }
-/// ```
-///
-/// The mutable slice yields mutable references to the elements:
-///
-/// ```
-/// let mut scores: &mut [i32] = &mut [7, 8, 9];
-/// for score in scores {
-///     *score += 1;
-/// }
-/// ```
-///
-/// This iterator yields mutable references to the slice's elements, so while
-/// the element type of the slice is `i32`, the element type of the iterator is
-/// `&mut i32`.
-///
-/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
-///   iterators.
-/// * Further methods that return iterators are [`.split`], [`.splitn`],
-///   [`.chunks`], [`.windows`] and more.
-///
-/// [`Hash`]: core::hash::Hash
-/// [`.iter`]: slice::iter
-/// [`.iter_mut`]: slice::iter_mut
-/// [`.split`]: slice::split
-/// [`.splitn`]: slice::splitn
-/// [`.chunks`]: slice::chunks
-/// [`.windows`]: slice::windows
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_slice {}
-
-#[rustc_doc_primitive = "str"]
-/// String slices.
-///
-/// *[See also the `std::str` module](crate::str).*
-///
-/// The `str` type, also called a 'string slice', is the most primitive string
-/// type. It is usually seen in its borrowed form, `&str`. It is also the type
-/// of string literals, `&'static str`.
-///
-/// String slices are always valid UTF-8.
-///
-/// # Basic Usage
-///
-/// String literals are string slices:
-///
-/// ```
-/// let hello_world = "Hello, World!";
-/// ```
-///
-/// Here we have declared a string slice initialized with a string literal.
-/// String literals have a static lifetime, which means the string `hello_world`
-/// is guaranteed to be valid for the duration of the entire program.
-/// We can explicitly specify `hello_world`'s lifetime as well:
-///
-/// ```
-/// let hello_world: &'static str = "Hello, world!";
-/// ```
-///
-/// # Representation
-///
-/// A `&str` is made up of two components: a pointer to some bytes, and a
-/// length. You can look at these with the [`as_ptr`] and [`len`] methods:
-///
-/// ```
-/// use std::slice;
-/// use std::str;
-///
-/// let story = "Once upon a time...";
-///
-/// let ptr = story.as_ptr();
-/// let len = story.len();
-///
-/// // story has nineteen bytes
-/// assert_eq!(19, len);
-///
-/// // We can re-build a str out of ptr and len. This is all unsafe because
-/// // we are responsible for making sure the two components are valid:
-/// let s = unsafe {
-///     // First, we build a &[u8]...
-///     let slice = slice::from_raw_parts(ptr, len);
-///
-///     // ... and then convert that slice into a string slice
-///     str::from_utf8(slice)
-/// };
-///
-/// assert_eq!(s, Ok(story));
-/// ```
-///
-/// [`as_ptr`]: str::as_ptr
-/// [`len`]: str::len
-///
-/// Note: This example shows the internals of `&str`. `unsafe` should not be
-/// used to get a string slice under normal circumstances. Use `as_str`
-/// instead.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_str {}
-
-#[rustc_doc_primitive = "tuple"]
-#[doc(alias = "(")]
-#[doc(alias = ")")]
-#[doc(alias = "()")]
-//
-/// A finite heterogeneous sequence, `(T, U, ..)`.
-///
-/// Let's cover each of those in turn:
-///
-/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple
-/// of length `3`:
-///
-/// ```
-/// ("hello", 5, 'c');
-/// ```
-///
-/// 'Length' is also sometimes called 'arity' here; each tuple of a different
-/// length is a different, distinct type.
-///
-/// Tuples are *heterogeneous*. This means that each element of the tuple can
-/// have a different type. In that tuple above, it has the type:
-///
-/// ```
-/// # let _:
-/// (&'static str, i32, char)
-/// # = ("hello", 5, 'c');
-/// ```
-///
-/// Tuples are a *sequence*. This means that they can be accessed by position;
-/// this is called 'tuple indexing', and it looks like this:
-///
-/// ```rust
-/// let tuple = ("hello", 5, 'c');
-///
-/// assert_eq!(tuple.0, "hello");
-/// assert_eq!(tuple.1, 5);
-/// assert_eq!(tuple.2, 'c');
-/// ```
-///
-/// The sequential nature of the tuple applies to its implementations of various
-/// traits. For example, in [`PartialOrd`] and [`Ord`], the elements are compared
-/// sequentially until the first non-equal set is found.
-///
-/// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type).
-///
-// Hardcoded anchor in src/librustdoc/html/format.rs
-// linked to as `#trait-implementations-1`
-/// # Trait implementations
-///
-/// In this documentation the shorthand `(T₁, T₂, …, Tₙ)` is used to represent tuples of varying
-/// length. When that is used, any trait bound expressed on `T` applies to each element of the
-/// tuple independently. Note that this is a convenience notation to avoid repetitive
-/// documentation, not valid Rust syntax.
-///
-/// Due to a temporary restriction in Rust’s type system, the following traits are only
-/// implemented on tuples of arity 12 or less. In the future, this may change:
-///
-/// * [`PartialEq`]
-/// * [`Eq`]
-/// * [`PartialOrd`]
-/// * [`Ord`]
-/// * [`Debug`]
-/// * [`Default`]
-/// * [`Hash`]
-/// * [`From<[T; N]>`][from]
-///
-/// [from]: convert::From
-/// [`Debug`]: fmt::Debug
-/// [`Hash`]: hash::Hash
-///
-/// The following traits are implemented for tuples of any length. These traits have
-/// implementations that are automatically generated by the compiler, so are not limited by
-/// missing language features.
-///
-/// * [`Clone`]
-/// * [`Copy`]
-/// * [`Send`]
-/// * [`Sync`]
-/// * [`Unpin`]
-/// * [`UnwindSafe`]
-/// * [`RefUnwindSafe`]
-///
-/// [`UnwindSafe`]: panic::UnwindSafe
-/// [`RefUnwindSafe`]: panic::RefUnwindSafe
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// let tuple = ("hello", 5, 'c');
-///
-/// assert_eq!(tuple.0, "hello");
-/// ```
-///
-/// Tuples are often used as a return type when you want to return more than
-/// one value:
-///
-/// ```
-/// fn calculate_point() -> (i32, i32) {
-///     // Don't do a calculation, that's not the point of the example
-///     (4, 5)
-/// }
-///
-/// let point = calculate_point();
-///
-/// assert_eq!(point.0, 4);
-/// assert_eq!(point.1, 5);
-///
-/// // Combining this with patterns can be nicer.
-///
-/// let (x, y) = calculate_point();
-///
-/// assert_eq!(x, 4);
-/// assert_eq!(y, 5);
-/// ```
-///
-/// Homogenous tuples can be created from arrays of appropriate length:
-///
-/// ```
-/// let array: [u32; 3] = [1, 2, 3];
-/// let tuple: (u32, u32, u32) = array.into();
-/// ```
-///
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_tuple {}
-
-// Required to make auto trait impls render.
-// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
-#[doc(hidden)]
-impl<T> (T,) {}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on arbitrary-length tuples.
-impl<T: Clone> Clone for (T,) {
-    fn clone(&self) -> Self {
-        loop {}
-    }
-}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on arbitrary-length tuples.
-impl<T: Copy> Copy for (T,) {
-    // empty
-}
-
-#[rustc_doc_primitive = "f32"]
-/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
-///
-/// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
-/// `-113.75`, `0.0078125`, `34359738368`, `0`, `-1`. So unlike integer types
-/// (such as `i32`), floating point types can represent non-integer numbers,
-/// too.
-///
-/// However, being able to represent this wide range of numbers comes at the
-/// cost of precision: floats can only represent some of the real numbers and
-/// calculation with floats round to a nearby representable number. For example,
-/// `5.0` and `1.0` can be exactly represented as `f32`, but `1.0 / 5.0` results
-/// in `0.20000000298023223876953125` since `0.2` cannot be exactly represented
-/// as `f32`. Note, however, that printing floats with `println` and friends will
-/// often discard insignificant digits: `println!("{}", 1.0f32 / 5.0f32)` will
-/// print `0.2`.
-///
-/// Additionally, `f32` can represent some special values:
-///
-/// - −0.0: IEEE 754 floating point numbers have a bit that indicates their sign, so −0.0 is a
-///   possible value. For comparison −0.0 = +0.0, but floating point operations can carry
-///   the sign bit through arithmetic operations. This means −0.0 × +0.0 produces −0.0 and
-///   a negative number rounded to a value smaller than a float can represent also produces −0.0.
-/// - [∞](#associatedconstant.INFINITY) and
-///   [−∞](#associatedconstant.NEG_INFINITY): these result from calculations
-///   like `1.0 / 0.0`.
-/// - [NaN (not a number)](#associatedconstant.NAN): this value results from
-///   calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
-///   behavior:
-///   - It is not equal to any float, including itself! This is the reason `f32`
-///     doesn't implement the `Eq` trait.
-///   - It is also neither smaller nor greater than any float, making it
-///     impossible to sort by the default comparison operation, which is the
-///     reason `f32` doesn't implement the `Ord` trait.
-///   - It is also considered *infectious* as almost all calculations where one
-///     of the operands is NaN will also result in NaN. The explanations on this
-///     page only explicitly document behavior on NaN operands if this default
-///     is deviated from.
-///   - Lastly, there are multiple bit patterns that are considered NaN.
-///     Rust does not currently guarantee that the bit patterns of NaN are
-///     preserved over arithmetic operations, and they are not guaranteed to be
-///     portable or even fully deterministic! This means that there may be some
-///     surprising results upon inspecting the bit patterns,
-///     as the same calculations might produce NaNs with different bit patterns.
-///
-/// When the number resulting from a primitive operation (addition,
-/// subtraction, multiplication, or division) on this type is not exactly
-/// representable as `f32`, it is rounded according to the roundTiesToEven
-/// direction defined in IEEE 754-2008. That means:
-///
-/// - The result is the representable value closest to the true value, if there
-///   is a unique closest representable value.
-/// - If the true value is exactly half-way between two representable values,
-///   the result is the one with an even least-significant binary digit.
-/// - If the true value's magnitude is ≥ `f32::MAX` + 2<sup>(`f32::MAX_EXP` −
-///   `f32::MANTISSA_DIGITS` − 1)</sup>, the result is ∞ or −∞ (preserving the
-///   true value's sign).
-///
-/// For more information on floating point numbers, see [Wikipedia][wikipedia].
-///
-/// *[See also the `std::f32::consts` module](crate::f32::consts).*
-///
-/// [wikipedia]: https://en.wikipedia.org/wiki/Single-precision_floating-point_format
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_f32 {}
-
-#[rustc_doc_primitive = "f64"]
-/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
-///
-/// This type is very similar to [`f32`], but has increased
-/// precision by using twice as many bits. Please see [the documentation for
-/// `f32`][`f32`] or [Wikipedia on double precision
-/// values][wikipedia] for more information.
-///
-/// *[See also the `std::f64::consts` module](crate::f64::consts).*
-///
-/// [`f32`]: prim@f32
-/// [wikipedia]: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_f64 {}
-
-#[rustc_doc_primitive = "i8"]
-//
-/// The 8-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i8 {}
-
-#[rustc_doc_primitive = "i16"]
-//
-/// The 16-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i16 {}
-
-#[rustc_doc_primitive = "i32"]
-//
-/// The 32-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i32 {}
-
-#[rustc_doc_primitive = "i64"]
-//
-/// The 64-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i64 {}
-
-#[rustc_doc_primitive = "i128"]
-//
-/// The 128-bit signed integer type.
-#[stable(feature = "i128", since = "1.26.0")]
-mod prim_i128 {}
-
-#[rustc_doc_primitive = "u8"]
-//
-/// The 8-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u8 {}
-
-#[rustc_doc_primitive = "u16"]
-//
-/// The 16-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u16 {}
-
-#[rustc_doc_primitive = "u32"]
-//
-/// The 32-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u32 {}
-
-#[rustc_doc_primitive = "u64"]
-//
-/// The 64-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u64 {}
-
-#[rustc_doc_primitive = "u128"]
-//
-/// The 128-bit unsigned integer type.
-#[stable(feature = "i128", since = "1.26.0")]
-mod prim_u128 {}
-
-#[rustc_doc_primitive = "isize"]
-//
-/// The pointer-sized signed integer type.
-///
-/// The size of this primitive is how many bytes it takes to reference any
-/// location in memory. For example, on a 32 bit target, this is 4 bytes
-/// and on a 64 bit target, this is 8 bytes.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_isize {}
-
-#[rustc_doc_primitive = "usize"]
-//
-/// The pointer-sized unsigned integer type.
-///
-/// The size of this primitive is how many bytes it takes to reference any
-/// location in memory. For example, on a 32 bit target, this is 4 bytes
-/// and on a 64 bit target, this is 8 bytes.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_usize {}
-
-#[rustc_doc_primitive = "reference"]
-#[doc(alias = "&")]
-#[doc(alias = "&mut")]
-//
-/// References, `&T` and `&mut T`.
-///
-/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
-/// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or
-/// <code>[ref](../std/keyword.ref.html) [mut](../std/keyword.mut.html)</code> pattern.
-///
-/// For those familiar with pointers, a reference is just a pointer that is assumed to be
-/// aligned, not null, and pointing to memory containing a valid value of `T` - for example,
-/// <code>&[bool]</code> can only point to an allocation containing the integer values `1`
-/// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but
-/// creating a <code>&[bool]</code> that points to an allocation containing
-/// the value `3` causes undefined behaviour.
-/// In fact, <code>[Option]\<&T></code> has the same memory representation as a
-/// nullable but aligned pointer, and can be passed across FFI boundaries as such.
-///
-/// In most cases, references can be used much like the original value. Field access, method
-/// calling, and indexing work the same (save for mutability rules, of course). In addition, the
-/// comparison operators transparently defer to the referent's implementation, allowing references
-/// to be compared the same as owned values.
-///
-/// References have a lifetime attached to them, which represents the scope for which the borrow is
-/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or
-/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the
-/// total life of the program. For example, string literals have a `'static` lifetime because the
-/// text data is embedded into the binary of the program, rather than in an allocation that needs
-/// to be dynamically managed.
-///
-/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
-/// references with longer lifetimes can be freely coerced into references with shorter ones.
-///
-/// Reference equality by address, instead of comparing the values pointed to, is accomplished via
-/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while
-/// [`PartialEq`] compares values.
-///
-/// ```
-/// use std::ptr;
-///
-/// let five = 5;
-/// let other_five = 5;
-/// let five_ref = &five;
-/// let same_five_ref = &five;
-/// let other_five_ref = &other_five;
-///
-/// assert!(five_ref == same_five_ref);
-/// assert!(five_ref == other_five_ref);
-///
-/// assert!(ptr::eq(five_ref, same_five_ref));
-/// assert!(!ptr::eq(five_ref, other_five_ref));
-/// ```
-///
-/// For more information on how to use references, see [the book's section on "References and
-/// Borrowing"][book-refs].
-///
-/// [book-refs]: ../book/ch04-02-references-and-borrowing.html
-///
-/// # Trait implementations
-///
-/// The following traits are implemented for all `&T`, regardless of the type of its referent:
-///
-/// * [`Copy`]
-/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!)
-/// * [`Deref`]
-/// * [`Borrow`]
-/// * [`fmt::Pointer`]
-///
-/// [`Deref`]: ops::Deref
-/// [`Borrow`]: borrow::Borrow
-///
-/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating
-/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its
-/// referent:
-///
-/// * [`DerefMut`]
-/// * [`BorrowMut`]
-///
-/// [`DerefMut`]: ops::DerefMut
-/// [`BorrowMut`]: borrow::BorrowMut
-/// [bool]: prim@bool
-///
-/// The following traits are implemented on `&T` references if the underlying `T` also implements
-/// that trait:
-///
-/// * All the traits in [`std::fmt`] except [`fmt::Pointer`] (which is implemented regardless of the type of its referent) and [`fmt::Write`]
-/// * [`PartialOrd`]
-/// * [`Ord`]
-/// * [`PartialEq`]
-/// * [`Eq`]
-/// * [`AsRef`]
-/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`)
-/// * [`Hash`]
-/// * [`ToSocketAddrs`]
-/// * [`Send`] \(`&T` references also require <code>T: [Sync]</code>)
-/// * [`Sync`]
-///
-/// [`std::fmt`]: fmt
-/// [`Hash`]: hash::Hash
-#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))]
-///
-/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T`
-/// implements that trait:
-///
-/// * [`AsMut`]
-/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`)
-/// * [`fmt::Write`]
-/// * [`Iterator`]
-/// * [`DoubleEndedIterator`]
-/// * [`ExactSizeIterator`]
-/// * [`FusedIterator`]
-/// * [`TrustedLen`]
-/// * [`io::Write`]
-/// * [`Read`]
-/// * [`Seek`]
-/// * [`BufRead`]
-///
-/// [`FusedIterator`]: iter::FusedIterator
-/// [`TrustedLen`]: iter::TrustedLen
-#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))]
-#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))]
-#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))]
-#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))]
-///
-/// Note that due to method call deref coercion, simply calling a trait method will act like they
-/// work on references as well as they do on owned values! The implementations described here are
-/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
-/// locally known.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_ref {}
-
-#[rustc_doc_primitive = "fn"]
-//
-/// Function pointers, like `fn(usize) -> bool`.
-///
-/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].*
-///
-/// Function pointers are pointers that point to *code*, not data. They can be called
-/// just like functions. Like references, function pointers are, among other things, assumed to
-/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null
-/// pointers, make your type [`Option<fn()>`](core::option#options-and-pointers-nullable-pointers)
-/// with your required signature.
-///
-/// ### Safety
-///
-/// Plain function pointers are obtained by casting either plain functions, or closures that don't
-/// capture an environment:
-///
-/// ```
-/// fn add_one(x: usize) -> usize {
-///     x + 1
-/// }
-///
-/// let ptr: fn(usize) -> usize = add_one;
-/// assert_eq!(ptr(5), 6);
-///
-/// let clos: fn(usize) -> usize = |x| x + 5;
-/// assert_eq!(clos(5), 10);
-/// ```
-///
-/// In addition to varying based on their signature, function pointers come in two flavors: safe
-/// and unsafe. Plain `fn()` function pointers can only point to safe functions,
-/// while `unsafe fn()` function pointers can point to safe or unsafe functions.
-///
-/// ```
-/// fn add_one(x: usize) -> usize {
-///     x + 1
-/// }
-///
-/// unsafe fn add_one_unsafely(x: usize) -> usize {
-///     x + 1
-/// }
-///
-/// let safe_ptr: fn(usize) -> usize = add_one;
-///
-/// //ERROR: mismatched types: expected normal fn, found unsafe fn
-/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely;
-///
-/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely;
-/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one;
-/// ```
-///
-/// ### ABI
-///
-/// On top of that, function pointers can vary based on what ABI they use. This
-/// is achieved by adding the `extern` keyword before the type, followed by the
-/// ABI in question. The default ABI is "Rust", i.e., `fn()` is the exact same
-/// type as `extern "Rust" fn()`. A pointer to a function with C ABI would have
-/// type `extern "C" fn()`.
-///
-/// `extern "ABI" { ... }` blocks declare functions with ABI "ABI". The default
-/// here is "C", i.e., functions declared in an `extern {...}` block have "C"
-/// ABI.
-///
-/// For more information and a list of supported ABIs, see [the nomicon's
-/// section on foreign calling conventions][nomicon-abi].
-///
-/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
-///
-/// ### Variadic functions
-///
-/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
-/// to be called with a variable number of arguments. Normal Rust functions, even those with an
-/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on
-/// variadic functions][nomicon-variadic].
-///
-/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions
-///
-/// ### Creating function pointers
-///
-/// When `bar` is the name of a function, then the expression `bar` is *not* a
-/// function pointer. Rather, it denotes a value of an unnameable type that
-/// uniquely identifies the function `bar`. The value is zero-sized because the
-/// type already identifies the function. This has the advantage that "calling"
-/// the value (it implements the `Fn*` traits) does not require dynamic
-/// dispatch.
-///
-/// This zero-sized type *coerces* to a regular function pointer. For example:
-///
-/// ```rust
-/// use std::mem;
-///
-/// fn bar(x: i32) {}
-///
-/// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar`
-/// assert_eq!(mem::size_of_val(&not_bar_ptr), 0);
-///
-/// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer
-/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::<usize>());
-///
-/// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar`
-/// ```
-///
-/// The last line shows that `&bar` is not a function pointer either. Rather, it
-/// is a reference to the function-specific ZST. `&bar` is basically never what you
-/// want when `bar` is a function.
-///
-/// ### Casting to and from integers
-///
-/// You cast function pointers directly to integers:
-///
-/// ```rust
-/// let fnptr: fn(i32) -> i32 = |x| x+2;
-/// let fnptr_addr = fnptr as usize;
-/// ```
-///
-/// However, a direct cast back is not possible. You need to use `transmute`:
-///
-/// ```rust
-/// # #[cfg(not(miri))] { // FIXME: use strict provenance APIs once they are stable, then remove this `cfg`
-/// # let fnptr: fn(i32) -> i32 = |x| x+2;
-/// # let fnptr_addr = fnptr as usize;
-/// let fnptr = fnptr_addr as *const ();
-/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
-/// assert_eq!(fnptr(40), 42);
-/// # }
-/// ```
-///
-/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
-/// This avoids an integer-to-pointer `transmute`, which can be problematic.
-/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
-///
-/// Note that all of this is not portable to platforms where function pointers and data pointers
-/// have different sizes.
-///
-/// ### Trait implementations
-///
-/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
-/// function pointers of varying length. Note that this is a convenience notation to avoid
-/// repetitive documentation, not valid Rust syntax.
-///
-/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
-/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
-/// may change:
-///
-/// * [`PartialEq`]
-/// * [`Eq`]
-/// * [`PartialOrd`]
-/// * [`Ord`]
-/// * [`Hash`]
-/// * [`Pointer`]
-/// * [`Debug`]
-///
-/// The following traits are implemented for function pointers with any number of arguments and
-/// any ABI. These traits have implementations that are automatically generated by the compiler,
-/// so are not limited by missing language features:
-///
-/// * [`Clone`]
-/// * [`Copy`]
-/// * [`Send`]
-/// * [`Sync`]
-/// * [`Unpin`]
-/// * [`UnwindSafe`]
-/// * [`RefUnwindSafe`]
-///
-/// [`Hash`]: hash::Hash
-/// [`Pointer`]: fmt::Pointer
-/// [`UnwindSafe`]: panic::UnwindSafe
-/// [`RefUnwindSafe`]: panic::RefUnwindSafe
-///
-/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
-/// these traits are specially known to the compiler.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_fn {}
-
-// Required to make auto trait impls render.
-// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
-#[doc(hidden)]
-impl<Ret, T> fn(T) -> Ret {}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on function pointers with any number of arguments.
-impl<Ret, T> Clone for fn(T) -> Ret {
-    fn clone(&self) -> Self {
-        loop {}
-    }
-}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on function pointers with any number of arguments.
-impl<Ret, T> Copy for fn(T) -> Ret {
-    // empty
-}
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index f92bb1a4b1f..d353c7bd5de 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -626,11 +626,6 @@ impl<T> Clone for Sender<T> {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Sender<T> {
-    fn drop(&mut self) {}
-}
-
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for Sender<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -755,11 +750,6 @@ impl<T> Clone for SyncSender<T> {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for SyncSender<T> {
-    fn drop(&mut self) {}
-}
-
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for SyncSender<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1096,11 +1086,6 @@ impl<T> IntoIterator for Receiver<T> {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Receiver<T> {
-    fn drop(&mut self) {}
-}
-
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for Receiver<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index e4581c2de78..7b26068c294 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -178,7 +178,7 @@ use crate::sys_common::thread;
 use crate::sys_common::thread_info;
 use crate::sys_common::thread_parking::Parker;
 use crate::sys_common::{AsInner, IntoInner};
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
 
 #[stable(feature = "scoped_threads", since = "1.63.0")]
 mod scoped;
@@ -872,6 +872,86 @@ pub fn sleep(dur: Duration) {
     imp::Thread::sleep(dur)
 }
 
+/// Puts the current thread to sleep until the specified deadline has passed.
+///
+/// The thread may still be asleep after the deadline specified due to
+/// scheduling specifics or platform-dependent functionality. It will never
+/// wake before.
+///
+/// This function is blocking, and should not be used in `async` functions.
+///
+/// # Platform-specific behavior
+///
+/// This function uses [`sleep`] internally, see its platform-specific behaviour.
+///
+///
+/// # Examples
+///
+/// A simple game loop that limits the game to 60 frames per second.
+///
+/// ```no_run
+/// #![feature(thread_sleep_until)]
+/// # use std::time::{Duration, Instant};
+/// # use std::thread;
+/// #
+/// # fn update() {}
+/// # fn render() {}
+/// #
+/// let max_fps = 60.0;
+/// let frame_time = Duration::from_secs_f32(1.0/max_fps);
+/// let mut next_frame = Instant::now();
+/// loop {
+///     thread::sleep_until(next_frame);
+///     next_frame += frame_time;
+///     update();
+///     render();
+/// }
+/// ```
+///
+/// A slow api we must not call too fast and which takes a few
+/// tries before succeeding. By using `sleep_until` the time the
+/// api call takes does not influence when we retry or when we give up
+///
+/// ```no_run
+/// #![feature(thread_sleep_until)]
+/// # use std::time::{Duration, Instant};
+/// # use std::thread;
+/// #
+/// # enum Status {
+/// #     Ready(usize),
+/// #     Waiting,
+/// # }
+/// # fn slow_web_api_call() -> Status { Status::Ready(42) }
+/// #
+/// # const MAX_DURATION: Duration = Duration::from_secs(10);
+/// #
+/// # fn try_api_call() -> Result<usize, ()> {
+/// let deadline = Instant::now() + MAX_DURATION;
+/// let delay = Duration::from_millis(250);
+/// let mut next_attempt = Instant::now();
+/// loop {
+///     if Instant::now() > deadline {
+///         break Err(());
+///     }
+///     if let Status::Ready(data) = slow_web_api_call() {
+///         break Ok(data);
+///     }
+///
+///     next_attempt = deadline.min(next_attempt + delay);
+///     thread::sleep_until(next_attempt);
+/// }
+/// # }
+/// # let _data = try_api_call();
+/// ```
+#[unstable(feature = "thread_sleep_until", issue = "113752")]
+pub fn sleep_until(deadline: Instant) {
+    let now = Instant::now();
+
+    if let Some(delay) = deadline.checked_duration_since(now) {
+        sleep(delay);
+    }
+}
+
 /// Used to ensure that `park` and `park_timeout` do not unwind, as that can
 /// cause undefined behaviour if not handled correctly (see #102398 for context).
 struct PanicGuard;
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index 253d504d7bd..548281ca506 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -1,8 +1,7 @@
 # rustbuild - Bootstrapping Rust
 
-This is an in-progress README which is targeted at helping to explain how Rust
-is bootstrapped and in general, some of the technical details of the build
-system.
+This README is aimed at helping to explain how Rust is bootstrapped and in general,
+some of the technical details of the build system.
 
 Note that this README only covers internal information, not how to use the tool.
 Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information.
diff --git a/src/bootstrap/bin/_helper.rs b/src/bootstrap/bin/_helper.rs
new file mode 100644
index 00000000000..09aa471dba4
--- /dev/null
+++ b/src/bootstrap/bin/_helper.rs
@@ -0,0 +1,24 @@
+/// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`.
+/// If it was not defined, returns 0 by default.
+///
+/// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer.
+fn parse_rustc_verbose() -> usize {
+    use std::str::FromStr;
+
+    match std::env::var("RUSTC_VERBOSE") {
+        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
+        Err(_) => 0,
+    }
+}
+
+/// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`.
+///
+/// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
+fn parse_rustc_stage() -> String {
+    std::env::var("RUSTC_STAGE").unwrap_or_else(|_| {
+        // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
+        eprintln!("rustc shim: fatal: RUSTC_STAGE was not set");
+        eprintln!("rustc shim: note: use `x.py build -vvv` to see all environment variables set by bootstrap");
+        exit(101);
+    })
+}
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 10718aeb89f..20cd63b966b 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -16,27 +16,25 @@
 //! never get replaced.
 
 include!("../dylib_util.rs");
+include!("./_helper.rs");
 
 use std::env;
 use std::path::PathBuf;
 use std::process::{exit, Child, Command};
-use std::str::FromStr;
 use std::time::Instant;
 
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
     let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str());
 
+    let stage = parse_rustc_stage();
+    let verbose = parse_rustc_verbose();
+
     // Detect whether or not we're a build script depending on whether --target
     // is passed (a bit janky...)
     let target = arg("--target");
     let version = args.iter().find(|w| &**w == "-vV");
 
-    let verbose = match env::var("RUSTC_VERBOSE") {
-        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
-        Err(_) => 0,
-    };
-
     // Use a different compiler for build scripts, since there may not yet be a
     // libstd for the real compiler to use. However, if Cargo is attempting to
     // determine the version of the compiler, the real compiler needs to be
@@ -47,12 +45,7 @@ fn main() {
     } else {
         ("RUSTC_REAL", "RUSTC_LIBDIR")
     };
-    let stage = env::var("RUSTC_STAGE").unwrap_or_else(|_| {
-        // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
-        eprintln!("rustc shim: fatal: RUSTC_STAGE was not set");
-        eprintln!("rustc shim: note: use `x.py build -vvv` to see all environment variables set by bootstrap");
-        exit(101);
-    });
+
     let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
     let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);
 
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs
index 4ecb3349816..6561c1c1933 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/bin/rustdoc.rs
@@ -9,14 +9,14 @@ use std::process::{exit, Command};
 
 include!("../dylib_util.rs");
 
+include!("./_helper.rs");
+
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
-    let stage = env::var("RUSTC_STAGE").unwrap_or_else(|_| {
-        // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
-        eprintln!("rustc shim: fatal: RUSTC_STAGE was not set");
-        eprintln!("rustc shim: note: use `x.py build -vvv` to see all environment variables set by bootstrap");
-        exit(101);
-    });
+
+    let stage = parse_rustc_stage();
+    let verbose = parse_rustc_verbose();
+
     let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
     let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set");
     let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
@@ -25,13 +25,6 @@ fn main() {
     // is passed (a bit janky...)
     let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
 
-    use std::str::FromStr;
-
-    let verbose = match env::var("RUSTC_VERBOSE") {
-        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
-        Err(_) => 0,
-    };
-
     let mut dylib_path = dylib_path();
     dylib_path.insert(0, PathBuf::from(libdir.clone()));
 
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index e4c76226454..a9aa7524e8b 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -312,6 +312,14 @@ def default_build_triple(verbose):
         # non-standard string (e.g. gnuwin32 tools returns `windows32`). In
         # these cases, fall back to using sys.platform.
         return 'x86_64-pc-windows-msvc'
+    elif kernel == 'AIX':
+        # `uname -m` returns the machine ID rather than machine hardware on AIX,
+        # so we are unable to use cputype to form triple. AIX 7.2 and
+        # above supports 32-bit and 64-bit mode simultaneously and `uname -p`
+        # returns `powerpc`, however we only supports `powerpc64-ibm-aix` in
+        # rust on AIX. For above reasons, kerneltype_mapper and cputype_mapper
+        # are not used to infer AIX's triple.
+        return 'powerpc64-ibm-aix'
     else:
         err = "unknown OS type: {}".format(kernel)
         sys.exit(err)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 91fa5ec6633..50f1007e1ff 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -525,7 +525,7 @@ impl<'a> ShouldRun<'a> {
                 .iter()
                 .map(|p| {
                     // assert only if `p` isn't submodule
-                    if !submodules_paths.iter().find(|sm_p| p.contains(*sm_p)).is_some() {
+                    if submodules_paths.iter().find(|sm_p| p.contains(*sm_p)).is_none() {
                         assert!(
                             self.builder.src.join(p).exists(),
                             "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 9c68e5a78d8..4f19ffa83db 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -570,6 +570,9 @@ fn copy_sanitizers(
         let dst = libdir.join(&runtime.name);
         builder.copy(&runtime.path, &dst);
 
+        // The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for
+        // sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do
+        // not list them here to rename and sign the runtime library.
         if target == "x86_64-apple-darwin"
             || target == "aarch64-apple-darwin"
             || target == "aarch64-apple-ios"
@@ -876,10 +879,8 @@ impl Step for Rustc {
                     cargo.rustflag("-Clto=off");
                 }
             }
-        } else {
-            if builder.config.rust_lto == RustcLto::Off {
-                cargo.rustflag("-Clto=off");
-            }
+        } else if builder.config.rust_lto == RustcLto::Off {
+            cargo.rustflag("-Clto=off");
         }
 
         for krate in &*self.crates {
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index e5fdac3ceda..176ef8e92db 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -322,33 +322,23 @@ pub struct RustfmtMetadata {
     pub version: String,
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
 pub enum RustfmtState {
     SystemToolchain(PathBuf),
     Downloaded(PathBuf),
     Unavailable,
+    #[default]
     LazyEvaluated,
 }
 
-impl Default for RustfmtState {
-    fn default() -> Self {
-        RustfmtState::LazyEvaluated
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Default, Clone, Copy, PartialEq)]
 pub enum LlvmLibunwind {
+    #[default]
     No,
     InTree,
     System,
 }
 
-impl Default for LlvmLibunwind {
-    fn default() -> Self {
-        Self::No
-    }
-}
-
 impl FromStr for LlvmLibunwind {
     type Err = String;
 
@@ -362,19 +352,14 @@ impl FromStr for LlvmLibunwind {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum SplitDebuginfo {
     Packed,
     Unpacked,
+    #[default]
     Off,
 }
 
-impl Default for SplitDebuginfo {
-    fn default() -> Self {
-        SplitDebuginfo::Off
-    }
-}
-
 impl std::str::FromStr for SplitDebuginfo {
     type Err = ();
 
@@ -1529,7 +1514,7 @@ impl Config {
             let asserts = llvm_assertions.unwrap_or(false);
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
-                    assert!(s == "if-available", "unknown option `{s}` for download-ci-llvm");
+                    assert_eq!(s, "if-available", "unknown option `{s}` for download-ci-llvm");
                     crate::llvm::is_ci_llvm_available(&config, asserts)
                 }
                 Some(StringOrBool::Bool(b)) => b,
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs
index b8f3be96062..aac76cdcbcf 100644
--- a/src/bootstrap/config/tests.rs
+++ b/src/bootstrap/config/tests.rs
@@ -136,7 +136,7 @@ build-config = {}
         "setting string value without quotes"
     );
     assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes");
-    assert_eq!(config.deny_warnings, false, "setting boolean value");
+    assert!(!config.deny_warnings, "setting boolean value");
     assert_eq!(
         config.tools,
         Some(["cargo".to_string()].into_iter().collect()),
@@ -181,13 +181,13 @@ fn profile_user_dist() {
 
 #[test]
 fn rust_optimize() {
-    assert_eq!(parse("").rust_optimize.is_release(), true);
-    assert_eq!(parse("rust.optimize = false").rust_optimize.is_release(), false);
-    assert_eq!(parse("rust.optimize = true").rust_optimize.is_release(), true);
-    assert_eq!(parse("rust.optimize = 0").rust_optimize.is_release(), false);
-    assert_eq!(parse("rust.optimize = 1").rust_optimize.is_release(), true);
+    assert!(parse("").rust_optimize.is_release());
+    assert!(!parse("rust.optimize = false").rust_optimize.is_release());
+    assert!(parse("rust.optimize = true").rust_optimize.is_release());
+    assert!(!parse("rust.optimize = 0").rust_optimize.is_release());
+    assert!(parse("rust.optimize = 1").rust_optimize.is_release());
+    assert!(parse("rust.optimize = \"s\"").rust_optimize.is_release());
     assert_eq!(parse("rust.optimize = 1").rust_optimize.get_opt_level(), Some("1".to_string()));
-    assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.is_release(), true);
     assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.get_opt_level(), Some("s".to_string()));
 }
 
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index 9489297d67d..8e9614ec89a 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -441,7 +441,7 @@ impl Config {
     }
 
     pub(crate) fn download_beta_toolchain(&self) {
-        self.verbose(&format!("downloading stage0 beta artifacts"));
+        self.verbose("downloading stage0 beta artifacts");
 
         let date = &self.stage0_metadata.compiler.date;
         let version = &self.stage0_metadata.compiler.version;
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 671d25484d0..1e001fae8ab 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -116,7 +116,7 @@ pub const VERSION: usize = 2;
 
 /// Extra --check-cfg to add when building
 /// (Mode restriction, config name, config values (if any))
-const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] = &[
+const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (None, "bootstrap", None),
     (Some(Mode::Rustc), "parallel_compiler", None),
     (Some(Mode::ToolRustc), "parallel_compiler", None),
@@ -1757,10 +1757,11 @@ to download LLVM rather than building it.
         //
         // In these cases we automatically enable Ninja if we find it in the
         // environment.
-        if !self.config.ninja_in_file && self.config.build.contains("msvc") {
-            if cmd_finder.maybe_have("ninja").is_some() {
-                return true;
-            }
+        if !self.config.ninja_in_file
+            && self.config.build.contains("msvc")
+            && cmd_finder.maybe_have("ninja").is_some()
+        {
+            return true;
         }
 
         self.config.ninja_in_file
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index aefed501513..7e5ade50ca7 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -155,7 +155,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
         "".to_owned()
     };
 
-    if &llvm_sha == "" {
+    if llvm_sha.is_empty() {
         eprintln!("error: could not find commit hash for downloading LLVM");
         eprintln!("help: maybe your repository history is too shallow?");
         eprintln!("help: consider disabling `download-ci-llvm`");
@@ -208,10 +208,10 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
         ("x86_64-unknown-netbsd", false),
     ];
 
-    if !supported_platforms.contains(&(&*config.build.triple, asserts)) {
-        if asserts == true || !supported_platforms.contains(&(&*config.build.triple, true)) {
-            return false;
-        }
+    if !supported_platforms.contains(&(&*config.build.triple, asserts))
+        && (asserts || !supported_platforms.contains(&(&*config.build.triple, true)))
+    {
+        return false;
     }
 
     if is_ci_llvm_modified(config) {
@@ -497,11 +497,11 @@ impl Step for Llvm {
             let mut cmd = Command::new(&res.llvm_config);
             let version = output(cmd.arg("--version"));
             let major = version.split('.').next().unwrap();
-            let lib_name = match &llvm_version_suffix {
+
+            match &llvm_version_suffix {
                 Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"),
                 None => format!("libLLVM-{major}.{extension}"),
-            };
-            lib_name
+            }
         };
 
         // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
@@ -756,13 +756,15 @@ fn configure_cmake(
 
     // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
     // We also do this if the user explicitly requested static libstdc++.
-    if builder.config.llvm_static_stdcpp {
-        if !target.contains("msvc") && !target.contains("netbsd") && !target.contains("solaris") {
-            if target.contains("apple") || target.contains("windows") {
-                ldflags.push_all("-static-libstdc++");
-            } else {
-                ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
-            }
+    if builder.config.llvm_static_stdcpp
+        && !target.contains("msvc")
+        && !target.contains("netbsd")
+        && !target.contains("solaris")
+    {
+        if target.contains("apple") || target.contains("windows") {
+            ldflags.push_all("-static-libstdc++");
+        } else {
+            ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
         }
     }
 
@@ -1061,6 +1063,7 @@ fn supported_sanitizers(
         "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "aarch64-apple-ios" => darwin_libs("ios", &["asan", "tsan"]),
         "aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan"]),
+        "aarch64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
         "aarch64-unknown-linux-gnu" => {
             common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
@@ -1071,6 +1074,7 @@ fn supported_sanitizers(
         "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
         "x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]),
+        "x86_64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]),
         "x86_64-unknown-netbsd" => {
             common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"])
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 144e2acd09e..0febdf250d3 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -95,20 +95,19 @@ pub fn check(build: &mut Build) {
                     .unwrap_or(true)
             })
             .any(|build_llvm_ourselves| build_llvm_ourselves);
+
     let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
-    if need_cmake {
-        if cmd_finder.maybe_have("cmake").is_none() {
-            eprintln!(
-                "
+    if need_cmake && cmd_finder.maybe_have("cmake").is_none() {
+        eprintln!(
+            "
 Couldn't find required command: cmake
 
 You should install cmake, or set `download-ci-llvm = true` in the
 `[llvm]` section of `config.toml` to download LLVM rather
 than building it.
 "
-            );
-            crate::exit!(1);
-        }
+        );
+        crate::exit!(1);
     }
 
     build.config.python = build
@@ -202,10 +201,10 @@ than building it.
             .entry(*target)
             .or_insert_with(|| Target::from_triple(&target.triple));
 
-        if target.contains("-none-") || target.contains("nvptx") {
-            if build.no_std(*target) == Some(false) {
-                panic!("All the *-none-* and nvptx* targets are no-std targets")
-            }
+        if (target.contains("-none-") || target.contains("nvptx"))
+            && build.no_std(*target) == Some(false)
+        {
+            panic!("All the *-none-* and nvptx* targets are no-std targets")
         }
 
         // Some environments don't want or need these tools, such as when testing Miri.
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 30730f50491..ef0234957b5 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -33,6 +33,7 @@ static SETTINGS_HASHES: &[&str] = &[
     "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
     "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
     "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+    "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
 ];
 static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json");
 
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 35e2e98e08e..ba030f0f525 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -846,7 +846,7 @@ impl Step for RustdocTheme {
         let rustdoc = builder.bootstrap_out.join("rustdoc");
         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
         cmd.arg(rustdoc.to_str().unwrap())
-            .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
+            .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
             .env("RUSTC_STAGE", self.compiler.stage.to_string())
             .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
             .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
@@ -1139,16 +1139,14 @@ help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
             .map(|filename| builder.src.join("src/etc/completions").join(filename));
         if builder.config.cmd.bless() {
             builder.ensure(crate::run::GenerateCompletions);
-        } else {
-            if crate::flags::get_completion(shells::Bash, &bash).is_some()
-                || crate::flags::get_completion(shells::Fish, &fish).is_some()
-                || crate::flags::get_completion(shells::PowerShell, &powershell).is_some()
-            {
-                eprintln!(
-                    "x.py completions were changed; run `x.py run generate-completions` to update them"
-                );
-                crate::exit!(1);
-            }
+        } else if crate::flags::get_completion(shells::Bash, &bash).is_some()
+            || crate::flags::get_completion(shells::Fish, &fish).is_some()
+            || crate::flags::get_completion(shells::PowerShell, &powershell).is_some()
+        {
+            eprintln!(
+                "x.py completions were changed; run `x.py run generate-completions` to update them"
+            );
+            crate::exit!(1);
         }
     }
 
@@ -1378,7 +1376,7 @@ impl Step for MirOpt {
         let run = |target| {
             builder.ensure(Compiletest {
                 compiler: self.compiler,
-                target: target,
+                target,
                 mode: "mir-opt",
                 suite: "mir-opt",
                 path: "tests/mir-opt",
diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile
index b6b4fdc67a9..db11700af28 100644
--- a/src/ci/docker/host-x86_64/arm-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.10
+FROM ubuntu:23.04
 
 ARG DEBIAN_FRONTEND=noninteractive
 COPY scripts/android-base-apt-get.sh /scripts/
diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile
index 9c6f648896b..b09b6edb01a 100644
--- a/src/ci/docker/host-x86_64/dist-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.10
+FROM ubuntu:23.04
 
 COPY scripts/android-base-apt-get.sh /scripts/
 RUN sh /scripts/android-base-apt-get.sh
diff --git a/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh b/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh
index dad97922338..f86402b0180 100755
--- a/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh
+++ b/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh
@@ -2,5 +2,5 @@
 
 set -ex
 
-curl https://static.redox-os.org/toolchain/x86_64-unknown-redox/relibc-install.tar.gz | \
+curl https://ci-mirrors.rust-lang.org/rustc/2022-11-27-relibc-install.tar.gz | \
 tar --extract --gzip --directory /usr/local
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index f6954275ad4..6f1b2a6a638 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -87,7 +87,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set rust.lto=thin
 
 ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \
-    ./build/$HOSTS/stage0-tools-bin/opt-dist python3 ../x.py dist \
+    ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
     build-manifest bootstrap
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index b31629ad605..0d67319168d 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.16.8
\ No newline at end of file
+0.16.9
\ No newline at end of file
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 89b82d59d31..973b9a0a089 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -114,7 +114,7 @@ x--expand-yaml-anchors--remove:
         run: git config --global core.autocrlf false
 
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 2
 
@@ -624,7 +624,7 @@ jobs:
                 --target=x86_64-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
-              SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths
+              SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-8c
 
@@ -707,7 +707,7 @@ jobs:
     if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 2
 
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index f69156b7c05..0d3f6338af4 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -625,3 +625,47 @@ and check the values of `feature`: `foo` and `bar`.
 
 This flag enables the generation of links in the source code pages which allow the reader
 to jump to a type definition.
+
+### Custom CSS classes for code blocks
+
+```rust
+#![feature(custom_code_classes_in_docs)]
+
+/// ```custom,{class=language-c}
+/// int main(void) { return 0; }
+/// ```
+pub struct Bar;
+```
+
+The text `int main(void) { return 0; }` is rendered without highlighting in a code block
+with the class `language-c`. This can be used to highlight other languages through JavaScript
+libraries for example.
+
+Without the `custom` attribute, it would be generated as a Rust code example with an additional
+`language-C` CSS class. Therefore, if you specifically don't want it to be a Rust code example,
+don't forget to add the `custom` attribute.
+
+To be noted that you can replace `class=` with `.` to achieve the same result:
+
+```rust
+#![feature(custom_code_classes_in_docs)]
+
+/// ```custom,{.language-c}
+/// int main(void) { return 0; }
+/// ```
+pub struct Bar;
+```
+
+To be noted, `rust` and `.rust`/`class=rust` have different effects: `rust` indicates that this is
+a Rust code block whereas the two others add a "rust" CSS class on the code block.
+
+You can also use double quotes:
+
+```rust
+#![feature(custom_code_classes_in_docs)]
+
+/// ```"not rust" {."hello everyone"}
+/// int main(void) { return 0; }
+/// ```
+pub struct Bar;
+```
diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json
index 6e5e2c35005..32a04cfd5d1 100644
--- a/src/etc/rust_analyzer_settings.json
+++ b/src/etc/rust_analyzer_settings.json
@@ -16,10 +16,10 @@
         "compiler/rustc_codegen_gcc/Cargo.toml"
     ],
     "rust-analyzer.rustfmt.overrideCommand": [
-        "./build/host/rustfmt/bin/rustfmt",
+        "${workspaceFolder}/build/host/rustfmt/bin/rustfmt",
         "--edition=2021"
     ],
-    "rust-analyzer.procMacro.server": "./build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
+    "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
     "rust-analyzer.procMacro.enable": true,
     "rust-analyzer.cargo.buildScripts.enable": true,
     "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 974dc1c5135..99aa979027f 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -410,9 +410,15 @@ impl Options {
 
         let to_check = matches.opt_strs("check-theme");
         if !to_check.is_empty() {
-            let paths = match theme::load_css_paths(
-                std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
-            ) {
+            let mut content =
+                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap();
+            if let Some((_, inside)) = content.split_once("/* Begin theme: light */") {
+                content = inside;
+            }
+            if let Some((inside, _)) = content.split_once("/* End theme: light */") {
+                content = inside;
+            }
+            let paths = match theme::load_css_paths(content) {
                 Ok(p) => p,
                 Err(e) => {
                     diag.struct_err(e).emit();
@@ -550,9 +556,15 @@ impl Options {
 
         let mut themes = Vec::new();
         if matches.opt_present("theme") {
-            let paths = match theme::load_css_paths(
-                std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
-            ) {
+            let mut content =
+                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap();
+            if let Some((_, inside)) = content.split_once("/* Begin theme: light */") {
+                content = inside;
+            }
+            if let Some((inside, _)) = content.split_once("/* End theme: light */") {
+                content = inside;
+            }
+            let paths = match theme::load_css_paths(content) {
                 Ok(p) => p,
                 Err(e) => {
                     diag.struct_err(e).emit();
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index ea87268877f..24597c3aca3 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1243,6 +1243,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
                     def_id.to_def_id(),
                     span_of_fragments(&attrs.doc_strings).unwrap_or(sp),
                 )),
+                self.tcx.features().custom_code_classes_in_docs,
             );
         }
 
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index f0ebb8e5a39..b34b69b1f15 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -46,6 +46,8 @@ impl ExternalHtml {
                 edition,
                 playground,
                 heading_offset: HeadingOffset::H2,
+                // For external files, it'll be disabled until the feature is enabled by default.
+                custom_code_classes_in_docs: false,
             }
             .into_string()
         );
@@ -61,6 +63,8 @@ impl ExternalHtml {
                 edition,
                 playground,
                 heading_offset: HeadingOffset::H2,
+                // For external files, it'll be disabled until the feature is enabled by default.
+                custom_code_classes_in_docs: false,
             }
             .into_string()
         );
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 039e8cdb987..d8e36139a78 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -52,8 +52,9 @@ pub(crate) fn render_example_with_highlighting(
     out: &mut Buffer,
     tooltip: Tooltip,
     playground_button: Option<&str>,
+    extra_classes: &[String],
 ) {
-    write_header(out, "rust-example-rendered", None, tooltip);
+    write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
     write_code(out, src, None, None);
     write_footer(out, playground_button);
 }
@@ -65,7 +66,13 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
     write!(out, "</pre>");
 }
 
-fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
+fn write_header(
+    out: &mut Buffer,
+    class: &str,
+    extra_content: Option<Buffer>,
+    tooltip: Tooltip,
+    extra_classes: &[String],
+) {
     write!(
         out,
         "<div class=\"example-wrap{}\">",
@@ -100,9 +107,19 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, to
         out.push_buffer(extra);
     }
     if class.is_empty() {
-        write!(out, "<pre class=\"rust\">");
+        write!(
+            out,
+            "<pre class=\"rust{}{}\">",
+            if extra_classes.is_empty() { "" } else { " " },
+            extra_classes.join(" "),
+        );
     } else {
-        write!(out, "<pre class=\"rust {class}\">");
+        write!(
+            out,
+            "<pre class=\"rust {class}{}{}\">",
+            if extra_classes.is_empty() { "" } else { " " },
+            extra_classes.join(" "),
+        );
     }
     write!(out, "<code>");
 }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b28019e3f91..59958fbaef9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -20,12 +20,14 @@
 //!     edition: Edition::Edition2015,
 //!     playground: &None,
 //!     heading_offset: HeadingOffset::H2,
+//!     custom_code_classes_in_docs: true,
 //! };
 //! let html = md.into_string();
 //! // ... something using html
 //! ```
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
 pub(crate) use rustc_resolve::rustdoc::main_body_opts;
@@ -37,8 +39,9 @@ use once_cell::sync::Lazy;
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::Write;
+use std::iter::Peekable;
 use std::ops::{ControlFlow, Range};
-use std::str;
+use std::str::{self, CharIndices};
 
 use crate::clean::RenderedLink;
 use crate::doctest;
@@ -93,6 +96,8 @@ pub struct Markdown<'a> {
     /// Offset at which we render headings.
     /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
     pub heading_offset: HeadingOffset,
+    /// `true` if the `custom_code_classes_in_docs` feature is enabled.
+    pub custom_code_classes_in_docs: bool,
 }
 /// A struct like `Markdown` that renders the markdown with a table of contents.
 pub(crate) struct MarkdownWithToc<'a> {
@@ -101,6 +106,8 @@ pub(crate) struct MarkdownWithToc<'a> {
     pub(crate) error_codes: ErrorCodes,
     pub(crate) edition: Edition,
     pub(crate) playground: &'a Option<Playground>,
+    /// `true` if the `custom_code_classes_in_docs` feature is enabled.
+    pub(crate) custom_code_classes_in_docs: bool,
 }
 /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags
 /// and includes no paragraph tags.
@@ -201,6 +208,7 @@ struct CodeBlocks<'p, 'a, I: Iterator<Item = Event<'a>>> {
     // Information about the playground if a URL has been specified, containing an
     // optional crate name and the URL.
     playground: &'p Option<Playground>,
+    custom_code_classes_in_docs: bool,
 }
 
 impl<'p, 'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'p, 'a, I> {
@@ -209,8 +217,15 @@ impl<'p, 'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'p, 'a, I> {
         error_codes: ErrorCodes,
         edition: Edition,
         playground: &'p Option<Playground>,
+        custom_code_classes_in_docs: bool,
     ) -> Self {
-        CodeBlocks { inner: iter, check_error_codes: error_codes, edition, playground }
+        CodeBlocks {
+            inner: iter,
+            check_error_codes: error_codes,
+            edition,
+            playground,
+            custom_code_classes_in_docs,
+        }
     }
 }
 
@@ -240,14 +255,28 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
 
         let parse_result = match kind {
             CodeBlockKind::Fenced(ref lang) => {
-                let parse_result =
-                    LangString::parse_without_check(lang, self.check_error_codes, false);
+                let parse_result = LangString::parse_without_check(
+                    lang,
+                    self.check_error_codes,
+                    false,
+                    self.custom_code_classes_in_docs,
+                );
                 if !parse_result.rust {
+                    let added_classes = parse_result.added_classes;
+                    let lang_string = if let Some(lang) = parse_result.unknown.first() {
+                        format!("language-{}", lang)
+                    } else {
+                        String::new()
+                    };
+                    let whitespace = if added_classes.is_empty() { "" } else { " " };
                     return Some(Event::Html(
                         format!(
                             "<div class=\"example-wrap\">\
-                                 <pre class=\"language-{lang}\"><code>{text}</code></pre>\
+                                 <pre class=\"{lang_string}{whitespace}{added_classes}\">\
+                                     <code>{text}</code>\
+                                 </pre>\
                              </div>",
+                            added_classes = added_classes.join(" "),
                             text = Escape(&original_text),
                         )
                         .into(),
@@ -258,6 +287,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             CodeBlockKind::Indented => Default::default(),
         };
 
+        let added_classes = parse_result.added_classes;
         let lines = original_text.lines().filter_map(|l| map_line(l).for_html());
         let text = lines.intersperse("\n".into()).collect::<String>();
 
@@ -315,6 +345,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             &mut s,
             tooltip,
             playground_button.as_deref(),
+            &added_classes,
         );
         Some(Event::Html(s.into_inner().into()))
     }
@@ -711,6 +742,27 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
     error_codes: ErrorCodes,
     enable_per_target_ignores: bool,
     extra_info: Option<&ExtraInfo<'_>>,
+    custom_code_classes_in_docs: bool,
+) {
+    find_codes(
+        doc,
+        tests,
+        error_codes,
+        enable_per_target_ignores,
+        extra_info,
+        false,
+        custom_code_classes_in_docs,
+    )
+}
+
+pub(crate) fn find_codes<T: doctest::Tester>(
+    doc: &str,
+    tests: &mut T,
+    error_codes: ErrorCodes,
+    enable_per_target_ignores: bool,
+    extra_info: Option<&ExtraInfo<'_>>,
+    include_non_rust: bool,
+    custom_code_classes_in_docs: bool,
 ) {
     let mut parser = Parser::new(doc).into_offset_iter();
     let mut prev_offset = 0;
@@ -729,12 +781,13 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
                                 error_codes,
                                 enable_per_target_ignores,
                                 extra_info,
+                                custom_code_classes_in_docs,
                             )
                         }
                     }
                     CodeBlockKind::Indented => Default::default(),
                 };
-                if !block_info.rust {
+                if !include_non_rust && !block_info.rust {
                     continue;
                 }
 
@@ -784,7 +837,23 @@ impl<'tcx> ExtraInfo<'tcx> {
         ExtraInfo { def_id, sp, tcx }
     }
 
-    fn error_invalid_codeblock_attr(&self, msg: String, help: &'static str) {
+    fn error_invalid_codeblock_attr(&self, msg: impl Into<DiagnosticMessage>) {
+        if let Some(def_id) = self.def_id.as_local() {
+            self.tcx.struct_span_lint_hir(
+                crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
+                self.tcx.hir().local_def_id_to_hir_id(def_id),
+                self.sp,
+                msg,
+                |l| l,
+            );
+        }
+    }
+
+    fn error_invalid_codeblock_attr_with_help(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+        help: impl Into<SubdiagnosticMessage>,
+    ) {
         if let Some(def_id) = self.def_id.as_local() {
             self.tcx.struct_span_lint_hir(
                 crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
@@ -808,6 +877,8 @@ pub(crate) struct LangString {
     pub(crate) compile_fail: bool,
     pub(crate) error_codes: Vec<String>,
     pub(crate) edition: Option<Edition>,
+    pub(crate) added_classes: Vec<String>,
+    pub(crate) unknown: Vec<String>,
 }
 
 #[derive(Eq, PartialEq, Clone, Debug)]
@@ -817,6 +888,276 @@ pub(crate) enum Ignore {
     Some(Vec<String>),
 }
 
+/// This is the parser for fenced codeblocks attributes. It implements the following eBNF:
+///
+/// ```eBNF
+/// lang-string = *(token-list / delimited-attribute-list / comment)
+///
+/// bareword = CHAR *(CHAR)
+/// quoted-string = QUOTE *(NONQUOTE) QUOTE
+/// token = bareword / quoted-string
+/// sep = COMMA/WS *(COMMA/WS)
+/// attribute = (DOT token)/(token EQUAL token)
+/// attribute-list = [sep] attribute *(sep attribute) [sep]
+/// delimited-attribute-list = OPEN-CURLY-BRACKET attribute-list CLOSE-CURLY-BRACKET
+/// token-list = [sep] token *(sep token) [sep]
+/// comment = OPEN_PAREN *(all characters) CLOSE_PAREN
+///
+/// OPEN_PAREN = "("
+/// CLOSE_PARENT = ")"
+/// OPEN-CURLY-BRACKET = "{"
+/// CLOSE-CURLY-BRACKET = "}"
+/// CHAR = ALPHA / DIGIT / "_" / "-" / ":"
+/// QUOTE = %x22
+/// NONQUOTE = %x09 / %x20 / %x21 / %x23-7E ; TAB / SPACE / all printable characters except `"`
+/// COMMA = ","
+/// DOT = "."
+/// EQUAL = "="
+///
+/// ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+/// DIGIT = %x30-39
+/// WS = %x09 / " "
+/// ```
+pub(crate) struct TagIterator<'a, 'tcx> {
+    inner: Peekable<CharIndices<'a>>,
+    data: &'a str,
+    is_in_attribute_block: bool,
+    extra: Option<&'a ExtraInfo<'tcx>>,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub(crate) enum LangStringToken<'a> {
+    LangToken(&'a str),
+    ClassAttribute(&'a str),
+    KeyValueAttribute(&'a str, &'a str),
+}
+
+fn is_bareword_char(c: char) -> bool {
+    c == '_' || c == '-' || c == ':' || c.is_ascii_alphabetic() || c.is_ascii_digit()
+}
+fn is_separator(c: char) -> bool {
+    c == ' ' || c == ',' || c == '\t'
+}
+
+struct Indices {
+    start: usize,
+    end: usize,
+}
+
+impl<'a, 'tcx> TagIterator<'a, 'tcx> {
+    pub(crate) fn new(data: &'a str, extra: Option<&'a ExtraInfo<'tcx>>) -> Self {
+        Self { inner: data.char_indices().peekable(), data, is_in_attribute_block: false, extra }
+    }
+
+    fn emit_error(&self, err: impl Into<DiagnosticMessage>) {
+        if let Some(extra) = self.extra {
+            extra.error_invalid_codeblock_attr(err);
+        }
+    }
+
+    fn skip_separators(&mut self) -> Option<usize> {
+        while let Some((pos, c)) = self.inner.peek() {
+            if !is_separator(*c) {
+                return Some(*pos);
+            }
+            self.inner.next();
+        }
+        None
+    }
+
+    fn parse_string(&mut self, start: usize) -> Option<Indices> {
+        while let Some((pos, c)) = self.inner.next() {
+            if c == '"' {
+                return Some(Indices { start: start + 1, end: pos });
+            }
+        }
+        self.emit_error("unclosed quote string `\"`");
+        None
+    }
+
+    fn parse_class(&mut self, start: usize) -> Option<LangStringToken<'a>> {
+        while let Some((pos, c)) = self.inner.peek().copied() {
+            if is_bareword_char(c) {
+                self.inner.next();
+            } else {
+                let class = &self.data[start + 1..pos];
+                if class.is_empty() {
+                    self.emit_error(format!("unexpected `{c}` character after `.`"));
+                    return None;
+                } else if self.check_after_token() {
+                    return Some(LangStringToken::ClassAttribute(class));
+                } else {
+                    return None;
+                }
+            }
+        }
+        let class = &self.data[start + 1..];
+        if class.is_empty() {
+            self.emit_error("missing character after `.`");
+            None
+        } else if self.check_after_token() {
+            Some(LangStringToken::ClassAttribute(class))
+        } else {
+            None
+        }
+    }
+
+    fn parse_token(&mut self, start: usize) -> Option<Indices> {
+        while let Some((pos, c)) = self.inner.peek() {
+            if !is_bareword_char(*c) {
+                return Some(Indices { start, end: *pos });
+            }
+            self.inner.next();
+        }
+        self.emit_error("unexpected end");
+        None
+    }
+
+    fn parse_key_value(&mut self, c: char, start: usize) -> Option<LangStringToken<'a>> {
+        let key_indices =
+            if c == '"' { self.parse_string(start)? } else { self.parse_token(start)? };
+        if key_indices.start == key_indices.end {
+            self.emit_error("unexpected empty string as key");
+            return None;
+        }
+
+        if let Some((_, c)) = self.inner.next() {
+            if c != '=' {
+                self.emit_error(format!("expected `=`, found `{}`", c));
+                return None;
+            }
+        } else {
+            self.emit_error("unexpected end");
+            return None;
+        }
+        let value_indices = match self.inner.next() {
+            Some((pos, '"')) => self.parse_string(pos)?,
+            Some((pos, c)) if is_bareword_char(c) => self.parse_token(pos)?,
+            Some((_, c)) => {
+                self.emit_error(format!("unexpected `{c}` character after `=`"));
+                return None;
+            }
+            None => {
+                self.emit_error("expected value after `=`");
+                return None;
+            }
+        };
+        if value_indices.start == value_indices.end {
+            self.emit_error("unexpected empty string as value");
+            None
+        } else if self.check_after_token() {
+            Some(LangStringToken::KeyValueAttribute(
+                &self.data[key_indices.start..key_indices.end],
+                &self.data[value_indices.start..value_indices.end],
+            ))
+        } else {
+            None
+        }
+    }
+
+    /// Returns `false` if an error was emitted.
+    fn check_after_token(&mut self) -> bool {
+        if let Some((_, c)) = self.inner.peek().copied() {
+            if c == '}' || is_separator(c) || c == '(' {
+                true
+            } else {
+                self.emit_error(format!("unexpected `{c}` character"));
+                false
+            }
+        } else {
+            // The error will be caught on the next iteration.
+            true
+        }
+    }
+
+    fn parse_in_attribute_block(&mut self) -> Option<LangStringToken<'a>> {
+        while let Some((pos, c)) = self.inner.next() {
+            if c == '}' {
+                self.is_in_attribute_block = false;
+                return self.next();
+            } else if c == '.' {
+                return self.parse_class(pos);
+            } else if c == '"' || is_bareword_char(c) {
+                return self.parse_key_value(c, pos);
+            } else {
+                self.emit_error(format!("unexpected character `{c}`"));
+                return None;
+            }
+        }
+        self.emit_error("unclosed attribute block (`{}`): missing `}` at the end");
+        None
+    }
+
+    /// Returns `false` if an error was emitted.
+    fn skip_paren_block(&mut self) -> bool {
+        while let Some((_, c)) = self.inner.next() {
+            if c == ')' {
+                return true;
+            }
+        }
+        self.emit_error("unclosed comment: missing `)` at the end");
+        false
+    }
+
+    fn parse_outside_attribute_block(&mut self, start: usize) -> Option<LangStringToken<'a>> {
+        while let Some((pos, c)) = self.inner.next() {
+            if c == '"' {
+                if pos != start {
+                    self.emit_error("expected ` `, `{` or `,` found `\"`");
+                    return None;
+                }
+                let indices = self.parse_string(pos)?;
+                if let Some((_, c)) = self.inner.peek().copied() && c != '{' && !is_separator(c) && c != '(' {
+                    self.emit_error(format!("expected ` `, `{{` or `,` after `\"`, found `{c}`"));
+                    return None;
+                }
+                return Some(LangStringToken::LangToken(&self.data[indices.start..indices.end]));
+            } else if c == '{' {
+                self.is_in_attribute_block = true;
+                return self.next();
+            } else if is_bareword_char(c) {
+                continue;
+            } else if is_separator(c) {
+                if pos != start {
+                    return Some(LangStringToken::LangToken(&self.data[start..pos]));
+                }
+                return self.next();
+            } else if c == '(' {
+                if !self.skip_paren_block() {
+                    return None;
+                }
+                if pos != start {
+                    return Some(LangStringToken::LangToken(&self.data[start..pos]));
+                }
+                return self.next();
+            } else {
+                self.emit_error(format!("unexpected character `{c}`"));
+                return None;
+            }
+        }
+        let token = &self.data[start..];
+        if token.is_empty() { None } else { Some(LangStringToken::LangToken(&self.data[start..])) }
+    }
+}
+
+impl<'a, 'tcx> Iterator for TagIterator<'a, 'tcx> {
+    type Item = LangStringToken<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let Some(start) = self.skip_separators() else {
+            if self.is_in_attribute_block {
+                self.emit_error("unclosed attribute block (`{}`): missing `}` at the end");
+            }
+            return None;
+        };
+        if self.is_in_attribute_block {
+            self.parse_in_attribute_block()
+        } else {
+            self.parse_outside_attribute_block(start)
+        }
+    }
+}
+
 impl Default for LangString {
     fn default() -> Self {
         Self {
@@ -829,6 +1170,8 @@ impl Default for LangString {
             compile_fail: false,
             error_codes: Vec::new(),
             edition: None,
+            added_classes: Vec::new(),
+            unknown: Vec::new(),
         }
     }
 }
@@ -838,33 +1181,15 @@ impl LangString {
         string: &str,
         allow_error_code_check: ErrorCodes,
         enable_per_target_ignores: bool,
-    ) -> LangString {
-        Self::parse(string, allow_error_code_check, enable_per_target_ignores, None)
-    }
-
-    fn tokens(string: &str) -> impl Iterator<Item = &str> {
-        // Pandoc, which Rust once used for generating documentation,
-        // expects lang strings to be surrounded by `{}` and for each token
-        // to be proceeded by a `.`. Since some of these lang strings are still
-        // loose in the wild, we strip a pair of surrounding `{}` from the lang
-        // string and a leading `.` from each token.
-
-        let string = string.trim();
-
-        let first = string.chars().next();
-        let last = string.chars().last();
-
-        let string = if first == Some('{') && last == Some('}') {
-            &string[1..string.len() - 1]
-        } else {
-            string
-        };
-
-        string
-            .split(|c| c == ',' || c == ' ' || c == '\t')
-            .map(str::trim)
-            .map(|token| token.strip_prefix('.').unwrap_or(token))
-            .filter(|token| !token.is_empty())
+        custom_code_classes_in_docs: bool,
+    ) -> Self {
+        Self::parse(
+            string,
+            allow_error_code_check,
+            enable_per_target_ignores,
+            None,
+            custom_code_classes_in_docs,
+        )
     }
 
     fn parse(
@@ -872,52 +1197,63 @@ impl LangString {
         allow_error_code_check: ErrorCodes,
         enable_per_target_ignores: bool,
         extra: Option<&ExtraInfo<'_>>,
-    ) -> LangString {
+        custom_code_classes_in_docs: bool,
+    ) -> Self {
         let allow_error_code_check = allow_error_code_check.as_bool();
         let mut seen_rust_tags = false;
         let mut seen_other_tags = false;
+        let mut seen_custom_tag = false;
         let mut data = LangString::default();
         let mut ignores = vec![];
 
         data.original = string.to_owned();
 
-        for token in Self::tokens(string) {
+        for token in TagIterator::new(string, extra) {
             match token {
-                "should_panic" => {
+                LangStringToken::LangToken("should_panic") => {
                     data.should_panic = true;
                     seen_rust_tags = !seen_other_tags;
                 }
-                "no_run" => {
+                LangStringToken::LangToken("no_run") => {
                     data.no_run = true;
                     seen_rust_tags = !seen_other_tags;
                 }
-                "ignore" => {
+                LangStringToken::LangToken("ignore") => {
                     data.ignore = Ignore::All;
                     seen_rust_tags = !seen_other_tags;
                 }
-                x if x.starts_with("ignore-") => {
+                LangStringToken::LangToken(x) if x.starts_with("ignore-") => {
                     if enable_per_target_ignores {
                         ignores.push(x.trim_start_matches("ignore-").to_owned());
                         seen_rust_tags = !seen_other_tags;
                     }
                 }
-                "rust" => {
+                LangStringToken::LangToken("rust") => {
                     data.rust = true;
                     seen_rust_tags = true;
                 }
-                "test_harness" => {
+                LangStringToken::LangToken("custom") => {
+                    if custom_code_classes_in_docs {
+                        seen_custom_tag = true;
+                    } else {
+                        seen_other_tags = true;
+                    }
+                }
+                LangStringToken::LangToken("test_harness") => {
                     data.test_harness = true;
                     seen_rust_tags = !seen_other_tags || seen_rust_tags;
                 }
-                "compile_fail" => {
+                LangStringToken::LangToken("compile_fail") => {
                     data.compile_fail = true;
                     seen_rust_tags = !seen_other_tags || seen_rust_tags;
                     data.no_run = true;
                 }
-                x if x.starts_with("edition") => {
+                LangStringToken::LangToken(x) if x.starts_with("edition") => {
                     data.edition = x[7..].parse::<Edition>().ok();
                 }
-                x if allow_error_code_check && x.starts_with('E') && x.len() == 5 => {
+                LangStringToken::LangToken(x)
+                    if allow_error_code_check && x.starts_with('E') && x.len() == 5 =>
+                {
                     if x[1..].parse::<u32>().is_ok() {
                         data.error_codes.push(x.to_owned());
                         seen_rust_tags = !seen_other_tags || seen_rust_tags;
@@ -925,7 +1261,7 @@ impl LangString {
                         seen_other_tags = true;
                     }
                 }
-                x if extra.is_some() => {
+                LangStringToken::LangToken(x) if extra.is_some() => {
                     let s = x.to_lowercase();
                     if let Some((flag, help)) = if s == "compile-fail"
                         || s == "compile_fail"
@@ -958,15 +1294,35 @@ impl LangString {
                         None
                     } {
                         if let Some(extra) = extra {
-                            extra.error_invalid_codeblock_attr(
+                            extra.error_invalid_codeblock_attr_with_help(
                                 format!("unknown attribute `{x}`. Did you mean `{flag}`?"),
                                 help,
                             );
                         }
                     }
                     seen_other_tags = true;
+                    data.unknown.push(x.to_owned());
+                }
+                LangStringToken::LangToken(x) => {
+                    seen_other_tags = true;
+                    data.unknown.push(x.to_owned());
+                }
+                LangStringToken::KeyValueAttribute(key, value) => {
+                    if custom_code_classes_in_docs {
+                        if key == "class" {
+                            data.added_classes.push(value.to_owned());
+                        } else if let Some(extra) = extra {
+                            extra.error_invalid_codeblock_attr(format!(
+                                "unsupported attribute `{key}`"
+                            ));
+                        }
+                    } else {
+                        seen_other_tags = true;
+                    }
+                }
+                LangStringToken::ClassAttribute(class) => {
+                    data.added_classes.push(class.to_owned());
                 }
-                _ => seen_other_tags = true,
             }
         }
 
@@ -975,7 +1331,7 @@ impl LangString {
             data.ignore = Ignore::Some(ignores);
         }
 
-        data.rust &= !seen_other_tags || seen_rust_tags;
+        data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags);
 
         data
     }
@@ -991,6 +1347,7 @@ impl Markdown<'_> {
             edition,
             playground,
             heading_offset,
+            custom_code_classes_in_docs,
         } = self;
 
         // This is actually common enough to special-case
@@ -1013,7 +1370,7 @@ impl Markdown<'_> {
         let p = Footnotes::new(p);
         let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
         let p = TableWrapper::new(p);
-        let p = CodeBlocks::new(p, codes, edition, playground);
+        let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs);
         html::push_html(&mut s, p);
 
         s
@@ -1022,7 +1379,14 @@ impl Markdown<'_> {
 
 impl MarkdownWithToc<'_> {
     pub(crate) fn into_string(self) -> String {
-        let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
+        let MarkdownWithToc {
+            content: md,
+            ids,
+            error_codes: codes,
+            edition,
+            playground,
+            custom_code_classes_in_docs,
+        } = self;
 
         let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
 
@@ -1034,7 +1398,7 @@ impl MarkdownWithToc<'_> {
             let p = HeadingLinks::new(p, Some(&mut toc), ids, HeadingOffset::H1);
             let p = Footnotes::new(p);
             let p = TableWrapper::new(p.map(|(ev, _)| ev));
-            let p = CodeBlocks::new(p, codes, edition, playground);
+            let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs);
             html::push_html(&mut s, p);
         }
 
@@ -1475,7 +1839,11 @@ pub(crate) struct RustCodeBlock {
 
 /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
 /// untagged (and assumed to be rust).
-pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeBlock> {
+pub(crate) fn rust_code_blocks(
+    md: &str,
+    extra_info: &ExtraInfo<'_>,
+    custom_code_classes_in_docs: bool,
+) -> Vec<RustCodeBlock> {
     let mut code_blocks = vec![];
 
     if md.is_empty() {
@@ -1492,7 +1860,13 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
                     let lang_string = if syntax.is_empty() {
                         Default::default()
                     } else {
-                        LangString::parse(&*syntax, ErrorCodes::Yes, false, Some(extra_info))
+                        LangString::parse(
+                            &*syntax,
+                            ErrorCodes::Yes,
+                            false,
+                            Some(extra_info),
+                            custom_code_classes_in_docs,
+                        )
                     };
                     if !lang_string.rust {
                         continue;
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index db8504d15c7..32957ac57fa 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -1,5 +1,8 @@
 use super::{find_testable_code, plain_text_summary, short_markdown_summary};
-use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownItemInfo};
+use super::{
+    ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, LangStringToken, Markdown,
+    MarkdownItemInfo, TagIterator,
+};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 
 #[test]
@@ -46,15 +49,37 @@ fn test_unique_id() {
 fn test_lang_string_parse() {
     fn t(lg: LangString) {
         let s = &lg.original;
-        assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg)
+        assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None, true), lg)
     }
 
     t(Default::default());
     t(LangString { original: "rust".into(), ..Default::default() });
-    t(LangString { original: ".rust".into(), ..Default::default() });
-    t(LangString { original: "{rust}".into(), ..Default::default() });
-    t(LangString { original: "{.rust}".into(), ..Default::default() });
-    t(LangString { original: "sh".into(), rust: false, ..Default::default() });
+    t(LangString {
+        original: "rusta".into(),
+        rust: false,
+        unknown: vec!["rusta".into()],
+        ..Default::default()
+    });
+    // error
+    t(LangString { original: "{rust}".into(), rust: true, ..Default::default() });
+    t(LangString {
+        original: "{.rust}".into(),
+        rust: true,
+        added_classes: vec!["rust".into()],
+        ..Default::default()
+    });
+    t(LangString {
+        original: "custom,{.rust}".into(),
+        rust: false,
+        added_classes: vec!["rust".into()],
+        ..Default::default()
+    });
+    t(LangString {
+        original: "sh".into(),
+        rust: false,
+        unknown: vec!["sh".into()],
+        ..Default::default()
+    });
     t(LangString { original: "ignore".into(), ignore: Ignore::All, ..Default::default() });
     t(LangString {
         original: "ignore-foo".into(),
@@ -70,41 +95,56 @@ fn test_lang_string_parse() {
         compile_fail: true,
         ..Default::default()
     });
-    t(LangString { original: "no_run,example".into(), no_run: true, ..Default::default() });
+    t(LangString {
+        original: "no_run,example".into(),
+        no_run: true,
+        unknown: vec!["example".into()],
+        ..Default::default()
+    });
     t(LangString {
         original: "sh,should_panic".into(),
         should_panic: true,
         rust: false,
+        unknown: vec!["sh".into()],
         ..Default::default()
     });
-    t(LangString { original: "example,rust".into(), ..Default::default() });
     t(LangString {
-        original: "test_harness,.rust".into(),
+        original: "example,rust".into(),
+        unknown: vec!["example".into()],
+        ..Default::default()
+    });
+    t(LangString {
+        original: "test_harness,rusta".into(),
         test_harness: true,
+        unknown: vec!["rusta".into()],
         ..Default::default()
     });
     t(LangString {
         original: "text, no_run".into(),
         no_run: true,
         rust: false,
+        unknown: vec!["text".into()],
         ..Default::default()
     });
     t(LangString {
         original: "text,no_run".into(),
         no_run: true,
         rust: false,
+        unknown: vec!["text".into()],
         ..Default::default()
     });
     t(LangString {
         original: "text,no_run, ".into(),
         no_run: true,
         rust: false,
+        unknown: vec!["text".into()],
         ..Default::default()
     });
     t(LangString {
         original: "text,no_run,".into(),
         no_run: true,
         rust: false,
+        unknown: vec!["text".into()],
         ..Default::default()
     });
     t(LangString {
@@ -117,29 +157,125 @@ fn test_lang_string_parse() {
         edition: Some(Edition::Edition2018),
         ..Default::default()
     });
+    t(LangString {
+        original: "{class=test}".into(),
+        added_classes: vec!["test".into()],
+        rust: true,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "custom,{class=test}".into(),
+        added_classes: vec!["test".into()],
+        rust: false,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "{.test}".into(),
+        added_classes: vec!["test".into()],
+        rust: true,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "custom,{.test}".into(),
+        added_classes: vec!["test".into()],
+        rust: false,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "rust,{class=test,.test2}".into(),
+        added_classes: vec!["test".into(), "test2".into()],
+        rust: true,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "{class=test:with:colon .test1}".into(),
+        added_classes: vec!["test:with:colon".into(), "test1".into()],
+        rust: true,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "custom,{class=test:with:colon .test1}".into(),
+        added_classes: vec!["test:with:colon".into(), "test1".into()],
+        rust: false,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "{class=first,class=second}".into(),
+        added_classes: vec!["first".into(), "second".into()],
+        rust: true,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "custom,{class=first,class=second}".into(),
+        added_classes: vec!["first".into(), "second".into()],
+        rust: false,
+        ..Default::default()
+    });
+    t(LangString {
+        original: "{class=first,.second},unknown".into(),
+        added_classes: vec!["first".into(), "second".into()],
+        rust: false,
+        unknown: vec!["unknown".into()],
+        ..Default::default()
+    });
+    t(LangString {
+        original: "{class=first .second} unknown".into(),
+        added_classes: vec!["first".into(), "second".into()],
+        rust: false,
+        unknown: vec!["unknown".into()],
+        ..Default::default()
+    });
+    // error
+    t(LangString { original: "{.first.second}".into(), rust: true, ..Default::default() });
+    // error
+    t(LangString { original: "{class=first=second}".into(), rust: true, ..Default::default() });
+    // error
+    t(LangString { original: "{class=first.second}".into(), rust: true, ..Default::default() });
+    // error
+    t(LangString { original: "{class=.first}".into(), rust: true, ..Default::default() });
+    t(LangString {
+        original: r#"{class="first"}"#.into(),
+        added_classes: vec!["first".into()],
+        rust: true,
+        ..Default::default()
+    });
+    t(LangString {
+        original: r#"custom,{class="first"}"#.into(),
+        added_classes: vec!["first".into()],
+        rust: false,
+        ..Default::default()
+    });
+    // error
+    t(LangString { original: r#"{class=f"irst"}"#.into(), rust: true, ..Default::default() });
 }
 
 #[test]
 fn test_lang_string_tokenizer() {
-    fn case(lang_string: &str, want: &[&str]) {
-        let have = LangString::tokens(lang_string).collect::<Vec<&str>>();
+    fn case(lang_string: &str, want: &[LangStringToken<'_>]) {
+        let have = TagIterator::new(lang_string, None).collect::<Vec<_>>();
         assert_eq!(have, want, "Unexpected lang string split for `{}`", lang_string);
     }
 
     case("", &[]);
-    case("foo", &["foo"]);
-    case("foo,bar", &["foo", "bar"]);
-    case(".foo,.bar", &["foo", "bar"]);
-    case("{.foo,.bar}", &["foo", "bar"]);
-    case("  {.foo,.bar}  ", &["foo", "bar"]);
-    case("foo bar", &["foo", "bar"]);
-    case("foo\tbar", &["foo", "bar"]);
-    case("foo\t, bar", &["foo", "bar"]);
-    case(" foo , bar ", &["foo", "bar"]);
-    case(",,foo,,bar,,", &["foo", "bar"]);
-    case("foo=bar", &["foo=bar"]);
-    case("a-b-c", &["a-b-c"]);
-    case("a_b_c", &["a_b_c"]);
+    case("foo", &[LangStringToken::LangToken("foo")]);
+    case("foo,bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
+    case(".foo,.bar", &[]);
+    case(
+        "{.foo,.bar}",
+        &[LangStringToken::ClassAttribute("foo"), LangStringToken::ClassAttribute("bar")],
+    );
+    case(
+        "  {.foo,.bar}  ",
+        &[LangStringToken::ClassAttribute("foo"), LangStringToken::ClassAttribute("bar")],
+    );
+    case("foo bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
+    case("foo\tbar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
+    case("foo\t, bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
+    case(" foo , bar ", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
+    case(",,foo,,bar,,", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
+    case("foo=bar", &[]);
+    case("a-b-c", &[LangStringToken::LangToken("a-b-c")]);
+    case("a_b_c", &[LangStringToken::LangToken("a_b_c")]);
 }
 
 #[test]
@@ -154,6 +290,7 @@ fn test_header() {
             edition: DEFAULT_EDITION,
             playground: &None,
             heading_offset: HeadingOffset::H2,
+            custom_code_classes_in_docs: true,
         }
         .into_string();
         assert_eq!(output, expect, "original: {}", input);
@@ -193,6 +330,7 @@ fn test_header_ids_multiple_blocks() {
             edition: DEFAULT_EDITION,
             playground: &None,
             heading_offset: HeadingOffset::H2,
+            custom_code_classes_in_docs: true,
         }
         .into_string();
         assert_eq!(output, expect, "original: {}", input);
@@ -297,7 +435,7 @@ fn test_find_testable_code_line() {
             }
         }
         let mut lines = Vec::<usize>::new();
-        find_testable_code(input, &mut lines, ErrorCodes::No, false, None);
+        find_testable_code(input, &mut lines, ErrorCodes::No, false, None, true);
         assert_eq!(lines, expect);
     }
 
@@ -322,6 +460,7 @@ fn test_ascii_with_prepending_hashtag() {
             edition: DEFAULT_EDITION,
             playground: &None,
             heading_offset: HeadingOffset::H2,
+            custom_code_classes_in_docs: true,
         }
         .into_string();
         assert_eq!(output, expect, "original: {}", input);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 736b6d7ebfa..97714afaa45 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -107,8 +107,8 @@ pub(crate) struct SharedContext<'tcx> {
     pub(super) module_sorting: ModuleSorting,
     /// Additional CSS files to be added to the generated docs.
     pub(crate) style_files: Vec<StylePath>,
-    /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
-    /// "light-v2.css").
+    /// Suffix to add on resource files (if suffix is "-v2" then "search-index.js" becomes
+    /// "search-index-v2.js").
     pub(crate) resource_suffix: String,
     /// Optional path string to be used to load static files on output pages. If not set, uses
     /// combinations of `../` to reach the documentation root.
@@ -714,18 +714,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                             You need to enable JavaScript be able to update your settings.\
                         </section>\
                      </noscript>\
-                     <script defer src=\"{static_root_path}{settings_js}\"></script>\
-                     <link rel=\"preload\" href=\"{static_root_path}{theme_light_css}\" \
-                         as=\"style\">\
-                     <link rel=\"preload\" href=\"{static_root_path}{theme_dark_css}\" \
-                         as=\"style\">\
-                     <link rel=\"preload\" href=\"{static_root_path}{theme_ayu_css}\" \
-                         as=\"style\">",
+                     <script defer src=\"{static_root_path}{settings_js}\"></script>",
                     static_root_path = page.get_static_root_path(),
                     settings_js = static_files::STATIC_FILES.settings_js,
-                    theme_light_css = static_files::STATIC_FILES.theme_light_css,
-                    theme_dark_css = static_files::STATIC_FILES.theme_dark_css,
-                    theme_ayu_css = static_files::STATIC_FILES.theme_ayu_css,
                 );
                 // Pre-load all theme CSS files, so that switching feels seamless.
                 //
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 5adbecd6d04..f70f59d3be3 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -403,7 +403,8 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
             error_codes: shared.codes,
             edition: shared.edition(),
             playground: &shared.playground,
-            heading_offset: HeadingOffset::H1
+            heading_offset: HeadingOffset::H1,
+            custom_code_classes_in_docs: false,
         }
         .into_string()
     )
@@ -437,6 +438,7 @@ fn render_markdown<'a, 'cx: 'a>(
     heading_offset: HeadingOffset,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
     display_fn(move |f| {
+        let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs;
         write!(
             f,
             "<div class=\"docblock\">{}</div>",
@@ -448,6 +450,7 @@ fn render_markdown<'a, 'cx: 'a>(
                 edition: cx.shared.edition(),
                 playground: &cx.shared.playground,
                 heading_offset,
+                custom_code_classes_in_docs,
             }
             .into_string()
         )
@@ -1778,6 +1781,7 @@ fn render_impl(
                      </div>",
                 );
             }
+            let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs;
             write!(
                 w,
                 "<div class=\"docblock\">{}</div>",
@@ -1788,7 +1792,8 @@ fn render_impl(
                     error_codes: cx.shared.codes,
                     edition: cx.shared.edition(),
                     playground: &cx.shared.playground,
-                    heading_offset: HeadingOffset::H4
+                    heading_offset: HeadingOffset::H4,
+                    custom_code_classes_in_docs,
                 }
                 .into_string()
             );
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 93aa11a5852..fe0cf6dc8cc 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -28,3 +28,216 @@ nav.sub {
 	    https://github.com/rust-lang/rust/issues/102576 */
 	display: none;
 }
+
+/* Begin: styles for themes
+	Keep the default light and dark themes synchronized with the ones
+	in rustdoc.css */
+
+/* Begin theme: light */
+:root {
+	--main-background-color: white;
+	--main-color: black;
+	--settings-input-color: #2196f3;
+	--settings-input-border-color: #717171;
+	--settings-button-color: #000;
+	--settings-button-border-focus: #717171;
+	--sidebar-background-color: #f5f5f5;
+	--sidebar-background-color-hover: #e0e0e0;
+	--code-block-background-color: #f5f5f5;
+	--scrollbar-track-background-color: #dcdcdc;
+	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+	--headings-border-bottom-color: #ddd;
+	--border-color: #e0e0e0;
+	--button-background-color: #fff;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: none;
+	--search-input-focused-border-color: #66afe9;
+	--copy-path-button-color: #999;
+	--copy-path-img-filter: invert(50%);
+	--copy-path-img-hover-filter: invert(35%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #ad378a;
+	--trait-link-color: #6e4fc9;
+	--assoc-item-link-color: #3873ad;
+	--function-link-color: #ad7c37;
+	--macro-link-color: #068000;
+	--keyword-link-color: #3873ad;
+	--mod-link-color: #3873ad;
+	--link-color: #3873ad;
+	--sidebar-link-color: #356da4;
+	--sidebar-current-link-background-color: #fff;
+	--search-result-link-focus-background-color: #ccc;
+	--search-result-border-color: #aaa3;
+	--search-color: #000;
+	--search-error-code-background-color: #d0cccc;
+	--search-results-alias-color: #000;
+	--search-results-grey-color: #999;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: #e6e6e6;
+	--search-tab-button-not-selected-background: #e6e6e6;
+	--search-tab-button-selected-border-top-color: #0089ff;
+	--search-tab-button-selected-background: #fff;
+	--stab-background-color: #fff5d6;
+	--stab-code-color: #000;
+	--code-highlight-kw-color: #8959a8;
+	--code-highlight-kw-2-color: #4271ae;
+	--code-highlight-lifetime-color: #b76514;
+	--code-highlight-prelude-color: #4271ae;
+	--code-highlight-prelude-val-color: #c82829;
+	--code-highlight-number-color: #718c00;
+	--code-highlight-string-color: #718c00;
+	--code-highlight-literal-color: #c82829;
+	--code-highlight-attribute-color: #c82829;
+	--code-highlight-self-color: #c82829;
+	--code-highlight-macro-color: #3e999f;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #8e908c;
+	--code-highlight-doc-comment-color: #4d4d4c;
+	--src-line-numbers-span-color: #c67e2d;
+	--src-line-number-highlighted-background-color: #fdffd3;
+	--test-arrow-color: #f5f5f5;
+	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+	--test-arrow-hover-color: #f5f5f5;
+	--test-arrow-hover-background-color: rgb(78, 139, 202);
+	--target-background-color: #fdffd3;
+	--target-border-color: #ad7c37;
+	--kbd-color: #000;
+	--kbd-background: #fafbfc;
+	--kbd-box-shadow-color: #c6cbd1;
+	--rust-logo-filter: initial;
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+		brightness(114%) contrast(76%);
+	--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+		brightness(96%) contrast(93%);
+	--crate-search-hover-border: #717171;
+	--src-sidebar-background-selected: #fff;
+	--src-sidebar-background-hover: #e0e0e0;
+	--table-alt-row-background-color: #f5f5f5;
+	--codeblock-link-background: #eee;
+	--scrape-example-toggle-line-background: #ccc;
+	--scrape-example-toggle-line-hover-background: #999;
+	--scrape-example-code-line-highlight: #fcffd6;
+	--scrape-example-code-line-highlight-focus: #f6fdb0;
+	--scrape-example-help-border-color: #555;
+	--scrape-example-help-color: #333;
+	--scrape-example-help-hover-border-color: #000;
+	--scrape-example-help-hover-color: #000;
+	--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+}
+/* End theme: light */
+
+@media (prefers-color-scheme: dark) {
+	/* Begin theme: dark */
+	:root {
+		--main-background-color: #353535;
+		--main-color: #ddd;
+		--settings-input-color: #2196f3;
+		--settings-input-border-color: #999;
+		--settings-button-color: #000;
+		--settings-button-border-focus: #ffb900;
+		--sidebar-background-color: #505050;
+		--sidebar-background-color-hover: #676767;
+		--code-block-background-color: #2A2A2A;
+		--scrollbar-track-background-color: #717171;
+		--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+		--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+		--headings-border-bottom-color: #d2d2d2;
+		--border-color: #e0e0e0;
+		--button-background-color: #f0f0f0;
+		--right-side-color: grey;
+		--code-attribute-color: #999;
+		--toggles-color: #999;
+		--toggle-filter: invert(100%);
+		--search-input-focused-border-color: #008dfd;
+		--copy-path-button-color: #999;
+		--copy-path-img-filter: invert(50%);
+		--copy-path-img-hover-filter: invert(65%);
+		--codeblock-error-hover-color: rgb(255, 0, 0);
+		--codeblock-error-color: rgba(255, 0, 0, .5);
+		--codeblock-ignore-hover-color: rgb(255, 142, 0);
+		--codeblock-ignore-color: rgba(255, 142, 0, .6);
+		--warning-border-color: #ff8e00;
+		--type-link-color: #2dbfb8;
+		--trait-link-color: #b78cf2;
+		--assoc-item-link-color: #d2991d;
+		--function-link-color: #2bab63;
+		--macro-link-color: #09bd00;
+		--keyword-link-color: #d2991d;
+		--mod-link-color:  #d2991d;
+		--link-color: #d2991d;
+		--sidebar-link-color: #fdbf35;
+		--sidebar-current-link-background-color: #444;
+		--search-result-link-focus-background-color: #616161;
+		--search-result-border-color: #aaa3;
+		--search-color: #111;
+		--search-error-code-background-color: #484848;
+		--search-results-alias-color: #fff;
+		--search-results-grey-color: #ccc;
+		--search-tab-title-count-color: #888;
+		--search-tab-button-not-selected-border-top-color: #252525;
+		--search-tab-button-not-selected-background: #252525;
+		--search-tab-button-selected-border-top-color: #0089ff;
+		--search-tab-button-selected-background: #353535;
+		--stab-background-color: #314559;
+		--stab-code-color: #e6e1cf;
+		--code-highlight-kw-color: #ab8ac1;
+		--code-highlight-kw-2-color: #769acb;
+		--code-highlight-lifetime-color: #d97f26;
+		--code-highlight-prelude-color: #769acb;
+		--code-highlight-prelude-val-color: #ee6868;
+		--code-highlight-number-color: #83a300;
+		--code-highlight-string-color: #83a300;
+		--code-highlight-literal-color: #ee6868;
+		--code-highlight-attribute-color: #ee6868;
+		--code-highlight-self-color: #ee6868;
+		--code-highlight-macro-color: #3e999f;
+		--code-highlight-question-mark-color: #ff9011;
+		--code-highlight-comment-color: #8d8d8b;
+		--code-highlight-doc-comment-color: #8ca375;
+		--src-line-numbers-span-color: #3b91e2;
+		--src-line-number-highlighted-background-color: #0a042f;
+		--test-arrow-color: #dedede;
+		--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+		--test-arrow-hover-color: #dedede;
+		--test-arrow-hover-background-color: #4e8bca;
+		--target-background-color: #494a3d;
+		--target-border-color: #bb7410;
+		--kbd-color: #000;
+		--kbd-background: #fafbfc;
+		--kbd-box-shadow-color: #c6cbd1;
+		--rust-logo-filter: drop-shadow(1px 0 0px #fff)
+			drop-shadow(0 1px 0 #fff)
+			drop-shadow(-1px 0 0 #fff)
+			drop-shadow(0 -1px 0 #fff);
+		/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+		--crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+			brightness(90%) contrast(90%);
+		--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+			brightness(100%) contrast(91%);
+		--crate-search-hover-border: #2196f3;
+		--src-sidebar-background-selected: #333;
+		--src-sidebar-background-hover: #444;
+		--table-alt-row-background-color: #2a2a2a;
+		--codeblock-link-background: #333;
+		--scrape-example-toggle-line-background: #999;
+		--scrape-example-toggle-line-hover-background: #c5c5c5;
+		--scrape-example-code-line-highlight: #5b3b01;
+		--scrape-example-code-line-highlight-focus: #7c4b0f;
+		--scrape-example-help-border-color: #aaa;
+		--scrape-example-help-color: #eee;
+		--scrape-example-help-hover-border-color: #fff;
+		--scrape-example-help-hover-color: #fff;
+		--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+		--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+	}
+/* End theme: dark */
+}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 84123f4e9d3..3b236641337 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -2098,3 +2098,413 @@ in src-script.js
 }
 
 /* End: styles for --scrape-examples feature */
+
+/* Begin: styles for themes
+
+	Keep the default light and dark themes synchronized with the ones
+	in noscript.css
+
+	The special "Begin theme" and "End theme" below are used by a lot of
+	tooling to ensure different themes all define all the variables. Do not
+	alter their formatting. */
+
+/* Begin theme: light */
+:root[data-theme="light"] {
+	--main-background-color: white;
+	--main-color: black;
+	--settings-input-color: #2196f3;
+	--settings-input-border-color: #717171;
+	--settings-button-color: #000;
+	--settings-button-border-focus: #717171;
+	--sidebar-background-color: #f5f5f5;
+	--sidebar-background-color-hover: #e0e0e0;
+	--code-block-background-color: #f5f5f5;
+	--scrollbar-track-background-color: #dcdcdc;
+	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+	--headings-border-bottom-color: #ddd;
+	--border-color: #e0e0e0;
+	--button-background-color: #fff;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: none;
+	--search-input-focused-border-color: #66afe9;
+	--copy-path-button-color: #999;
+	--copy-path-img-filter: invert(50%);
+	--copy-path-img-hover-filter: invert(35%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #ad378a;
+	--trait-link-color: #6e4fc9;
+	--assoc-item-link-color: #3873ad;
+	--function-link-color: #ad7c37;
+	--macro-link-color: #068000;
+	--keyword-link-color: #3873ad;
+	--mod-link-color: #3873ad;
+	--link-color: #3873ad;
+	--sidebar-link-color: #356da4;
+	--sidebar-current-link-background-color: #fff;
+	--search-result-link-focus-background-color: #ccc;
+	--search-result-border-color: #aaa3;
+	--search-color: #000;
+	--search-error-code-background-color: #d0cccc;
+	--search-results-alias-color: #000;
+	--search-results-grey-color: #999;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: #e6e6e6;
+	--search-tab-button-not-selected-background: #e6e6e6;
+	--search-tab-button-selected-border-top-color: #0089ff;
+	--search-tab-button-selected-background: #fff;
+	--stab-background-color: #fff5d6;
+	--stab-code-color: #000;
+	--code-highlight-kw-color: #8959a8;
+	--code-highlight-kw-2-color: #4271ae;
+	--code-highlight-lifetime-color: #b76514;
+	--code-highlight-prelude-color: #4271ae;
+	--code-highlight-prelude-val-color: #c82829;
+	--code-highlight-number-color: #718c00;
+	--code-highlight-string-color: #718c00;
+	--code-highlight-literal-color: #c82829;
+	--code-highlight-attribute-color: #c82829;
+	--code-highlight-self-color: #c82829;
+	--code-highlight-macro-color: #3e999f;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #8e908c;
+	--code-highlight-doc-comment-color: #4d4d4c;
+	--src-line-numbers-span-color: #c67e2d;
+	--src-line-number-highlighted-background-color: #fdffd3;
+	--test-arrow-color: #f5f5f5;
+	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+	--test-arrow-hover-color: #f5f5f5;
+	--test-arrow-hover-background-color: rgb(78, 139, 202);
+	--target-background-color: #fdffd3;
+	--target-border-color: #ad7c37;
+	--kbd-color: #000;
+	--kbd-background: #fafbfc;
+	--kbd-box-shadow-color: #c6cbd1;
+	--rust-logo-filter: initial;
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+		brightness(114%) contrast(76%);
+	--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+		brightness(96%) contrast(93%);
+	--crate-search-hover-border: #717171;
+	--src-sidebar-background-selected: #fff;
+	--src-sidebar-background-hover: #e0e0e0;
+	--table-alt-row-background-color: #f5f5f5;
+	--codeblock-link-background: #eee;
+	--scrape-example-toggle-line-background: #ccc;
+	--scrape-example-toggle-line-hover-background: #999;
+	--scrape-example-code-line-highlight: #fcffd6;
+	--scrape-example-code-line-highlight-focus: #f6fdb0;
+	--scrape-example-help-border-color: #555;
+	--scrape-example-help-color: #333;
+	--scrape-example-help-hover-border-color: #000;
+	--scrape-example-help-hover-color: #000;
+	--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+}
+/* End theme: light */
+
+/* Begin theme: dark */
+:root[data-theme="dark"] {
+	--main-background-color: #353535;
+	--main-color: #ddd;
+	--settings-input-color: #2196f3;
+	--settings-input-border-color: #999;
+	--settings-button-color: #000;
+	--settings-button-border-focus: #ffb900;
+	--sidebar-background-color: #505050;
+	--sidebar-background-color-hover: #676767;
+	--code-block-background-color: #2A2A2A;
+	--scrollbar-track-background-color: #717171;
+	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+	--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+	--headings-border-bottom-color: #d2d2d2;
+	--border-color: #e0e0e0;
+	--button-background-color: #f0f0f0;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: invert(100%);
+	--search-input-focused-border-color: #008dfd;
+	--copy-path-button-color: #999;
+	--copy-path-img-filter: invert(50%);
+	--copy-path-img-hover-filter: invert(65%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #2dbfb8;
+	--trait-link-color: #b78cf2;
+	--assoc-item-link-color: #d2991d;
+	--function-link-color: #2bab63;
+	--macro-link-color: #09bd00;
+	--keyword-link-color: #d2991d;
+	--mod-link-color:  #d2991d;
+	--link-color: #d2991d;
+	--sidebar-link-color: #fdbf35;
+	--sidebar-current-link-background-color: #444;
+	--search-result-link-focus-background-color: #616161;
+	--search-result-border-color: #aaa3;
+	--search-color: #111;
+	--search-error-code-background-color: #484848;
+	--search-results-alias-color: #fff;
+	--search-results-grey-color: #ccc;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: #252525;
+	--search-tab-button-not-selected-background: #252525;
+	--search-tab-button-selected-border-top-color: #0089ff;
+	--search-tab-button-selected-background: #353535;
+	--stab-background-color: #314559;
+	--stab-code-color: #e6e1cf;
+	--code-highlight-kw-color: #ab8ac1;
+	--code-highlight-kw-2-color: #769acb;
+	--code-highlight-lifetime-color: #d97f26;
+	--code-highlight-prelude-color: #769acb;
+	--code-highlight-prelude-val-color: #ee6868;
+	--code-highlight-number-color: #83a300;
+	--code-highlight-string-color: #83a300;
+	--code-highlight-literal-color: #ee6868;
+	--code-highlight-attribute-color: #ee6868;
+	--code-highlight-self-color: #ee6868;
+	--code-highlight-macro-color: #3e999f;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #8d8d8b;
+	--code-highlight-doc-comment-color: #8ca375;
+	--src-line-numbers-span-color: #3b91e2;
+	--src-line-number-highlighted-background-color: #0a042f;
+	--test-arrow-color: #dedede;
+	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+	--test-arrow-hover-color: #dedede;
+	--test-arrow-hover-background-color: #4e8bca;
+	--target-background-color: #494a3d;
+	--target-border-color: #bb7410;
+	--kbd-color: #000;
+	--kbd-background: #fafbfc;
+	--kbd-box-shadow-color: #c6cbd1;
+	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
+		drop-shadow(0 1px 0 #fff)
+		drop-shadow(-1px 0 0 #fff)
+		drop-shadow(0 -1px 0 #fff);
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+		brightness(90%) contrast(90%);
+	--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+		brightness(100%) contrast(91%);
+	--crate-search-hover-border: #2196f3;
+	--src-sidebar-background-selected: #333;
+	--src-sidebar-background-hover: #444;
+	--table-alt-row-background-color: #2a2a2a;
+	--codeblock-link-background: #333;
+	--scrape-example-toggle-line-background: #999;
+	--scrape-example-toggle-line-hover-background: #c5c5c5;
+	--scrape-example-code-line-highlight: #5b3b01;
+	--scrape-example-code-line-highlight-focus: #7c4b0f;
+	--scrape-example-help-border-color: #aaa;
+	--scrape-example-help-color: #eee;
+	--scrape-example-help-hover-border-color: #fff;
+	--scrape-example-help-hover-color: #fff;
+	--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+	--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+}
+/* End theme: dark */
+
+/* Begin theme: ayu */
+/*
+Based off of the Ayu theme
+Original by Dempfi (https://github.com/dempfi/ayu)
+*/
+:root[data-theme="ayu"] {
+	--main-background-color: #0f1419;
+	--main-color: #c5c5c5;
+	--settings-input-color: #ffb454;
+	--settings-input-border-color: #999;
+	--settings-button-color: #fff;
+	--settings-button-border-focus: #e0e0e0;
+	--sidebar-background-color: #14191f;
+	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+	--code-block-background-color: #191f26;
+	--scrollbar-track-background-color: transparent;
+	--scrollbar-thumb-background-color: #5c6773;
+	--scrollbar-color: #5c6773 #24292f;
+	--headings-border-bottom-color: #5c6773;
+	--border-color: #5c6773;
+	--button-background-color: #141920;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: invert(100%);
+	--search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
+	--copy-path-button-color: #fff;
+	--copy-path-img-filter: invert(70%);
+	--copy-path-img-hover-filter: invert(100%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #ffa0a5;
+	--trait-link-color: #39afd7;
+	--assoc-item-link-color: #39afd7;
+	--function-link-color: #fdd687;
+	--macro-link-color: #a37acc;
+	--keyword-link-color: #39afd7;
+	--mod-link-color: #39afd7;
+	--link-color: #39afd7;
+	--sidebar-link-color: #53b1db;
+	--sidebar-current-link-background-color: transparent;
+	--search-result-link-focus-background-color: #3c3c3c;
+	--search-result-border-color: #aaa3;
+	--search-color: #fff;
+	--search-error-code-background-color: #4f4c4c;
+	--search-results-alias-color: #c5c5c5;
+	--search-results-grey-color: #999;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: none;
+	--search-tab-button-not-selected-background: transparent !important;
+	--search-tab-button-selected-border-top-color: none;
+	--search-tab-button-selected-background: #141920 !important;
+	--stab-background-color: #314559;
+	--stab-code-color: #e6e1cf;
+	--code-highlight-kw-color: #ff7733;
+	--code-highlight-kw-2-color: #ff7733;
+	--code-highlight-lifetime-color: #ff7733;
+	--code-highlight-prelude-color: #69f2df;
+	--code-highlight-prelude-val-color: #ff7733;
+	--code-highlight-number-color: #b8cc52;
+	--code-highlight-string-color: #b8cc52;
+	--code-highlight-literal-color: #ff7733;
+	--code-highlight-attribute-color: #e6e1cf;
+	--code-highlight-self-color: #36a3d9;
+	--code-highlight-macro-color: #a37acc;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #788797;
+	--code-highlight-doc-comment-color: #a1ac88;
+	--src-line-numbers-span-color: #5c6773;
+	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
+	--test-arrow-color: #788797;
+	--test-arrow-background-color: rgba(57, 175, 215, 0.09);
+	--test-arrow-hover-color: #c5c5c5;
+	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
+	--target-background-color: rgba(255, 236, 164, 0.06);
+	--target-border-color: rgba(255, 180, 76, 0.85);
+	--kbd-color: #c5c5c5;
+	--kbd-background: #314559;
+	--kbd-box-shadow-color: #5c6773;
+	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
+		drop-shadow(0 1px 0 #fff)
+		drop-shadow(-1px 0 0 #fff)
+		drop-shadow(0 -1px 0 #fff);
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
+		brightness(94%) contrast(94%);
+	--crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
+		brightness(113%) contrast(76%);
+	--crate-search-hover-border: #e0e0e0;
+	--src-sidebar-background-selected: #14191f;
+	--src-sidebar-background-hover: #14191f;
+	--table-alt-row-background-color: #191f26;
+	--codeblock-link-background: #333;
+	--scrape-example-toggle-line-background: #999;
+	--scrape-example-toggle-line-hover-background: #c5c5c5;
+	--scrape-example-code-line-highlight: #5b3b01;
+	--scrape-example-code-line-highlight-focus: #7c4b0f;
+	--scrape-example-help-border-color: #aaa;
+	--scrape-example-help-color: #eee;
+	--scrape-example-help-hover-border-color: #fff;
+	--scrape-example-help-hover-color: #fff;
+	--scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
+	--scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
+}
+
+:root[data-theme="ayu"] h1,
+:root[data-theme="ayu"] h2,
+:root[data-theme="ayu"] h3,
+:root[data-theme="ayu"] h4,
+:where(:root[data-theme="ayu"]) h1 a,
+:root[data-theme="ayu"] .sidebar h2 a,
+:root[data-theme="ayu"] .sidebar h3 a,
+:root[data-theme="ayu"] #source-sidebar > .title {
+	color: #fff;
+}
+
+:root[data-theme="ayu"] .docblock code {
+	color: #ffb454;
+}
+
+:root[data-theme="ayu"] .docblock a > code {
+	color: #39AFD7 !important;
+}
+
+:root[data-theme="ayu"] .code-header,
+:root[data-theme="ayu"] .docblock pre > code,
+:root[data-theme="ayu"] pre,
+:root[data-theme="ayu"] pre > code,
+:root[data-theme="ayu"] .item-info code,
+:root[data-theme="ayu"] .rustdoc.source .example-wrap {
+	color: #e6e1cf;
+}
+
+:root[data-theme="ayu"] .sidebar .current,
+:root[data-theme="ayu"] .sidebar a:hover,
+:root[data-theme="ayu"] #src-sidebar div.files > a:hover,
+:root[data-theme="ayu"] details.dir-entry summary:hover,
+:root[data-theme="ayu"] #src-sidebar div.files > a:focus,
+:root[data-theme="ayu"] details.dir-entry summary:focus,
+:root[data-theme="ayu"] #src-sidebar div.files > a.selected {
+	color: #ffb44c;
+}
+
+:root[data-theme="ayu"] .sidebar-elems .location {
+	color: #ff7733;
+}
+
+:root[data-theme="ayu"] .src-line-numbers .line-highlighted {
+	color: #708090;
+	padding-right: 7px;
+	border-right: 1px solid #ffb44c;
+}
+
+:root[data-theme="ayu"] .search-results a:hover,
+:root[data-theme="ayu"] .search-results a:focus {
+	color: #fff !important;
+	background-color: #3c3c3c;
+}
+
+:root[data-theme="ayu"] .search-results a {
+	color: #0096cf;
+}
+
+:root[data-theme="ayu"] .search-results a div.desc {
+	color: #c5c5c5;
+}
+
+:root[data-theme="ayu"] .result-name .primitive > i,
+:root[data-theme="ayu"] .result-name .keyword > i {
+	color: #788797;
+}
+
+:root[data-theme="ayu"] #search-tabs > button.selected {
+	border-bottom: 1px solid #ffb44c !important;
+	border-top: none;
+}
+:root[data-theme="ayu"] #search-tabs > button:not(.selected) {
+	border: none;
+	background-color: transparent !important;
+}
+:root[data-theme="ayu"] #search-tabs > button:hover {
+	border-bottom: 1px solid rgba(242, 151, 24, 0.3);
+}
+
+:root[data-theme="ayu"] #settings-menu > a img {
+	filter: invert(100);
+}
+/* End theme: ayu */
+
+/* End: styles for themes */
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
deleted file mode 100644
index 873a1668f8b..00000000000
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
-Based off of the Ayu theme
-Original by Dempfi (https://github.com/dempfi/ayu)
-*/
-
-:root {
-	--main-background-color: #0f1419;
-	--main-color: #c5c5c5;
-	--settings-input-color: #ffb454;
-	--settings-input-border-color: #999;
-	--settings-button-color: #fff;
-	--settings-button-border-focus: #e0e0e0;
-	--sidebar-background-color: #14191f;
-	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
-	--code-block-background-color: #191f26;
-	--scrollbar-track-background-color: transparent;
-	--scrollbar-thumb-background-color: #5c6773;
-	--scrollbar-color: #5c6773 #24292f;
-	--headings-border-bottom-color: #5c6773;
-	--border-color: #5c6773;
-	--button-background-color: #141920;
-	--right-side-color: grey;
-	--code-attribute-color: #999;
-	--toggles-color: #999;
-	--toggle-filter: invert(100%);
-	--search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
-	--copy-path-button-color: #fff;
-	--copy-path-img-filter: invert(70%);
-	--copy-path-img-hover-filter: invert(100%);
-	--codeblock-error-hover-color: rgb(255, 0, 0);
-	--codeblock-error-color: rgba(255, 0, 0, .5);
-	--codeblock-ignore-hover-color: rgb(255, 142, 0);
-	--codeblock-ignore-color: rgba(255, 142, 0, .6);
-	--warning-border-color: #ff8e00;
-	--type-link-color: #ffa0a5;
-	--trait-link-color: #39afd7;
-	--assoc-item-link-color: #39afd7;
-	--function-link-color: #fdd687;
-	--macro-link-color: #a37acc;
-	--keyword-link-color: #39afd7;
-	--mod-link-color: #39afd7;
-	--link-color: #39afd7;
-	--sidebar-link-color: #53b1db;
-	--sidebar-current-link-background-color: transparent;
-	--search-result-link-focus-background-color: #3c3c3c;
-	--search-result-border-color: #aaa3;
-	--search-color: #fff;
-	--search-error-code-background-color: #4f4c4c;
-	--search-results-alias-color: #c5c5c5;
-	--search-results-grey-color: #999;
-	--search-tab-title-count-color: #888;
-	--search-tab-button-not-selected-border-top-color: none;
-	--search-tab-button-not-selected-background: transparent !important;
-	--search-tab-button-selected-border-top-color: none;
-	--search-tab-button-selected-background: #141920 !important;
-	--stab-background-color: #314559;
-	--stab-code-color: #e6e1cf;
-	--code-highlight-kw-color: #ff7733;
-	--code-highlight-kw-2-color: #ff7733;
-	--code-highlight-lifetime-color: #ff7733;
-	--code-highlight-prelude-color: #69f2df;
-	--code-highlight-prelude-val-color: #ff7733;
-	--code-highlight-number-color: #b8cc52;
-	--code-highlight-string-color: #b8cc52;
-	--code-highlight-literal-color: #ff7733;
-	--code-highlight-attribute-color: #e6e1cf;
-	--code-highlight-self-color: #36a3d9;
-	--code-highlight-macro-color: #a37acc;
-	--code-highlight-question-mark-color: #ff9011;
-	--code-highlight-comment-color: #788797;
-	--code-highlight-doc-comment-color: #a1ac88;
-	--src-line-numbers-span-color: #5c6773;
-	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
-	--test-arrow-color: #788797;
-	--test-arrow-background-color: rgba(57, 175, 215, 0.09);
-	--test-arrow-hover-color: #c5c5c5;
-	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
-	--target-background-color: rgba(255, 236, 164, 0.06);
-	--target-border-color: rgba(255, 180, 76, 0.85);
-	--kbd-color: #c5c5c5;
-	--kbd-background: #314559;
-	--kbd-box-shadow-color: #5c6773;
-	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
-		drop-shadow(0 1px 0 #fff)
-		drop-shadow(-1px 0 0 #fff)
-		drop-shadow(0 -1px 0 #fff);
-	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-	--crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
-		brightness(94%) contrast(94%);
-	--crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
-		brightness(113%) contrast(76%);
-	--crate-search-hover-border: #e0e0e0;
-	--src-sidebar-background-selected: #14191f;
-	--src-sidebar-background-hover: #14191f;
-	--table-alt-row-background-color: #191f26;
-	--codeblock-link-background: #333;
-	--scrape-example-toggle-line-background: #999;
-	--scrape-example-toggle-line-hover-background: #c5c5c5;
-	--scrape-example-code-line-highlight: #5b3b01;
-	--scrape-example-code-line-highlight-focus: #7c4b0f;
-	--scrape-example-help-border-color: #aaa;
-	--scrape-example-help-color: #eee;
-	--scrape-example-help-hover-border-color: #fff;
-	--scrape-example-help-hover-color: #fff;
-	--scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
-	--scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
-}
-
-h1, h2, h3, h4,
-h1 a, .sidebar h2 a, .sidebar h3 a,
-#src-sidebar > .title {
-	color: #fff;
-}
-h4 {
-	border: none;
-}
-
-.docblock code {
-	color: #ffb454;
-}
-.docblock a > code {
-	color: #39AFD7 !important;
-}
-.code-header,
-.docblock pre > code,
-pre, pre > code,
-.item-info code,
-.rustdoc.src .example-wrap {
-	color: #e6e1cf;
-}
-
-.sidebar .current,
-.sidebar a:hover,
-#src-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#src-sidebar div.files > a:focus, details.dir-entry summary:focus,
-#src-sidebar div.files > a.selected {
-	color: #ffb44c;
-}
-
-.sidebar-elems .location {
-	color: #ff7733;
-}
-
-.src-line-numbers .line-highlighted {
-	color: #708090;
-	padding-right: 7px;
-	border-right: 1px solid #ffb44c;
-}
-
-.search-results a:hover,
-.search-results a:focus {
-	color: #fff !important;
-	background-color: #3c3c3c;
-}
-
-.search-results a {
-	color: #0096cf;
-}
-.search-results a div.desc {
-	color: #c5c5c5;
-}
-
-.result-name .primitive > i, .result-name .keyword > i {
-	color: #788797;
-}
-
-#search-tabs > button.selected {
-	border-bottom: 1px solid #ffb44c !important;
-	border-top: none;
-}
-#search-tabs > button:not(.selected) {
-	border: none;
-	background-color: transparent !important;
-}
-#search-tabs > button:hover {
-	border-bottom: 1px solid rgba(242, 151, 24, 0.3);
-}
-
-#settings-menu > a img {
-	filter: invert(100);
-}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
deleted file mode 100644
index 2b6e28d35a5..00000000000
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ /dev/null
@@ -1,102 +0,0 @@
-:root {
-	--main-background-color: #353535;
-	--main-color: #ddd;
-	--settings-input-color: #2196f3;
-	--settings-input-border-color: #999;
-	--settings-button-color: #000;
-	--settings-button-border-focus: #ffb900;
-	--sidebar-background-color: #505050;
-	--sidebar-background-color-hover: #676767;
-	--code-block-background-color: #2A2A2A;
-	--scrollbar-track-background-color: #717171;
-	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
-	--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
-	--headings-border-bottom-color: #d2d2d2;
-	--border-color: #e0e0e0;
-	--button-background-color: #f0f0f0;
-	--right-side-color: grey;
-	--code-attribute-color: #999;
-	--toggles-color: #999;
-	--toggle-filter: invert(100%);
-	--search-input-focused-border-color: #008dfd;
-	--copy-path-button-color: #999;
-	--copy-path-img-filter: invert(50%);
-	--copy-path-img-hover-filter: invert(65%);
-	--codeblock-error-hover-color: rgb(255, 0, 0);
-	--codeblock-error-color: rgba(255, 0, 0, .5);
-	--codeblock-ignore-hover-color: rgb(255, 142, 0);
-	--codeblock-ignore-color: rgba(255, 142, 0, .6);
-	--warning-border-color: #ff8e00;
-	--type-link-color: #2dbfb8;
-	--trait-link-color: #b78cf2;
-	--assoc-item-link-color: #d2991d;
-	--function-link-color: #2bab63;
-	--macro-link-color: #09bd00;
-	--keyword-link-color: #d2991d;
-	--mod-link-color:  #d2991d;
-	--link-color: #d2991d;
-	--sidebar-link-color: #fdbf35;
-	--sidebar-current-link-background-color: #444;
-	--search-result-link-focus-background-color: #616161;
-	--search-result-border-color: #aaa3;
-	--search-color: #111;
-	--search-error-code-background-color: #484848;
-	--search-results-alias-color: #fff;
-	--search-results-grey-color: #ccc;
-	--search-tab-title-count-color: #888;
-	--search-tab-button-not-selected-border-top-color: #252525;
-	--search-tab-button-not-selected-background: #252525;
-	--search-tab-button-selected-border-top-color: #0089ff;
-	--search-tab-button-selected-background: #353535;
-	--stab-background-color: #314559;
-	--stab-code-color: #e6e1cf;
-	--code-highlight-kw-color: #ab8ac1;
-	--code-highlight-kw-2-color: #769acb;
-	--code-highlight-lifetime-color: #d97f26;
-	--code-highlight-prelude-color: #769acb;
-	--code-highlight-prelude-val-color: #ee6868;
-	--code-highlight-number-color: #83a300;
-	--code-highlight-string-color: #83a300;
-	--code-highlight-literal-color: #ee6868;
-	--code-highlight-attribute-color: #ee6868;
-	--code-highlight-self-color: #ee6868;
-	--code-highlight-macro-color: #3e999f;
-	--code-highlight-question-mark-color: #ff9011;
-	--code-highlight-comment-color: #8d8d8b;
-	--code-highlight-doc-comment-color: #8ca375;
-	--src-line-numbers-span-color: #3b91e2;
-	--src-line-number-highlighted-background-color: #0a042f;
-	--test-arrow-color: #dedede;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #dedede;
-	--test-arrow-hover-background-color: #4e8bca;
-	--target-background-color: #494a3d;
-	--target-border-color: #bb7410;
-	--kbd-color: #000;
-	--kbd-background: #fafbfc;
-	--kbd-box-shadow-color: #c6cbd1;
-	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
-		drop-shadow(0 1px 0 #fff)
-		drop-shadow(-1px 0 0 #fff)
-		drop-shadow(0 -1px 0 #fff);
-	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-	--crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
-		brightness(90%) contrast(90%);
-	--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
-		brightness(100%) contrast(91%);
-	--crate-search-hover-border: #2196f3;
-	--src-sidebar-background-selected: #333;
-	--src-sidebar-background-hover: #444;
-	--table-alt-row-background-color: #2a2a2a;
-	--codeblock-link-background: #333;
-	--scrape-example-toggle-line-background: #999;
-	--scrape-example-toggle-line-hover-background: #c5c5c5;
-	--scrape-example-code-line-highlight: #5b3b01;
-	--scrape-example-code-line-highlight-focus: #7c4b0f;
-	--scrape-example-help-border-color: #aaa;
-	--scrape-example-help-color: #eee;
-	--scrape-example-help-hover-border-color: #fff;
-	--scrape-example-help-hover-color: #fff;
-	--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
-	--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
-}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
deleted file mode 100644
index 9c016db4502..00000000000
--- a/src/librustdoc/html/static/css/themes/light.css
+++ /dev/null
@@ -1,99 +0,0 @@
-:root {
-	--main-background-color: white;
-	--main-color: black;
-	--settings-input-color: #2196f3;
-	--settings-input-border-color: #717171;
-	--settings-button-color: #000;
-	--settings-button-border-focus: #717171;
-	--sidebar-background-color: #f5f5f5;
-	--sidebar-background-color-hover: #e0e0e0;
-	--code-block-background-color: #f5f5f5;
-	--scrollbar-track-background-color: #dcdcdc;
-	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
-	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
-	--headings-border-bottom-color: #ddd;
-	--border-color: #e0e0e0;
-	--button-background-color: #fff;
-	--right-side-color: grey;
-	--code-attribute-color: #999;
-	--toggles-color: #999;
-	--toggle-filter: none;
-	--search-input-focused-border-color: #66afe9;
-	--copy-path-button-color: #999;
-	--copy-path-img-filter: invert(50%);
-	--copy-path-img-hover-filter: invert(35%);
-	--codeblock-error-hover-color: rgb(255, 0, 0);
-	--codeblock-error-color: rgba(255, 0, 0, .5);
-	--codeblock-ignore-hover-color: rgb(255, 142, 0);
-	--codeblock-ignore-color: rgba(255, 142, 0, .6);
-	--warning-border-color: #ff8e00;
-	--type-link-color: #ad378a;
-	--trait-link-color: #6e4fc9;
-	--assoc-item-link-color: #3873ad;
-	--function-link-color: #ad7c37;
-	--macro-link-color: #068000;
-	--keyword-link-color: #3873ad;
-	--mod-link-color: #3873ad;
-	--link-color: #3873ad;
-	--sidebar-link-color: #356da4;
-	--sidebar-current-link-background-color: #fff;
-	--search-result-link-focus-background-color: #ccc;
-	--search-result-border-color: #aaa3;
-	--search-color: #000;
-	--search-error-code-background-color: #d0cccc;
-	--search-results-alias-color: #000;
-	--search-results-grey-color: #999;
-	--search-tab-title-count-color: #888;
-	--search-tab-button-not-selected-border-top-color: #e6e6e6;
-	--search-tab-button-not-selected-background: #e6e6e6;
-	--search-tab-button-selected-border-top-color: #0089ff;
-	--search-tab-button-selected-background: #fff;
-	--stab-background-color: #fff5d6;
-	--stab-code-color: #000;
-	--code-highlight-kw-color: #8959a8;
-	--code-highlight-kw-2-color: #4271ae;
-	--code-highlight-lifetime-color: #b76514;
-	--code-highlight-prelude-color: #4271ae;
-	--code-highlight-prelude-val-color: #c82829;
-	--code-highlight-number-color: #718c00;
-	--code-highlight-string-color: #718c00;
-	--code-highlight-literal-color: #c82829;
-	--code-highlight-attribute-color: #c82829;
-	--code-highlight-self-color: #c82829;
-	--code-highlight-macro-color: #3e999f;
-	--code-highlight-question-mark-color: #ff9011;
-	--code-highlight-comment-color: #8e908c;
-	--code-highlight-doc-comment-color: #4d4d4c;
-	--src-line-numbers-span-color: #c67e2d;
-	--src-line-number-highlighted-background-color: #fdffd3;
-	--test-arrow-color: #f5f5f5;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: rgb(78, 139, 202);
-	--target-background-color: #fdffd3;
-	--target-border-color: #ad7c37;
-	--kbd-color: #000;
-	--kbd-background: #fafbfc;
-	--kbd-box-shadow-color: #c6cbd1;
-	--rust-logo-filter: initial;
-	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-	--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
-		brightness(114%) contrast(76%);
-	--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
-		brightness(96%) contrast(93%);
-	--crate-search-hover-border: #717171;
-	--src-sidebar-background-selected: #fff;
-	--src-sidebar-background-hover: #e0e0e0;
-	--table-alt-row-background-color: #f5f5f5;
-	--codeblock-link-background: #eee;
-	--scrape-example-toggle-line-background: #ccc;
-	--scrape-example-toggle-line-hover-background: #999;
-	--scrape-example-code-line-highlight: #fcffd6;
-	--scrape-example-code-line-highlight-focus: #f6fdb0;
-	--scrape-example-help-border-color: #555;
-	--scrape-example-help-color: #333;
-	--scrape-example-help-hover-border-color: #000;
-	--scrape-example-help-hover-color: #000;
-	--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
-	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
-}
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 822d22946b4..eb256455b08 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -49,10 +49,12 @@ window.currentCrate = getVar("current-crate");
 function setMobileTopbar() {
     // FIXME: It would be nicer to generate this text content directly in HTML,
     // but with the current code it's hard to get the right information in the right place.
-    const mobileLocationTitle = document.querySelector(".mobile-topbar h2");
+    const mobileTopbar = document.querySelector(".mobile-topbar");
     const locationTitle = document.querySelector(".sidebar h2.location");
-    if (mobileLocationTitle && locationTitle) {
-        mobileLocationTitle.innerHTML = locationTitle.innerHTML;
+    if (mobileTopbar && locationTitle) {
+        const mobileTitle = document.createElement("h2");
+        mobileTitle.innerHTML = locationTitle.innerHTML;
+        mobileTopbar.appendChild(mobileTitle);
     }
 }
 
@@ -204,9 +206,6 @@ function preLoadCss(cssUrl) {
         // Sending request for the CSS and the JS files at the same time so it will
         // hopefully be loaded when the JS will generate the settings content.
         loadScript(getVar("static-root-path") + getVar("settings-js"));
-        preLoadCss(getVar("static-root-path") + getVar("theme-light-css"));
-        preLoadCss(getVar("static-root-path") + getVar("theme-dark-css"));
-        preLoadCss(getVar("static-root-path") + getVar("theme-ayu-css"));
         // Pre-load all theme CSS files, so that switching feels seamless.
         //
         // When loading settings.html as a standalone page, the equivalent HTML is
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index af3ca42a6c0..c69641092ab 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -5,6 +5,7 @@
 // the page, so we don't see major layout changes during the load of the page.
 "use strict";
 
+const builtinThemes = ["light", "dark", "ayu"];
 const darkThemes = ["dark", "ayu"];
 window.currentTheme = document.getElementById("themeStyle");
 
@@ -119,19 +120,32 @@ function switchTheme(newThemeName, saveTheme) {
         updateLocalStorage("theme", newThemeName);
     }
 
-    let newHref;
+    document.documentElement.setAttribute("data-theme", newThemeName);
 
-    if (newThemeName === "light" || newThemeName === "dark" || newThemeName === "ayu") {
-        newHref = getVar("static-root-path") + getVar("theme-" + newThemeName + "-css");
+    if (builtinThemes.indexOf(newThemeName) !== -1) {
+        if (window.currentTheme) {
+            window.currentTheme.parentNode.removeChild(window.currentTheme);
+            window.currentTheme = null;
+        }
     } else {
-        newHref = getVar("root-path") + newThemeName + getVar("resource-suffix") + ".css";
-    }
-
-    if (!window.currentTheme) {
-        document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
-        window.currentTheme = document.getElementById("themeStyle");
-    } else if (newHref !== window.currentTheme.href) {
-        window.currentTheme.href = newHref;
+        const newHref = getVar("root-path") + newThemeName +
+            getVar("resource-suffix") + ".css";
+        if (!window.currentTheme) {
+            // If we're in the middle of loading, document.write blocks
+            // rendering, but if we are done, it would blank the page.
+            if (document.readyState === "loading") {
+                document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
+                window.currentTheme = document.getElementById("themeStyle");
+            } else {
+                window.currentTheme = document.createElement("link");
+                window.currentTheme.rel = "stylesheet";
+                window.currentTheme.id = "themeStyle";
+                window.currentTheme.href = newHref;
+                document.documentElement.appendChild(window.currentTheme);
+            }
+        } else if (newHref !== window.currentTheme.href) {
+            window.currentTheme.href = newHref;
+        }
     }
 }
 
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 7742646f81a..ca9a78f51b3 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -108,9 +108,6 @@ static_files! {
     rust_favicon_svg => "static/images/favicon.svg",
     rust_favicon_png_16 => "static/images/favicon-16x16.png",
     rust_favicon_png_32 => "static/images/favicon-32x32.png",
-    theme_light_css => "static/css/themes/light.css",
-    theme_dark_css => "static/css/themes/dark.css",
-    theme_ayu_css => "static/css/themes/ayu.css",
     fira_sans_regular => "static/fonts/FiraSans-Regular.woff2",
     fira_sans_medium => "static/fonts/FiraSans-Medium.woff2",
     fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index ad63571c6d0..579c782be09 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -33,9 +33,6 @@
          data-channel="{{rust_channel}}" {#+ #}
          data-search-js="{{files.search_js}}" {#+ #}
          data-settings-js="{{files.settings_js}}" {#+ #}
-         data-theme-light-css="{{files.theme_light_css}}" {#+ #}
-         data-theme-dark-css="{{files.theme_dark_css}}" {#+ #}
-         data-theme-ayu-css="{{files.theme_ayu_css}}" {#+ #}
     > {# #}
     <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {# #}
     {% if page.css_class.contains("crate") %}
@@ -52,12 +49,6 @@
     {% endif %}
     <noscript> {# #}
         <link rel="stylesheet" {#+ #}
-           media="(prefers-color-scheme:light)" {#+ #}
-           href="{{static_root_path|safe}}{{files.theme_light_css}}"> {# #}
-        <link rel="stylesheet" {#+ #}
-           media="(prefers-color-scheme:dark)" {#+ #}
-           href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {# #}
-        <link rel="stylesheet" {#+ #}
            href="{{static_root_path|safe}}{{files.noscript_css}}"> {# #}
     </noscript> {# #}
     {% if layout.css_file_extension.is_some() %}
@@ -93,8 +84,7 @@
             <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
         {% endif %}
         </a> {# #}
-        <h2></h2> {# #}
-    </nav> {# #}
+    </nav>
     {% endif %}
     <nav class="sidebar"> {# #}
         {% if page.css_class != "src" %}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 92e06f3ab0f..2f88f6dc6e0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -430,8 +430,8 @@ fn opts() -> Vec<RustcOptGroup> {
             o.optopt(
                 "",
                 "resource-suffix",
-                "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \
-                 \"light-suffix.css\"",
+                "suffix to add to CSS and JavaScript files, e.g., \"search-index.js\" will \
+                 become \"search-index-suffix.js\"",
                 "PATH",
             )
         }),
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 526eea30478..b74a9392f27 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -80,6 +80,8 @@ pub(crate) fn render<P: AsRef<Path>>(
             error_codes,
             edition,
             playground: &playground,
+            // For markdown files, it'll be disabled until the feature is enabled by default.
+            custom_code_classes_in_docs: false,
         }
         .into_string()
     } else {
@@ -91,6 +93,8 @@ pub(crate) fn render<P: AsRef<Path>>(
             edition,
             playground: &playground,
             heading_offset: HeadingOffset::H1,
+            // For markdown files, it'll be disabled until the feature is enabled by default.
+            custom_code_classes_in_docs: false,
         }
         .into_string()
     };
@@ -154,7 +158,15 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
     collector.set_position(DUMMY_SP);
     let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
 
-    find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
+    // For markdown files, custom code classes will be disabled until the feature is enabled by default.
+    find_testable_code(
+        &input_str,
+        &mut collector,
+        codes,
+        options.enable_per_target_ignores,
+        None,
+        false,
+    );
 
     crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
     Ok(())
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 592dd0a145c..60def40588a 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -208,7 +208,14 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
                 let has_docs = !i.attrs.doc_strings.is_empty();
                 let mut tests = Tests { found_tests: 0 };
 
-                find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, false, None);
+                find_testable_code(
+                    &i.doc_value(),
+                    &mut tests,
+                    ErrorCodes::No,
+                    false,
+                    None,
+                    self.ctx.tcx.features().custom_code_classes_in_docs,
+                );
 
                 let has_doc_example = tests.found_tests != 0;
                 let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
diff --git a/src/librustdoc/passes/check_custom_code_classes.rs b/src/librustdoc/passes/check_custom_code_classes.rs
new file mode 100644
index 00000000000..1a703a4e967
--- /dev/null
+++ b/src/librustdoc/passes/check_custom_code_classes.rs
@@ -0,0 +1,88 @@
+//! NIGHTLY & UNSTABLE CHECK: custom_code_classes_in_docs
+//!
+//! This pass will produce errors when finding custom classes outside of
+//! nightly + relevant feature active.
+
+use super::Pass;
+use crate::clean::{Crate, Item};
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::html::markdown::{find_codes, ErrorCodes, LangString};
+
+use rustc_errors::StashKey;
+use rustc_feature::GateIssue;
+use rustc_session::parse::add_feature_diagnostics_for_issue;
+use rustc_span::symbol::sym;
+
+pub(crate) const CHECK_CUSTOM_CODE_CLASSES: Pass = Pass {
+    name: "check-custom-code-classes",
+    run: check_custom_code_classes,
+    description: "check for custom code classes without the feature-gate enabled",
+};
+
+pub(crate) fn check_custom_code_classes(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let mut coll = CustomCodeClassLinter { cx };
+
+    coll.fold_crate(krate)
+}
+
+struct CustomCodeClassLinter<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
+}
+
+impl<'a, 'tcx> DocFolder for CustomCodeClassLinter<'a, 'tcx> {
+    fn fold_item(&mut self, item: Item) -> Option<Item> {
+        look_for_custom_classes(&self.cx, &item);
+        Some(self.fold_item_recur(item))
+    }
+}
+
+#[derive(Debug)]
+struct TestsWithCustomClasses {
+    custom_classes_found: Vec<String>,
+}
+
+impl crate::doctest::Tester for TestsWithCustomClasses {
+    fn add_test(&mut self, _: String, config: LangString, _: usize) {
+        self.custom_classes_found.extend(config.added_classes.into_iter());
+    }
+}
+
+pub(crate) fn look_for_custom_classes<'tcx>(cx: &DocContext<'tcx>, item: &Item) {
+    if !item.item_id.is_local() {
+        // If non-local, no need to check anything.
+        return;
+    }
+
+    let mut tests = TestsWithCustomClasses { custom_classes_found: vec![] };
+
+    let dox = item.attrs.doc_value();
+    find_codes(&dox, &mut tests, ErrorCodes::No, false, None, true, true);
+
+    if !tests.custom_classes_found.is_empty() && !cx.tcx.features().custom_code_classes_in_docs {
+        let span = item.attr_span(cx.tcx);
+        let sess = &cx.tcx.sess.parse_sess;
+        let mut err = sess
+            .span_diagnostic
+            .struct_span_warn(span, "custom classes in code blocks will change behaviour");
+        add_feature_diagnostics_for_issue(
+            &mut err,
+            sess,
+            sym::custom_code_classes_in_docs,
+            GateIssue::Language,
+            false,
+        );
+
+        err.note(
+            // This will list the wrong items to make them more easily searchable.
+            // To ensure the most correct hits, it adds back the 'class:' that was stripped.
+            format!(
+                "found these custom classes: class={}",
+                tests.custom_classes_found.join(",class=")
+            ),
+        );
+
+        // A later feature_err call can steal and cancel this warning.
+        err.stash(span, StashKey::EarlySyntaxWarning);
+    }
+}
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 96224d7c6e2..d1c4cc1f595 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -113,7 +113,14 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
 
     let mut tests = Tests { found_tests: 0 };
 
-    find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
+    find_testable_code(
+        dox,
+        &mut tests,
+        ErrorCodes::No,
+        false,
+        None,
+        cx.tcx.features().custom_code_classes_in_docs,
+    );
 
     if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
         if should_have_doc_example(cx, item) {
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 316b1a41c7d..ac8a75a4f18 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -20,7 +20,9 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
     if let Some(dox) = &item.opt_doc_value() {
         let sp = item.attr_span(cx.tcx);
         let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp);
-        for code_block in markdown::rust_code_blocks(dox, &extra) {
+        for code_block in
+            markdown::rust_code_blocks(dox, &extra, cx.tcx.features().custom_code_classes_in_docs)
+        {
             check_rust_syntax(cx, item, dox, code_block);
         }
     }
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index bb678e33888..4eeaaa2bb70 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -35,6 +35,9 @@ pub(crate) use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 mod lint;
 pub(crate) use self::lint::RUN_LINTS;
 
+mod check_custom_code_classes;
+pub(crate) use self::check_custom_code_classes::CHECK_CUSTOM_CODE_CLASSES;
+
 /// A single pass over the cleaned documentation.
 ///
 /// Runs in the compiler context, so it has access to types and traits and the like.
@@ -66,6 +69,7 @@ pub(crate) enum Condition {
 
 /// The full list of passes.
 pub(crate) const PASSES: &[Pass] = &[
+    CHECK_CUSTOM_CODE_CLASSES,
     CHECK_DOC_TEST_VISIBILITY,
     STRIP_HIDDEN,
     STRIP_PRIVATE,
@@ -79,6 +83,7 @@ pub(crate) const PASSES: &[Pass] = &[
 
 /// The list of passes run by default.
 pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(CHECK_CUSTOM_CODE_CLASSES),
     ConditionalPass::always(COLLECT_TRAIT_IMPLS),
     ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 722e01cd1fc..8c1acbd7347 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -185,6 +185,9 @@ pub(crate) fn parse_selectors(
     while let Some(c) = iter.next() {
         match c {
             '{' => {
+                if selector.trim().starts_with(":root[data-theme") {
+                    selector = String::from(":root");
+                }
                 let s = minifier::css::minify(selector.trim()).map(|s| s.to_string())?;
                 parse_rules(content, s, iter, paths)?;
                 selector.clear();
diff --git a/src/librustdoc/theme/tests.rs b/src/librustdoc/theme/tests.rs
index 2a28c19c3fe..56f40b8046d 100644
--- a/src/librustdoc/theme/tests.rs
+++ b/src/librustdoc/theme/tests.rs
@@ -100,7 +100,7 @@ fn check_invalid_css() {
 
 #[test]
 fn test_with_minification() {
-    let text = include_str!("../html/static/css/themes/dark.css");
+    let text = include_str!("../html/static/css/noscript.css");
     let minified = minifier::css::minify(&text).expect("CSS minification failed").to_string();
 
     let against = load_css_paths(text).unwrap();
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 2fc85d15a542bfb610aff7682073412cf635352
+Subproject b4ddf95ad9954118ac0dae835f2966394ad04c0
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 243192385c2..88466333787 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -204,7 +204,7 @@ fn is_value_unfrozen_raw<'tcx>(
             // similar to 2., but with the a frozen variant) (e.g. borrowing
             // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
             // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
-            err == ErrorHandled::TooGeneric
+            matches!(err, ErrorHandled::TooGeneric(..))
         },
         |val| val.map_or(true, |val| inner(cx, val, ty)),
     )
@@ -244,8 +244,8 @@ pub fn const_eval_resolve<'tcx>(
             };
             tcx.const_eval_global_id_for_typeck(param_env, cid, span)
         },
-        Ok(None) => Err(ErrorHandled::TooGeneric),
-        Err(err) => Err(ErrorHandled::Reported(err.into())),
+        Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
+        Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
     }
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
index d14974faffa..f8ace799593 100644
--- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of `main::{constant#3}` failed
 LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
    |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/test.rs:37:5
    |
 LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index def30f5903d..b454c29aef4 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -10,7 +10,7 @@
     arithmetic_overflow,
     unconditional_panic
 )]
-#![feature(const_mut_refs, inline_const, saturating_int_impl)]
+#![feature(const_mut_refs, inline_const)]
 #![warn(clippy::arithmetic_side_effects)]
 
 extern crate proc_macro_derive;
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
index 64facf20803..1c34875d2b8 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -24,7 +24,7 @@ error[E0080]: evaluation of `main::{constant#3}` failed
 LL |     const { &ARR[idx4()] };
    |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/indexing_slicing_index.rs:48:5
    |
 LL |     const { &ARR[idx4()] };
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 855df427538..7b42d8e9b58 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -695,7 +695,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_command_to_procres(&self, cmd: &mut Command) -> ProcRes {
-        let output = cmd.output().unwrap_or_else(|_| panic!("failed to exec `{cmd:?}`"));
+        let output = cmd.output().unwrap_or_else(|e| panic!("failed to exec `{cmd:?}`: {e:?}"));
 
         let proc_res = ProcRes {
             status: output.status,
@@ -1216,12 +1216,12 @@ impl<'test> TestCx<'test> {
                 .arg(&exe_file)
                 .arg(&self.config.adb_test_dir)
                 .status()
-                .unwrap_or_else(|_| panic!("failed to exec `{:?}`", adb_path));
+                .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}"));
 
             Command::new(adb_path)
                 .args(&["forward", "tcp:5039", "tcp:5039"])
                 .status()
-                .unwrap_or_else(|_| panic!("failed to exec `{:?}`", adb_path));
+                .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}"));
 
             let adb_arg = format!(
                 "export LD_LIBRARY_PATH={}; \
@@ -1238,7 +1238,7 @@ impl<'test> TestCx<'test> {
                 .stdout(Stdio::piped())
                 .stderr(Stdio::inherit())
                 .spawn()
-                .unwrap_or_else(|_| panic!("failed to exec `{:?}`", adb_path));
+                .unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}"));
 
             // Wait for the gdbserver to print out "Listening on port ..."
             // at which point we know that it's started and then we can
@@ -1263,7 +1263,7 @@ impl<'test> TestCx<'test> {
             let Output { status, stdout, stderr } = Command::new(&gdb_path)
                 .args(debugger_opts)
                 .output()
-                .unwrap_or_else(|_| panic!("failed to exec `{:?}`", gdb_path));
+                .unwrap_or_else(|e| panic!("failed to exec `{gdb_path:?}`: {e:?}"));
             let cmdline = {
                 let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
                 gdb.args(debugger_opts);
@@ -2277,7 +2277,7 @@ impl<'test> TestCx<'test> {
         add_dylib_path(&mut command, iter::once(lib_path).chain(aux_path));
 
         let mut child = disable_error_reporting(|| command.spawn())
-            .unwrap_or_else(|_| panic!("failed to exec `{:?}`", &command));
+            .unwrap_or_else(|e| panic!("failed to exec `{command:?}`: {e:?}"));
         if let Some(input) = input {
             child.stdin.as_mut().unwrap().write_all(input.as_bytes()).unwrap();
         }
@@ -3847,8 +3847,8 @@ impl<'test> TestCx<'test> {
                     .open(coverage_file_path.as_path())
                     .expect("could not create or open file");
 
-                if writeln!(file, "{}", self.testpaths.file.display()).is_err() {
-                    panic!("couldn't write to {}", coverage_file_path.display());
+                if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) {
+                    panic!("couldn't write to {}: {e:?}", coverage_file_path.display());
                 }
             }
         } else if self.props.run_rustfix {
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 17bed38b65e..02648fe5c29 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -13,6 +13,7 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
     "aarch64-apple-ios",
     "aarch64-apple-ios-sim",
+    "aarch64-apple-ios-macabi",
     "aarch64-unknown-fuchsia",
     "aarch64-linux-android",
     "aarch64-unknown-linux-gnu",
@@ -22,6 +23,7 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "i686-unknown-linux-gnu",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
+    "x86_64-apple-ios-macabi",
     "x86_64-unknown-fuchsia",
     "x86_64-linux-android",
     "x86_64-unknown-freebsd",
@@ -60,6 +62,7 @@ pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
     // "aarch64-apple-darwin",
     "aarch64-unknown-linux-gnu",
     "x86_64-apple-darwin",
+    "x86_64-apple-ios-macabi",
     "x86_64-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
 ];
@@ -75,9 +78,11 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
     "aarch64-apple-ios",
     "aarch64-apple-ios-sim",
+    "aarch64-apple-ios-macabi",
     "aarch64-unknown-linux-gnu",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
+    "x86_64-apple-ios-macabi",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 5e635667ecf..a2030c1c343 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-ae9465fee3962c0c895959001302999bc48ba6d5
+19dd9535408db0f1ff3d16613619076aef524d19
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 0c7e8278147..72d9dbd045d 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -142,9 +142,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     fn eval_path_scalar(&self, path: &[&str]) -> Scalar<Provenance> {
         let this = self.eval_context_ref();
         let instance = this.resolve_path(path, Namespace::ValueNS);
-        let cid = GlobalId { instance, promoted: None };
         // We don't give a span -- this isn't actually used directly by the program anyway.
-        let const_val = this.eval_global(cid, None).unwrap_or_else(|err| {
+        let const_val = this.eval_global(instance).unwrap_or_else(|err| {
             panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
         });
         this.read_scalar(&const_val)
diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr
index 596a6bb4ca8..d2b9018cd4b 100644
--- a/src/tools/miri/tests/fail/const-ub-checks.stderr
+++ b/src/tools/miri/tests/fail/const-ub-checks.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL |     ptr.read();
    |     ^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-ub-checks.rs:LL:CC
    |
 LL |     let _x = UNALIGNED_READ;
diff --git a/src/tools/miri/tests/fail/erroneous_const.stderr b/src/tools/miri/tests/fail/erroneous_const.stderr
index 209c4a932dc..cacf866393d 100644
--- a/src/tools/miri/tests/fail/erroneous_const.stderr
+++ b/src/tools/miri/tests/fail/erroneous_const.stderr
@@ -6,7 +6,7 @@ LL |     const VOID: ! = panic!();
    |
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/erroneous_const.rs:LL:CC
    |
 LL |         let _ = PrintName::<T>::VOID;
diff --git a/src/tools/miri/tests/fail/erroneous_const2.stderr b/src/tools/miri/tests/fail/erroneous_const2.stderr
index 9aad1fc9b02..36e83b8f3bc 100644
--- a/src/tools/miri/tests/fail/erroneous_const2.stderr
+++ b/src/tools/miri/tests/fail/erroneous_const2.stderr
@@ -4,13 +4,13 @@ error[E0080]: evaluation of constant value failed
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    |                   ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/erroneous_const2.rs:LL:CC
    |
 LL |     println!("{}", FOO);
    |                    ^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/erroneous_const2.rs:LL:CC
    |
 LL |     println!("{}", FOO);
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 3f7dba81c3a..f1c3dd6aa9b 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -21,3 +21,5 @@ serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 glob = "0.3"
 tempfile = "3.5"
+derive_builder = "0.12"
+clap = { version = "4", features = ["derive"] }
diff --git a/src/tools/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs
new file mode 100644
index 00000000000..ff782a1687e
--- /dev/null
+++ b/src/tools/opt-dist/src/environment.rs
@@ -0,0 +1,108 @@
+use camino::Utf8PathBuf;
+use derive_builder::Builder;
+
+#[derive(Builder)]
+pub struct Environment {
+    host_triple: String,
+    python_binary: String,
+    /// The rustc checkout, where the compiler source is located.
+    checkout_dir: Utf8PathBuf,
+    /// The main directory where the build occurs. Stage0 rustc and cargo have to be available in
+    /// this directory before `opt-dist` is started.
+    build_dir: Utf8PathBuf,
+    /// Directory where the optimization artifacts (PGO/BOLT profiles, etc.)
+    /// will be stored.
+    artifact_dir: Utf8PathBuf,
+    /// Path to the host LLVM used to compile LLVM in `src/llvm-project`.
+    host_llvm_dir: Utf8PathBuf,
+    /// List of test paths that should be skipped when testing the optimized artifacts.
+    skipped_tests: Vec<String>,
+    /// Directory containing a pre-built rustc-perf checkout.
+    #[builder(default)]
+    prebuilt_rustc_perf: Option<Utf8PathBuf>,
+    use_bolt: bool,
+    shared_llvm: bool,
+}
+
+impl Environment {
+    pub fn host_triple(&self) -> &str {
+        &self.host_triple
+    }
+
+    pub fn python_binary(&self) -> &str {
+        &self.python_binary
+    }
+
+    pub fn checkout_path(&self) -> Utf8PathBuf {
+        self.checkout_dir.clone()
+    }
+
+    pub fn build_root(&self) -> Utf8PathBuf {
+        self.build_dir.clone()
+    }
+
+    pub fn build_artifacts(&self) -> Utf8PathBuf {
+        self.build_root().join("build").join(&self.host_triple)
+    }
+
+    pub fn artifact_dir(&self) -> Utf8PathBuf {
+        self.artifact_dir.clone()
+    }
+
+    pub fn cargo_stage_0(&self) -> Utf8PathBuf {
+        self.build_artifacts()
+            .join("stage0")
+            .join("bin")
+            .join(format!("cargo{}", executable_extension()))
+    }
+
+    pub fn rustc_stage_0(&self) -> Utf8PathBuf {
+        self.build_artifacts()
+            .join("stage0")
+            .join("bin")
+            .join(format!("rustc{}", executable_extension()))
+    }
+
+    pub fn rustc_stage_2(&self) -> Utf8PathBuf {
+        self.build_artifacts()
+            .join("stage2")
+            .join("bin")
+            .join(format!("rustc{}", executable_extension()))
+    }
+
+    pub fn prebuilt_rustc_perf(&self) -> Option<Utf8PathBuf> {
+        self.prebuilt_rustc_perf.clone()
+    }
+
+    /// Path to the built rustc-perf benchmark suite.
+    pub fn rustc_perf_dir(&self) -> Utf8PathBuf {
+        self.artifact_dir.join("rustc-perf")
+    }
+
+    pub fn host_llvm_dir(&self) -> Utf8PathBuf {
+        self.host_llvm_dir.clone()
+    }
+
+    pub fn use_bolt(&self) -> bool {
+        self.use_bolt
+    }
+
+    pub fn supports_shared_llvm(&self) -> bool {
+        self.shared_llvm
+    }
+
+    pub fn skipped_tests(&self) -> &[String] {
+        &self.skipped_tests
+    }
+}
+
+/// What is the extension of binary executables on this platform?
+#[cfg(target_family = "unix")]
+pub fn executable_extension() -> &'static str {
+    ""
+}
+
+#[cfg(target_family = "windows")]
+pub fn executable_extension() -> &'static str {
+    ".exe"
+}
diff --git a/src/tools/opt-dist/src/environment/linux.rs b/src/tools/opt-dist/src/environment/linux.rs
deleted file mode 100644
index 58b7e6d2306..00000000000
--- a/src/tools/opt-dist/src/environment/linux.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use crate::environment::Environment;
-use crate::exec::cmd;
-use crate::utils::io::copy_directory;
-use camino::{Utf8Path, Utf8PathBuf};
-
-pub(super) struct LinuxEnvironment;
-
-impl Environment for LinuxEnvironment {
-    fn python_binary(&self) -> &'static str {
-        "python3"
-    }
-
-    fn checkout_path(&self) -> Utf8PathBuf {
-        Utf8PathBuf::from("/checkout")
-    }
-
-    fn host_llvm_dir(&self) -> Utf8PathBuf {
-        Utf8PathBuf::from("/rustroot")
-    }
-
-    fn opt_artifacts(&self) -> Utf8PathBuf {
-        Utf8PathBuf::from("/tmp/tmp-multistage/opt-artifacts")
-    }
-
-    fn build_root(&self) -> Utf8PathBuf {
-        self.checkout_path().join("obj")
-    }
-
-    fn prepare_rustc_perf(&self) -> anyhow::Result<()> {
-        // /tmp/rustc-perf comes from the x64 dist Dockerfile
-        copy_directory(Utf8Path::new("/tmp/rustc-perf"), &self.rustc_perf_dir())?;
-        cmd(&[self.cargo_stage_0().as_str(), "build", "-p", "collector"])
-            .workdir(&self.rustc_perf_dir())
-            .env("RUSTC", &self.rustc_stage_0().into_string())
-            .env("RUSTC_BOOTSTRAP", "1")
-            .run()?;
-        Ok(())
-    }
-
-    fn supports_bolt(&self) -> bool {
-        true
-    }
-
-    fn supports_shared_llvm(&self) -> bool {
-        true
-    }
-
-    fn executable_extension(&self) -> &'static str {
-        ""
-    }
-
-    fn skipped_tests(&self) -> &'static [&'static str] {
-        &[
-            // Fails because of linker errors, as of June 2023.
-            "tests/ui/process/nofile-limit.rs",
-        ]
-    }
-}
diff --git a/src/tools/opt-dist/src/environment/mod.rs b/src/tools/opt-dist/src/environment/mod.rs
deleted file mode 100644
index a8650fad011..00000000000
--- a/src/tools/opt-dist/src/environment/mod.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use camino::Utf8PathBuf;
-
-#[cfg(target_family = "unix")]
-mod linux;
-#[cfg(target_family = "windows")]
-mod windows;
-
-pub trait Environment {
-    fn host_triple(&self) -> String {
-        std::env::var("PGO_HOST").expect("PGO_HOST environment variable missing")
-    }
-
-    fn python_binary(&self) -> &'static str;
-
-    /// The rustc checkout, where the compiler source is located.
-    fn checkout_path(&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.
-    fn opt_artifacts(&self) -> Utf8PathBuf;
-
-    /// The main directory where the build occurs.
-    fn build_root(&self) -> Utf8PathBuf;
-
-    fn build_artifacts(&self) -> Utf8PathBuf {
-        self.build_root().join("build").join(self.host_triple())
-    }
-
-    fn cargo_stage_0(&self) -> Utf8PathBuf {
-        self.build_artifacts()
-            .join("stage0")
-            .join("bin")
-            .join(format!("cargo{}", self.executable_extension()))
-    }
-
-    fn rustc_stage_0(&self) -> Utf8PathBuf {
-        self.build_artifacts()
-            .join("stage0")
-            .join("bin")
-            .join(format!("rustc{}", self.executable_extension()))
-    }
-
-    fn rustc_stage_2(&self) -> Utf8PathBuf {
-        self.build_artifacts()
-            .join("stage2")
-            .join("bin")
-            .join(format!("rustc{}", self.executable_extension()))
-    }
-
-    /// Path to the built rustc-perf benchmark suite.
-    fn rustc_perf_dir(&self) -> Utf8PathBuf {
-        self.opt_artifacts().join("rustc-perf")
-    }
-
-    /// Download and/or compile rustc-perf.
-    fn prepare_rustc_perf(&self) -> anyhow::Result<()>;
-
-    fn supports_bolt(&self) -> bool;
-
-    fn supports_shared_llvm(&self) -> bool;
-
-    /// What is the extension of binary executables in this environment?
-    fn executable_extension(&self) -> &'static str;
-
-    /// List of test paths that should be skipped when testing the optimized artifacts.
-    fn skipped_tests(&self) -> &'static [&'static str];
-}
-
-pub fn create_environment() -> Box<dyn Environment> {
-    #[cfg(target_family = "unix")]
-    return Box::new(linux::LinuxEnvironment);
-    #[cfg(target_family = "windows")]
-    return Box::new(windows::WindowsEnvironment::new());
-}
diff --git a/src/tools/opt-dist/src/environment/windows.rs b/src/tools/opt-dist/src/environment/windows.rs
deleted file mode 100644
index 79399391798..00000000000
--- a/src/tools/opt-dist/src/environment/windows.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-use crate::environment::Environment;
-use crate::exec::cmd;
-use crate::utils::io::move_directory;
-use crate::utils::retry_action;
-use camino::Utf8PathBuf;
-use std::io::Cursor;
-use std::time::Duration;
-use zip::ZipArchive;
-
-pub(super) struct WindowsEnvironment {
-    checkout_dir: Utf8PathBuf,
-}
-
-impl WindowsEnvironment {
-    pub fn new() -> Self {
-        Self { checkout_dir: std::env::current_dir().unwrap().try_into().unwrap() }
-    }
-}
-
-impl Environment for WindowsEnvironment {
-    fn python_binary(&self) -> &'static str {
-        "python"
-    }
-
-    fn checkout_path(&self) -> Utf8PathBuf {
-        self.checkout_dir.clone()
-    }
-
-    fn host_llvm_dir(&self) -> Utf8PathBuf {
-        self.checkout_path().join("citools").join("clang-rust")
-    }
-
-    fn opt_artifacts(&self) -> Utf8PathBuf {
-        self.checkout_path().join("opt-artifacts")
-    }
-
-    fn build_root(&self) -> Utf8PathBuf {
-        self.checkout_path()
-    }
-
-    fn prepare_rustc_perf(&self) -> anyhow::Result<()> {
-        // FIXME: add some mechanism for synchronization of this commit SHA with
-        // Linux (which builds rustc-perf in a Dockerfile)
-        // rustc-perf version from 2023-05-30
-        const PERF_COMMIT: &str = "8b2ac3042e1ff2c0074455a0a3618adef97156b1";
-
-        let url = format!("https://ci-mirrors.rust-lang.org/rustc/rustc-perf-{PERF_COMMIT}.zip");
-        let client = reqwest::blocking::Client::builder()
-            .timeout(Duration::from_secs(60 * 2))
-            .connect_timeout(Duration::from_secs(60 * 2))
-            .build()?;
-        let response = retry_action(
-            || Ok(client.get(&url).send()?.error_for_status()?.bytes()?.to_vec()),
-            "Download rustc-perf archive",
-            5,
-        )?;
-
-        let mut archive = ZipArchive::new(Cursor::new(response))?;
-        archive.extract(self.rustc_perf_dir())?;
-        move_directory(
-            &self.rustc_perf_dir().join(format!("rustc-perf-{PERF_COMMIT}")),
-            &self.rustc_perf_dir(),
-        )?;
-
-        cmd(&[self.cargo_stage_0().as_str(), "build", "-p", "collector"])
-            .workdir(&self.rustc_perf_dir())
-            .env("RUSTC", &self.rustc_stage_0().into_string())
-            .env("RUSTC_BOOTSTRAP", "1")
-            .run()?;
-
-        Ok(())
-    }
-
-    fn supports_bolt(&self) -> bool {
-        false
-    }
-
-    fn supports_shared_llvm(&self) -> bool {
-        false
-    }
-
-    fn executable_extension(&self) -> &'static str {
-        ".exe"
-    }
-
-    fn skipped_tests(&self) -> &'static [&'static str] {
-        &[
-            // Fails as of June 2023.
-            "tests\\codegen\\vec-shrink-panik.rs",
-        ]
-    }
-}
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 4765dceb5dd..04e0184528a 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -96,7 +96,7 @@ pub struct Bootstrap {
 }
 
 impl Bootstrap {
-    pub fn build(env: &dyn Environment) -> Self {
+    pub fn build(env: &Environment) -> Self {
         let metrics_path = env.build_root().join("build").join("metrics.json");
         let cmd = cmd(&[
             env.python_binary(),
@@ -114,7 +114,7 @@ impl Bootstrap {
         Self { cmd, metrics_path }
     }
 
-    pub fn dist(env: &dyn Environment, dist_args: &[String]) -> Self {
+    pub fn dist(env: &Environment, dist_args: &[String]) -> Self {
         let metrics_path = env.build_root().join("build").join("metrics.json");
         let cmd = cmd(&dist_args.iter().map(|arg| arg.as_str()).collect::<Vec<_>>())
             .env("RUST_BACKTRACE", "full");
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index 8ab19674d05..978e2dfa4e8 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -1,17 +1,22 @@
 use crate::bolt::{bolt_optimize, with_bolt_instrumented};
 use anyhow::Context;
+use camino::{Utf8Path, Utf8PathBuf};
+use clap::Parser;
 use log::LevelFilter;
+use std::io::Cursor;
+use std::time::Duration;
 use utils::io;
+use zip::ZipArchive;
 
-use crate::environment::{create_environment, Environment};
-use crate::exec::Bootstrap;
+use crate::environment::{Environment, EnvironmentBuilder};
+use crate::exec::{cmd, Bootstrap};
 use crate::tests::run_tests;
 use crate::timer::Timer;
 use crate::training::{gather_llvm_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles};
-use crate::utils::io::reset_directory;
+use crate::utils::io::{copy_directory, move_directory, reset_directory};
 use crate::utils::{
     clear_llvm_files, format_env_variables, print_binary_sizes, print_free_disk_space,
-    with_log_group,
+    retry_action, with_log_group,
 };
 
 mod bolt;
@@ -23,24 +28,169 @@ mod timer;
 mod training;
 mod utils;
 
+#[derive(clap::Parser, Debug)]
+struct Args {
+    #[clap(subcommand)]
+    env: EnvironmentCmd,
+}
+
+#[derive(clap::Parser, Clone, Debug)]
+struct SharedArgs {
+    // Arguments passed to `x` to perform the final (dist) build.
+    build_args: Vec<String>,
+}
+
+#[derive(clap::Parser, Clone, Debug)]
+enum EnvironmentCmd {
+    /// Perform a custom local PGO/BOLT optimized build.
+    Local {
+        /// Target triple of the host.
+        #[arg(long)]
+        target_triple: String,
+
+        /// Checkout directory of `rustc`.
+        #[arg(long)]
+        checkout_dir: Utf8PathBuf,
+
+        /// Host LLVM installation directory.
+        #[arg(long)]
+        llvm_dir: Utf8PathBuf,
+
+        /// Python binary to use in bootstrap invocations.
+        #[arg(long, default_value = "python3")]
+        python: String,
+
+        /// Directory where artifacts (like PGO profiles or rustc-perf) of this workflow
+        /// will be stored.
+        #[arg(long, default_value = "opt-artifacts")]
+        artifact_dir: Utf8PathBuf,
+
+        /// Is LLVM for `rustc` built in shared library mode?
+        #[arg(long, default_value_t = true)]
+        llvm_shared: bool,
+
+        /// Should BOLT optimization be used? If yes, host LLVM must have BOLT binaries
+        /// (`llvm-bolt` and `merge-fdata`) available.
+        #[arg(long, default_value_t = false)]
+        use_bolt: bool,
+
+        /// Tests that should be skipped when testing the optimized compiler.
+        #[arg(long)]
+        skipped_tests: Vec<String>,
+
+        #[clap(flatten)]
+        shared: SharedArgs,
+    },
+    /// Perform an optimized build on Linux CI, from inside Docker.
+    LinuxCi {
+        #[clap(flatten)]
+        shared: SharedArgs,
+    },
+    /// Perform an optimized build on Windows CI, directly inside Github Actions.
+    WindowsCi {
+        #[clap(flatten)]
+        shared: SharedArgs,
+    },
+}
+
 fn is_try_build() -> bool {
     std::env::var("DIST_TRY_BUILD").unwrap_or_else(|_| "0".to_string()) != "0"
 }
 
+fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)> {
+    let (env, args) = match args.env {
+        EnvironmentCmd::Local {
+            target_triple,
+            checkout_dir,
+            llvm_dir,
+            python,
+            artifact_dir,
+            llvm_shared,
+            use_bolt,
+            skipped_tests,
+            shared,
+        } => {
+            let env = EnvironmentBuilder::default()
+                .host_triple(target_triple)
+                .python_binary(python)
+                .checkout_dir(checkout_dir.clone())
+                .host_llvm_dir(llvm_dir)
+                .artifact_dir(artifact_dir)
+                .build_dir(checkout_dir)
+                .shared_llvm(llvm_shared)
+                .use_bolt(use_bolt)
+                .skipped_tests(skipped_tests)
+                .build()?;
+
+            (env, shared.build_args)
+        }
+        EnvironmentCmd::LinuxCi { shared } => {
+            let target_triple =
+                std::env::var("PGO_HOST").expect("PGO_HOST environment variable missing");
+
+            let checkout_dir = Utf8PathBuf::from("/checkout");
+            let env = EnvironmentBuilder::default()
+                .host_triple(target_triple)
+                .python_binary("python3".to_string())
+                .checkout_dir(checkout_dir.clone())
+                .host_llvm_dir(Utf8PathBuf::from("/rustroot"))
+                .artifact_dir(Utf8PathBuf::from("/tmp/tmp-multistage/opt-artifacts"))
+                .build_dir(checkout_dir.join("obj"))
+                // /tmp/rustc-perf comes from the x64 dist Dockerfile
+                .prebuilt_rustc_perf(Some(Utf8PathBuf::from("/tmp/rustc-perf")))
+                .shared_llvm(true)
+                .use_bolt(true)
+                .skipped_tests(vec![
+                    // Fails because of linker errors, as of June 2023.
+                    "tests/ui/process/nofile-limit.rs".to_string(),
+                ])
+                .build()?;
+
+            (env, shared.build_args)
+        }
+        EnvironmentCmd::WindowsCi { shared } => {
+            let target_triple =
+                std::env::var("PGO_HOST").expect("PGO_HOST environment variable missing");
+
+            let checkout_dir: Utf8PathBuf = std::env::current_dir()?.try_into()?;
+            let env = EnvironmentBuilder::default()
+                .host_triple(target_triple)
+                .python_binary("python".to_string())
+                .checkout_dir(checkout_dir.clone())
+                .host_llvm_dir(checkout_dir.join("citools").join("clang-rust"))
+                .artifact_dir(checkout_dir.join("opt-artifacts"))
+                .build_dir(checkout_dir)
+                .shared_llvm(false)
+                .use_bolt(false)
+                .skipped_tests(vec![
+                    // Fails as of June 2023.
+                    "tests\\codegen\\vec-shrink-panik.rs".to_string(),
+                ])
+                .build()?;
+
+            (env, shared.build_args)
+        }
+    };
+    Ok((env, args))
+}
+
 fn execute_pipeline(
-    env: &dyn Environment,
+    env: &Environment,
     timer: &mut Timer,
     dist_args: Vec<String>,
 ) -> anyhow::Result<()> {
-    reset_directory(&env.opt_artifacts())?;
+    reset_directory(&env.artifact_dir())?;
 
-    with_log_group("Building rustc-perf", || env.prepare_rustc_perf())?;
+    with_log_group("Building rustc-perf", || match env.prebuilt_rustc_perf() {
+        Some(dir) => copy_rustc_perf(env, &dir),
+        None => download_rustc_perf(env),
+    })?;
 
     // Stage 1: Build PGO instrumented rustc
     // We use a normal build of LLVM, because gathering PGO profiles for LLVM and `rustc` at the
     // same time can cause issues, because the host and in-tree LLVM versions can diverge.
     let rustc_pgo_profile = timer.section("Stage 1 (Rustc PGO)", |stage| {
-        let rustc_profile_dir_root = env.opt_artifacts().join("rustc-pgo");
+        let rustc_profile_dir_root = env.artifact_dir().join("rustc-pgo");
 
         stage.section("Build PGO instrumented rustc and LLVM", |section| {
             let mut builder = Bootstrap::build(env).rustc_pgo_instrument(&rustc_profile_dir_root);
@@ -74,7 +224,7 @@ fn execute_pipeline(
         // Remove the previous, uninstrumented build of LLVM.
         clear_llvm_files(env)?;
 
-        let llvm_profile_dir_root = env.opt_artifacts().join("llvm-pgo");
+        let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo");
 
         stage.section("Build PGO instrumented LLVM", |section| {
             Bootstrap::build(env)
@@ -95,7 +245,7 @@ fn execute_pipeline(
         Ok(profile)
     })?;
 
-    let llvm_bolt_profile = if env.supports_bolt() {
+    let llvm_bolt_profile = if env.use_bolt() {
         // Stage 3: Build BOLT instrumented LLVM
         // We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles.
         // Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build.
@@ -171,8 +321,9 @@ fn main() -> anyhow::Result<()> {
         .parse_default_env()
         .init();
 
-    let mut build_args: Vec<String> = std::env::args().skip(1).collect();
-    println!("Running optimized build pipeline with args `{}`", build_args.join(" "));
+    let args = Args::parse();
+
+    println!("Running optimized build pipeline with args `{:?}`", args);
 
     with_log_group("Environment values", || {
         println!("Environment values\n{}", format_env_variables());
@@ -184,6 +335,8 @@ fn main() -> anyhow::Result<()> {
         }
     });
 
+    let (env, mut build_args) = create_environment(args).context("Cannot create environment")?;
+
     // Skip components that are not needed for try builds to speed them up
     if is_try_build() {
         log::info!("Skipping building of unimportant components for a try build");
@@ -202,14 +355,58 @@ fn main() -> anyhow::Result<()> {
     }
 
     let mut timer = Timer::new();
-    let env = create_environment();
 
-    let result = execute_pipeline(env.as_ref(), &mut timer, build_args);
+    let result = execute_pipeline(&env, &mut timer, build_args);
     log::info!("Timer results\n{}", timer.format_stats());
 
     print_free_disk_space()?;
     result.context("Optimized build pipeline has failed")?;
-    print_binary_sizes(env.as_ref())?;
+    print_binary_sizes(&env)?;
+
+    Ok(())
+}
+
+// Copy rustc-perf from the given path into the environment and build it.
+fn copy_rustc_perf(env: &Environment, dir: &Utf8Path) -> anyhow::Result<()> {
+    copy_directory(dir, &env.rustc_perf_dir())?;
+    build_rustc_perf(env)
+}
+
+// Download and build rustc-perf into the given environment.
+fn download_rustc_perf(env: &Environment) -> anyhow::Result<()> {
+    reset_directory(&env.rustc_perf_dir())?;
+
+    // FIXME: add some mechanism for synchronization of this commit SHA with
+    // Linux (which builds rustc-perf in a Dockerfile)
+    // rustc-perf version from 2023-05-30
+    const PERF_COMMIT: &str = "8b2ac3042e1ff2c0074455a0a3618adef97156b1";
+
+    let url = format!("https://ci-mirrors.rust-lang.org/rustc/rustc-perf-{PERF_COMMIT}.zip");
+    let client = reqwest::blocking::Client::builder()
+        .timeout(Duration::from_secs(60 * 2))
+        .connect_timeout(Duration::from_secs(60 * 2))
+        .build()?;
+    let response = retry_action(
+        || Ok(client.get(&url).send()?.error_for_status()?.bytes()?.to_vec()),
+        "Download rustc-perf archive",
+        5,
+    )?;
+
+    let mut archive = ZipArchive::new(Cursor::new(response))?;
+    archive.extract(env.rustc_perf_dir())?;
+    move_directory(
+        &env.rustc_perf_dir().join(format!("rustc-perf-{PERF_COMMIT}")),
+        &env.rustc_perf_dir(),
+    )?;
+
+    build_rustc_perf(env)
+}
 
+fn build_rustc_perf(env: &Environment) -> anyhow::Result<()> {
+    cmd(&[env.cargo_stage_0().as_str(), "build", "-p", "collector"])
+        .workdir(&env.rustc_perf_dir())
+        .env("RUSTC", &env.rustc_stage_0().into_string())
+        .env("RUSTC_BOOTSTRAP", "1")
+        .run()?;
     Ok(())
 }
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index 3dd1a3223f5..31aabca09f3 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -1,11 +1,11 @@
-use crate::environment::Environment;
+use crate::environment::{executable_extension, Environment};
 use crate::exec::cmd;
 use crate::utils::io::{copy_directory, find_file_in_dir, unpack_archive};
 use anyhow::Context;
 use camino::{Utf8Path, Utf8PathBuf};
 
 /// Run tests on optimized dist artifacts.
-pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> {
+pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
     // After `dist` is executed, we extract its archived components into a sysroot directory,
     // and then use that extracted rustc as a stage0 compiler.
     // Then we run a subset of tests using that compiler, to have a basic smoke test which checks
@@ -33,8 +33,8 @@ pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> {
 
     // We need to manually copy libstd to the extracted rustc sysroot
     copy_directory(
-        &libstd_dir.join("lib").join("rustlib").join(&host_triple).join("lib"),
-        &rustc_dir.join("lib").join("rustlib").join(&host_triple).join("lib"),
+        &libstd_dir.join("lib").join("rustlib").join(host_triple).join("lib"),
+        &rustc_dir.join("lib").join("rustlib").join(host_triple).join("lib"),
     )?;
 
     // Extract sources - they aren't in the `rustc-nightly-{host}` tarball, so we need to manually copy libstd
@@ -45,9 +45,9 @@ pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> {
         &rustc_dir.join("lib").join("rustlib").join("src"),
     )?;
 
-    let rustc_path = rustc_dir.join("bin").join(format!("rustc{}", env.executable_extension()));
+    let rustc_path = rustc_dir.join("bin").join(format!("rustc{}", executable_extension()));
     assert!(rustc_path.is_file());
-    let cargo_path = cargo_dir.join("bin").join(format!("cargo{}", env.executable_extension()));
+    let cargo_path = cargo_dir.join("bin").join(format!("cargo{}", executable_extension()));
     assert!(cargo_path.is_file());
 
     // Specify path to a LLVM config so that LLVM is not rebuilt.
@@ -56,7 +56,7 @@ pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> {
         .build_artifacts()
         .join("llvm")
         .join("bin")
-        .join(format!("llvm-config{}", env.executable_extension()));
+        .join(format!("llvm-config{}", executable_extension()));
     assert!(llvm_config.is_file());
 
     let config_content = format!(
@@ -109,6 +109,6 @@ fn find_dist_version(directory: &Utf8Path) -> anyhow::Result<String> {
         .unwrap()
         .to_string();
     let (version, _) =
-        archive.strip_prefix("reproducible-artifacts-").unwrap().split_once("-").unwrap();
+        archive.strip_prefix("reproducible-artifacts-").unwrap().split_once('-').unwrap();
     Ok(version.to_string())
 }
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 59c73fbd695..274f4cea0ab 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -1,4 +1,4 @@
-use crate::environment::Environment;
+use crate::environment::{executable_extension, Environment};
 use crate::exec::{cmd, CmdBuilder};
 use crate::utils::io::{count_files, delete_directory};
 use crate::utils::with_log_group;
@@ -30,7 +30,7 @@ const RUSTC_PGO_CRATES: &[&str] = &[
 const LLVM_BOLT_CRATES: &[&str] = LLVM_PGO_CRATES;
 
 fn init_compiler_benchmarks(
-    env: &dyn Environment,
+    env: &Environment,
     profiles: &[&str],
     scenarios: &[&str],
     crates: &[&str],
@@ -75,7 +75,7 @@ enum LlvmProfdata {
 }
 
 fn merge_llvm_profiles(
-    env: &dyn Environment,
+    env: &Environment,
     merged_path: &Utf8Path,
     profile_dir: &Utf8Path,
     profdata: LlvmProfdata,
@@ -86,7 +86,7 @@ fn merge_llvm_profiles(
             .build_artifacts()
             .join("llvm")
             .join("build")
-            .join(format!("bin/llvm-profdata{}", env.executable_extension())),
+            .join(format!("bin/llvm-profdata{}", executable_extension())),
     };
 
     cmd(&[llvm_profdata.as_str(), "merge", "-o", merged_path.as_str(), profile_dir.as_str()])
@@ -116,7 +116,7 @@ fn log_profile_stats(
 pub struct LlvmPGOProfile(pub Utf8PathBuf);
 
 pub fn gather_llvm_profiles(
-    env: &dyn Environment,
+    env: &Environment,
     profile_root: &Utf8Path,
 ) -> anyhow::Result<LlvmPGOProfile> {
     log::info!("Running benchmarks with PGO instrumented LLVM");
@@ -127,7 +127,7 @@ pub fn gather_llvm_profiles(
             .context("Cannot gather LLVM PGO profiles")
     })?;
 
-    let merged_profile = env.opt_artifacts().join("llvm-pgo.profdata");
+    let merged_profile = env.artifact_dir().join("llvm-pgo.profdata");
     log::info!("Merging LLVM PGO profiles to {merged_profile}");
 
     merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Host)?;
@@ -143,7 +143,7 @@ pub fn gather_llvm_profiles(
 pub struct RustcPGOProfile(pub Utf8PathBuf);
 
 pub fn gather_rustc_profiles(
-    env: &dyn Environment,
+    env: &Environment,
     profile_root: &Utf8Path,
 ) -> anyhow::Result<RustcPGOProfile> {
     log::info!("Running benchmarks with PGO instrumented rustc");
@@ -163,7 +163,7 @@ pub fn gather_rustc_profiles(
             .context("Cannot gather rustc PGO profiles")
     })?;
 
-    let merged_profile = env.opt_artifacts().join("rustc-pgo.profdata");
+    let merged_profile = env.artifact_dir().join("rustc-pgo.profdata");
     log::info!("Merging Rustc PGO profiles to {merged_profile}");
 
     merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Target)?;
@@ -178,7 +178,7 @@ pub fn gather_rustc_profiles(
 
 pub struct LlvmBoltProfile(pub Utf8PathBuf);
 
-pub fn gather_llvm_bolt_profiles(env: &dyn Environment) -> anyhow::Result<LlvmBoltProfile> {
+pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltProfile> {
     log::info!("Running benchmarks with BOLT instrumented LLVM");
 
     with_log_group("Running benchmarks", || {
@@ -187,12 +187,12 @@ pub fn gather_llvm_bolt_profiles(env: &dyn Environment) -> anyhow::Result<LlvmBo
             .context("Cannot gather LLVM BOLT profiles")
     })?;
 
-    let merged_profile = env.opt_artifacts().join("llvm-bolt.profdata");
+    let merged_profile = env.artifact_dir().join("llvm-bolt.profdata");
     let profile_root = Utf8PathBuf::from("/tmp/prof.fdata");
     log::info!("Merging LLVM BOLT profiles to {merged_profile}");
 
     let profiles: Vec<_> =
-        glob::glob(&format!("{profile_root}*"))?.into_iter().collect::<Result<Vec<_>, _>>()?;
+        glob::glob(&format!("{profile_root}*"))?.collect::<Result<Vec<_>, _>>()?;
 
     let mut merge_args = vec!["merge-fdata"];
     merge_args.extend(profiles.iter().map(|p| p.to_str().unwrap()));
diff --git a/src/tools/opt-dist/src/utils/io.rs b/src/tools/opt-dist/src/utils/io.rs
index 8bd516fa349..d6bd5cb85e4 100644
--- a/src/tools/opt-dist/src/utils/io.rs
+++ b/src/tools/opt-dist/src/utils/io.rs
@@ -7,7 +7,7 @@ use std::path::Path;
 /// Delete and re-create the directory.
 pub fn reset_directory(path: &Utf8Path) -> anyhow::Result<()> {
     log::info!("Resetting directory {path}");
-    let _ = std::fs::remove_dir(path);
+    let _ = std::fs::remove_dir_all(path);
     std::fs::create_dir_all(path)?;
     Ok(())
 }
@@ -63,7 +63,6 @@ pub fn get_files_from_dir(
     let path = format!("{dir}/*{}", suffix.unwrap_or(""));
 
     Ok(glob::glob(&path)?
-        .into_iter()
         .map(|p| p.map(|p| Utf8PathBuf::from_path_buf(p).unwrap()))
         .collect::<Result<Vec<_>, _>>()?)
 }
@@ -74,9 +73,8 @@ pub fn find_file_in_dir(
     prefix: &str,
     suffix: &str,
 ) -> anyhow::Result<Utf8PathBuf> {
-    let files = glob::glob(&format!("{directory}/{prefix}*{suffix}"))?
-        .into_iter()
-        .collect::<Result<Vec<_>, _>>()?;
+    let files =
+        glob::glob(&format!("{directory}/{prefix}*{suffix}"))?.collect::<Result<Vec<_>, _>>()?;
     match files.len() {
         0 => Err(anyhow::anyhow!("No file with prefix {prefix} found in {directory}")),
         1 => Ok(Utf8PathBuf::from_path_buf(files[0].clone()).unwrap()),
diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs
index 2af28077ed1..6fc96592a88 100644
--- a/src/tools/opt-dist/src/utils/mod.rs
+++ b/src/tools/opt-dist/src/utils/mod.rs
@@ -26,7 +26,7 @@ pub fn print_free_disk_space() -> anyhow::Result<()> {
     Ok(())
 }
 
-pub fn print_binary_sizes(env: &dyn Environment) -> anyhow::Result<()> {
+pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> {
     use std::fmt::Write;
 
     let root = env.build_artifacts().join("stage2");
@@ -48,7 +48,7 @@ pub fn print_binary_sizes(env: &dyn Environment) -> anyhow::Result<()> {
     Ok(())
 }
 
-pub fn clear_llvm_files(env: &dyn Environment) -> anyhow::Result<()> {
+pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> {
     // Bootstrap currently doesn't support rebuilding LLVM when PGO options
     // change (or any other llvm-related options); so just clear out the relevant
     // directories ourselves.
diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml
index 24745d1c806..c9ad7803951 100644
--- a/src/tools/rust-analyzer/.cargo/config.toml
+++ b/src/tools/rust-analyzer/.cargo/config.toml
@@ -8,4 +8,4 @@ lint = "clippy --all-targets -- -Aclippy::collapsible_if -Aclippy::needless_pass
 linker = "rust-lld"
 
 [env]
-CARGO_WORKSPACE_DIR = { value = "", relative = true }
\ No newline at end of file
+CARGO_WORKSPACE_DIR = { value = "", relative = true }
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 9f246098e76..fb7b4b07f98 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -86,12 +86,20 @@ jobs:
       - name: Test
         run: cargo test ${{ env.USE_SYSROOT_ABI }} -- --nocapture --quiet
 
+      - name: Switch to stable toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup component add --toolchain stable rust-src
+          rustup default stable
+
       - name: Run analysis-stats on rust-analyzer
         if: matrix.os == 'ubuntu-latest'
         run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats .
 
       - name: Run analysis-stats on rust std library
         if: matrix.os == 'ubuntu-latest'
+        env:
+          RUSTC_BOOTSTRAP: 1
         run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
 
   # Weird targets to catch non-portable code
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index 260e45ff517..bbeccd1621d 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -67,7 +67,7 @@ jobs:
   other_metrics:
     strategy:
       matrix:
-        names: [self, ripgrep, webrender, diesel]
+        names: [self, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18]
     runs-on: ubuntu-latest
     needs: [setup_cargo, build_metrics]
 
@@ -92,7 +92,7 @@ jobs:
           key: ${{ runner.os }}-target-${{ github.sha }}
 
       - name: Collect metrics
-        run: cargo xtask metrics ${{ matrix.names }}
+        run: cargo xtask metrics "${{ matrix.names }}"
 
       - name: Upload metrics
         uses: actions/upload-artifact@v3
@@ -118,25 +118,30 @@ jobs:
         with:
           name: self-${{ github.sha }}
 
-      - name: Download ripgrep metrics
+      - name: Download ripgrep-13.0.0 metrics
         uses: actions/download-artifact@v3
         with:
-          name: ripgrep-${{ github.sha }}
+          name: ripgrep-13.0.0-${{ github.sha }}
 
-      - name: Download webrender metrics
+      - name: Download webrender-2022 metrics
         uses: actions/download-artifact@v3
         with:
-          name: webrender-${{ github.sha }}
+          name: webrender-2022-${{ github.sha }}
 
-      - name: Download diesel metrics
+      - name: Download diesel-1.4.8 metrics
         uses: actions/download-artifact@v3
         with:
-          name: diesel-${{ github.sha }}
+          name: diesel-1.4.8-${{ github.sha }}
+
+      - name: Download hyper-0.14.18 metrics
+        uses: actions/download-artifact@v3
+        with:
+          name: hyper-0.14.18-${{ github.sha }}
 
       - name: Combine json
         run: |
           git clone --depth 1 https://$METRICS_TOKEN@github.com/rust-analyzer/metrics.git
-          jq -s ".[0] * .[1] * .[2] * .[3] * .[4]" build.json self.json ripgrep.json webrender.json diesel.json -c >> metrics/metrics.json
+          jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5]" build.json self.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json
           cd metrics
           git add .
           git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index 43681c785fd..b5dbe30c322 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -128,6 +128,8 @@ jobs:
 
       - name: Run analysis-stats on rust std library
         if: matrix.target == 'x86_64-unknown-linux-gnu'
+        env:
+          RUSTC_BOOTSTRAP: 1
         run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
 
       - name: Upload artifacts
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 49e96236c51..bd6554bf889 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -381,14 +381,14 @@ dependencies = [
 
 [[package]]
 name = "filetime"
-version = "0.2.19"
+version = "0.2.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
+checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
- "windows-sys 0.42.0",
+ "redox_syscall 0.3.5",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -541,6 +541,7 @@ dependencies = [
  "mbe",
  "once_cell",
  "profile",
+ "ra-ap-rustc_parse_format",
  "rustc-hash",
  "smallvec",
  "stdx",
@@ -854,7 +855,6 @@ version = "0.0.0"
 dependencies = [
  "dashmap",
  "hashbrown 0.12.3",
- "once_cell",
  "rustc-hash",
  "triomphe",
 ]
@@ -999,7 +999,7 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
 
 [[package]]
 name = "lsp-server"
-version = "0.7.3"
+version = "0.7.4"
 dependencies = [
  "crossbeam-channel",
  "log",
@@ -1010,9 +1010,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-server"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72417faa455bfb4e5bf14b157d8e2ca2ed74b4e89b8cf42ea2d864825ae5c8a2"
+checksum = "b52dccdf3302eefab8c8a1273047f0a3c3dca4b527c8458d00c09484c8371928"
 dependencies = [
  "crossbeam-channel",
  "log",
@@ -1149,20 +1149,21 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
 
 [[package]]
 name = "notify"
-version = "5.1.0"
+version = "6.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9"
+checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.3.2",
  "crossbeam-channel",
  "filetime",
  "fsevent-sys",
  "inotify",
  "kqueue",
  "libc",
+ "log",
  "mio",
  "walkdir",
- "windows-sys 0.42.0",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -1251,7 +1252,7 @@ dependencies = [
  "cfg-if",
  "instant",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "smallvec",
  "winapi",
 ]
@@ -1264,7 +1265,7 @@ checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "smallvec",
  "windows-sys 0.42.0",
 ]
@@ -1482,16 +1483,36 @@ dependencies = [
 ]
 
 [[package]]
+name = "ra-ap-rustc_index"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07b5fa61d34da18e148dc3a81f654488ea07f40938d8aefb17f8b64bb78c6120"
+dependencies = [
+ "arrayvec",
+ "smallvec",
+]
+
+[[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.1.0"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1c145702ed3f237918e512685185dc8a4d0edc3a5326c63d20361d8ba9b45b3"
+checksum = "f2e2f6b48422e4eed5218277ab7cc9733e60dd8f3167f4f36a49a0cafe4dc195"
 dependencies = [
- "unic-emoji-char",
+ "unicode-properties",
  "unicode-xid",
 ]
 
 [[package]]
+name = "ra-ap-rustc_parse_format"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3c7369ad01cc79f9e3513c9f6a6326f6b980100e4862a7ac71b9991c88108bb"
+dependencies = [
+ "ra-ap-rustc_index",
+ "ra-ap-rustc_lexer",
+]
+
+[[package]]
 name = "rayon"
 version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1523,6 +1544,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
 name = "rowan"
 version = "0.15.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1545,7 +1575,6 @@ dependencies = [
  "crossbeam-channel",
  "dissimilar",
  "expect-test",
- "filetime",
  "flycheck",
  "hir",
  "hir-def",
@@ -1555,7 +1584,7 @@ dependencies = [
  "ide-ssr",
  "itertools",
  "load-cargo",
- "lsp-server 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lsp-server 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "lsp-types",
  "mbe",
  "mimalloc",
@@ -2057,47 +2086,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
 
 [[package]]
-name = "unic-char-property"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
-dependencies = [
- "unic-char-range",
-]
-
-[[package]]
-name = "unic-char-range"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
-
-[[package]]
-name = "unic-common"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
-
-[[package]]
-name = "unic-emoji-char"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
-dependencies = [
- "unic-char-property",
- "unic-char-range",
- "unic-ucd-version",
-]
-
-[[package]]
-name = "unic-ucd-version"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
-dependencies = [
- "unic-common",
-]
-
-[[package]]
 name = "unicase"
 version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2128,6 +2116,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "unicode-properties"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
+
+[[package]]
 name = "unicode-segmentation"
 version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 5eb59d6db11..cab88fc18ce 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -86,7 +86,7 @@ proc-macro-test = { path = "./crates/proc-macro-test" }
 # In-tree crates that are published separately and follow semver. See lib/README.md
 line-index = { version = "0.1.0-pre.1" }
 la-arena = { version = "0.3.1" }
-lsp-server = { version = "0.7.3" }
+lsp-server = { version = "0.7.4" }
 
 # non-local crates
 smallvec = { version = "1.10.0", features = [
@@ -97,11 +97,15 @@ smallvec = { version = "1.10.0", features = [
 smol_str = "0.2.0"
 nohash-hasher = "0.2.0"
 text-size = "1.1.0"
-# See https://github.com/serde-rs/serde/issues/2538#issuecomment-1684517372 for why we pin serde
-serde = { version = "1.0.156, < 1.0.172", features = ["derive"] }
+serde = { version = "1.0.156", features = ["derive"] }
 serde_json = "1.0.96"
 triomphe = { version = "0.1.8", default-features = false, features = ["std"] }
 # can't upgrade due to dashmap depending on 0.12.3 currently
 hashbrown = { version = "0.12.3", features = ["inline-more"], default-features = false }
 
-rustc_lexer = { version = "0.1.0", package = "ra-ap-rustc_lexer" }
+rustc_lexer = { version = "0.10.0", package = "ra-ap-rustc_lexer" }
+rustc_parse_format = { version = "0.10.0", package = "ra-ap-rustc_parse_format", default-features = false }
+
+# Upstream broke this for us so we can't update it
+rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
+rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs
index aaac0fc3790..3f5ccb621c7 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs
@@ -179,8 +179,8 @@ impl ChangeFixture {
                     meta.edition,
                     Some(crate_name.clone().into()),
                     version,
-                    meta.cfg,
-                    Default::default(),
+                    meta.cfg.clone(),
+                    Some(meta.cfg),
                     meta.env,
                     false,
                     origin,
@@ -200,7 +200,7 @@ impl ChangeFixture {
             } else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
                 assert!(default_crate_root.is_none());
                 default_crate_root = Some(file_id);
-                default_cfg = meta.cfg;
+                default_cfg.extend(meta.cfg.into_iter());
                 default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
                 default_target_data_layout = meta.target_data_layout;
             }
@@ -220,8 +220,8 @@ impl ChangeFixture {
                 Edition::CURRENT,
                 Some(CrateName::new("test").unwrap().into()),
                 None,
-                default_cfg,
-                Default::default(),
+                default_cfg.clone(),
+                Some(default_cfg),
                 default_env,
                 false,
                 CrateOrigin::Local { repo: None, name: None },
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index 183b9b7d278..0aeb0b05052 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -86,6 +86,32 @@ impl CfgOptions {
     }
 }
 
+impl Extend<CfgAtom> for CfgOptions {
+    fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
+        iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
+    }
+}
+
+impl IntoIterator for CfgOptions {
+    type Item = <FxHashSet<CfgAtom> as IntoIterator>::Item;
+
+    type IntoIter = <FxHashSet<CfgAtom> as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        <FxHashSet<CfgAtom> as IntoIterator>::into_iter(self.enabled)
+    }
+}
+
+impl<'a> IntoIterator for &'a CfgOptions {
+    type Item = <&'a FxHashSet<CfgAtom> as IntoIterator>::Item;
+
+    type IntoIter = <&'a FxHashSet<CfgAtom> as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        <&FxHashSet<CfgAtom> as IntoIterator>::into_iter(&self.enabled)
+    }
+}
+
 #[derive(Default, Clone, Debug, PartialEq, Eq)]
 pub struct CfgDiff {
     // Invariants: No duplicates, no atom that's both in `enable` and `disable`.
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index fbb943ccb99..2de719af92c 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -5,7 +5,9 @@
 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 
 use std::{
+    ffi::OsString,
     fmt, io,
+    path::PathBuf,
     process::{ChildStderr, ChildStdout, Command, Stdio},
     time::Duration,
 };
@@ -168,7 +170,7 @@ struct FlycheckActor {
     /// doesn't provide a way to read sub-process output without blocking, so we
     /// have to wrap sub-processes output handling in a thread and pass messages
     /// back over a channel.
-    cargo_handle: Option<CargoHandle>,
+    command_handle: Option<CommandHandle>,
 }
 
 enum Event {
@@ -184,7 +186,7 @@ impl FlycheckActor {
         workspace_root: AbsPathBuf,
     ) -> FlycheckActor {
         tracing::info!(%id, ?workspace_root, "Spawning flycheck");
-        FlycheckActor { id, sender, config, root: workspace_root, cargo_handle: None }
+        FlycheckActor { id, sender, config, root: workspace_root, command_handle: None }
     }
 
     fn report_progress(&self, progress: Progress) {
@@ -192,7 +194,7 @@ impl FlycheckActor {
     }
 
     fn next_event(&self, inbox: &Receiver<StateChange>) -> Option<Event> {
-        let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
+        let check_chan = self.command_handle.as_ref().map(|cargo| &cargo.receiver);
         if let Ok(msg) = inbox.try_recv() {
             // give restarts a preference so check outputs don't block a restart or stop
             return Some(Event::RequestStateChange(msg));
@@ -221,21 +223,19 @@ impl FlycheckActor {
                     }
 
                     let command = self.check_command();
+                    let formatted_command = format!("{:?}", command);
+
                     tracing::debug!(?command, "will restart flycheck");
-                    match CargoHandle::spawn(command) {
-                        Ok(cargo_handle) => {
-                            tracing::debug!(
-                                command = ?self.check_command(),
-                                "did  restart flycheck"
-                            );
-                            self.cargo_handle = Some(cargo_handle);
+                    match CommandHandle::spawn(command) {
+                        Ok(command_handle) => {
+                            tracing::debug!(command = formatted_command, "did  restart flycheck");
+                            self.command_handle = Some(command_handle);
                             self.report_progress(Progress::DidStart);
                         }
                         Err(error) => {
                             self.report_progress(Progress::DidFailToRestart(format!(
-                                "Failed to run the following command: {:?} error={}",
-                                self.check_command(),
-                                error
+                                "Failed to run the following command: {} error={}",
+                                formatted_command, error
                             )));
                         }
                     }
@@ -244,12 +244,14 @@ impl FlycheckActor {
                     tracing::debug!(flycheck_id = self.id, "flycheck finished");
 
                     // Watcher finished
-                    let cargo_handle = self.cargo_handle.take().unwrap();
-                    let res = cargo_handle.join();
+                    let command_handle = self.command_handle.take().unwrap();
+                    let formatted_handle = format!("{:?}", command_handle);
+
+                    let res = command_handle.join();
                     if res.is_err() {
                         tracing::error!(
-                            "Flycheck failed to run the following command: {:?}",
-                            self.check_command()
+                            "Flycheck failed to run the following command: {}",
+                            formatted_handle
                         );
                     }
                     self.report_progress(Progress::DidFinish(res));
@@ -284,12 +286,12 @@ impl FlycheckActor {
     }
 
     fn cancel_check_process(&mut self) {
-        if let Some(cargo_handle) = self.cargo_handle.take() {
+        if let Some(command_handle) = self.command_handle.take() {
             tracing::debug!(
-                command = ?self.check_command(),
+                command = ?command_handle,
                 "did  cancel flycheck"
             );
-            cargo_handle.cancel();
+            command_handle.cancel();
             self.report_progress(Progress::DidCancel);
         }
     }
@@ -391,19 +393,36 @@ impl Drop for JodGroupChild {
 }
 
 /// A handle to a cargo process used for fly-checking.
-struct CargoHandle {
+struct CommandHandle {
     /// The handle to the actual cargo process. As we cannot cancel directly from with
     /// a read syscall dropping and therefore terminating the process is our best option.
     child: JodGroupChild,
     thread: stdx::thread::JoinHandle<io::Result<(bool, String)>>,
     receiver: Receiver<CargoMessage>,
+    program: OsString,
+    arguments: Vec<OsString>,
+    current_dir: Option<PathBuf>,
 }
 
-impl CargoHandle {
-    fn spawn(mut command: Command) -> std::io::Result<CargoHandle> {
+impl fmt::Debug for CommandHandle {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("CommandHandle")
+            .field("program", &self.program)
+            .field("arguments", &self.arguments)
+            .field("current_dir", &self.current_dir)
+            .finish()
+    }
+}
+
+impl CommandHandle {
+    fn spawn(mut command: Command) -> std::io::Result<CommandHandle> {
         command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
         let mut child = command.group_spawn().map(JodGroupChild)?;
 
+        let program = command.get_program().into();
+        let arguments = command.get_args().map(|arg| arg.into()).collect::<Vec<OsString>>();
+        let current_dir = command.get_current_dir().map(|arg| arg.to_path_buf());
+
         let stdout = child.0.inner().stdout.take().unwrap();
         let stderr = child.0.inner().stderr.take().unwrap();
 
@@ -413,7 +432,7 @@ impl CargoHandle {
             .name("CargoHandle".to_owned())
             .spawn(move || actor.run())
             .expect("failed to spawn thread");
-        Ok(CargoHandle { child, thread, receiver })
+        Ok(CommandHandle { program, arguments, current_dir, child, thread, receiver })
     }
 
     fn cancel(mut self) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index 30307deb79b..8cf61ee04d4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -31,8 +31,10 @@ smallvec.workspace = true
 hashbrown.workspace = true
 triomphe.workspace = true
 
-rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
-rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
+rustc_abi.workspace = true
+rustc_index.workspace = true
+rustc_parse_format.workspace = true
+
 
 # local deps
 stdx.workspace = true
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 a5db75a91eb..c6454eb9ea0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -5,7 +5,7 @@ pub mod builtin;
 #[cfg(test)]
 mod tests;
 
-use std::{hash::Hash, ops};
+use std::{hash::Hash, ops, slice::Iter as SliceIter};
 
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
@@ -14,12 +14,11 @@ use hir_expand::{
     attrs::{collect_attrs, Attr, AttrId, RawAttrs},
     HirFileId, InFile,
 };
-use itertools::Itertools;
 use la_arena::{ArenaMap, Idx, RawIdx};
 use mbe::DelimiterKind;
 use syntax::{
-    ast::{self, HasAttrs, IsString},
-    AstPtr, AstToken, SmolStr, TextRange, TextSize,
+    ast::{self, HasAttrs},
+    AstPtr, SmolStr,
 };
 use triomphe::Arc;
 
@@ -33,26 +32,6 @@ use crate::{
     LocalFieldId, Lookup, MacroId, VariantId,
 };
 
-/// Holds documentation
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Documentation(String);
-
-impl Documentation {
-    pub fn new(s: String) -> Self {
-        Documentation(s)
-    }
-
-    pub fn as_str(&self) -> &str {
-        &self.0
-    }
-}
-
-impl From<Documentation> for String {
-    fn from(Documentation(string): Documentation) -> Self {
-        string
-    }
-}
-
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct Attrs(RawAttrs);
 
@@ -221,33 +200,6 @@ impl Attrs {
         self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
     }
 
-    pub fn docs(&self) -> Option<Documentation> {
-        let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value());
-        let indent = doc_indent(self);
-        let mut buf = String::new();
-        for doc in docs {
-            // str::lines doesn't yield anything for the empty string
-            if !doc.is_empty() {
-                buf.extend(Itertools::intersperse(
-                    doc.lines().map(|line| {
-                        line.char_indices()
-                            .nth(indent)
-                            .map_or(line, |(offset, _)| &line[offset..])
-                            .trim_end()
-                    }),
-                    "\n",
-                ));
-            }
-            buf.push('\n');
-        }
-        buf.pop();
-        if buf.is_empty() {
-            None
-        } else {
-            Some(Documentation(buf))
-        }
-    }
-
     pub fn has_doc_hidden(&self) -> bool {
         self.by_key("doc").tt_values().any(|tt| {
             tt.delimiter.kind == DelimiterKind::Parenthesis &&
@@ -299,7 +251,6 @@ impl Attrs {
     }
 }
 
-use std::slice::Iter as SliceIter;
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub enum DocAtom {
     /// eg. `#[doc(hidden)]`
@@ -313,7 +264,6 @@ pub enum DocAtom {
 
 // Adapted from `CfgExpr` parsing code
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-// #[cfg_attr(test, derive(derive_arbitrary::Arbitrary))]
 pub enum DocExpr {
     Invalid,
     /// eg. `#[doc(hidden)]`, `#[doc(alias = "x")]`
@@ -574,62 +524,6 @@ impl AttrsWithOwner {
 
         AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
     }
-
-    pub fn docs_with_rangemap(
-        &self,
-        db: &dyn DefDatabase,
-    ) -> Option<(Documentation, DocsRangeMap)> {
-        let docs =
-            self.by_key("doc").attrs().filter_map(|attr| attr.string_value().map(|s| (s, attr.id)));
-        let indent = doc_indent(self);
-        let mut buf = String::new();
-        let mut mapping = Vec::new();
-        for (doc, idx) in docs {
-            if !doc.is_empty() {
-                let mut base_offset = 0;
-                for raw_line in doc.split('\n') {
-                    let line = raw_line.trim_end();
-                    let line_len = line.len();
-                    let (offset, line) = match line.char_indices().nth(indent) {
-                        Some((offset, _)) => (offset, &line[offset..]),
-                        None => (0, line),
-                    };
-                    let buf_offset = buf.len();
-                    buf.push_str(line);
-                    mapping.push((
-                        TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
-                        idx,
-                        TextRange::at(
-                            (base_offset + offset).try_into().ok()?,
-                            line_len.try_into().ok()?,
-                        ),
-                    ));
-                    buf.push('\n');
-                    base_offset += raw_line.len() + 1;
-                }
-            } else {
-                buf.push('\n');
-            }
-        }
-        buf.pop();
-        if buf.is_empty() {
-            None
-        } else {
-            Some((Documentation(buf), DocsRangeMap { mapping, source_map: self.source_map(db) }))
-        }
-    }
-}
-
-fn doc_indent(attrs: &Attrs) -> usize {
-    attrs
-        .by_key("doc")
-        .attrs()
-        .filter_map(|attr| attr.string_value())
-        .flat_map(|s| s.lines())
-        .filter(|line| !line.chars().all(|c| c.is_whitespace()))
-        .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
-        .min()
-        .unwrap_or(0)
 }
 
 #[derive(Debug)]
@@ -673,7 +567,7 @@ impl AttrSourceMap {
         self.source_of_id(attr.id)
     }
 
-    fn source_of_id(&self, id: AttrId) -> InFile<&Either<ast::Attr, ast::Comment>> {
+    pub fn source_of_id(&self, id: AttrId) -> InFile<&Either<ast::Attr, ast::Comment>> {
         let ast_idx = id.ast_index();
         let file_id = match self.mod_def_site_file_id {
             Some((file_id, def_site_cut)) if def_site_cut <= ast_idx => file_id,
@@ -687,69 +581,6 @@ impl AttrSourceMap {
     }
 }
 
-/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
-#[derive(Debug)]
-pub struct DocsRangeMap {
-    source_map: AttrSourceMap,
-    // (docstring-line-range, attr_index, attr-string-range)
-    // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
-    // the original (untrimmed) syntax doc line
-    mapping: Vec<(TextRange, AttrId, TextRange)>,
-}
-
-impl DocsRangeMap {
-    /// Maps a [`TextRange`] relative to the documentation string back to its AST range
-    pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
-        let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
-        let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
-        if !line_docs_range.contains_range(range) {
-            return None;
-        }
-
-        let relative_range = range - line_docs_range.start();
-
-        let InFile { file_id, value: source } = self.source_map.source_of_id(idx);
-        match source {
-            Either::Left(attr) => {
-                let string = get_doc_string_in_attr(attr)?;
-                let text_range = string.open_quote_text_range()?;
-                let range = TextRange::at(
-                    text_range.end() + original_line_src_range.start() + relative_range.start(),
-                    string.syntax().text_range().len().min(range.len()),
-                );
-                Some(InFile { file_id, value: range })
-            }
-            Either::Right(comment) => {
-                let text_range = comment.syntax().text_range();
-                let range = TextRange::at(
-                    text_range.start()
-                        + TextSize::try_from(comment.prefix().len()).ok()?
-                        + original_line_src_range.start()
-                        + relative_range.start(),
-                    text_range.len().min(range.len()),
-                );
-                Some(InFile { file_id, value: range })
-            }
-        }
-    }
-}
-
-fn get_doc_string_in_attr(it: &ast::Attr) -> Option<ast::String> {
-    match it.expr() {
-        // #[doc = lit]
-        Some(ast::Expr::Literal(lit)) => match lit.kind() {
-            ast::LiteralKind::String(it) => Some(it),
-            _ => None,
-        },
-        // #[cfg_attr(..., doc = "", ...)]
-        None => {
-            // FIXME: See highlight injection for what to do here
-            None
-        }
-        _ => None,
-    }
-}
-
 #[derive(Debug, Clone, Copy)]
 pub struct AttrQuery<'attr> {
     attrs: &'attr Attrs,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
index 9bd0c30b105..152f05b2c3b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
@@ -8,7 +8,8 @@
 //! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
 //! ease updating.
 
-use once_cell::sync::OnceCell;
+use std::sync::OnceLock;
+
 use rustc_hash::FxHashMap;
 
 /// Ignored attribute namespaces used by tools.
@@ -29,7 +30,7 @@ pub struct AttributeTemplate {
 }
 
 pub fn find_builtin_attr_idx(name: &str) -> Option<usize> {
-    static BUILTIN_LOOKUP_TABLE: OnceCell<FxHashMap<&'static str, usize>> = OnceCell::new();
+    static BUILTIN_LOOKUP_TABLE: OnceLock<FxHashMap<&'static str, usize>> = OnceLock::new();
     BUILTIN_LOOKUP_TABLE
         .get_or_init(|| {
             INERT_ATTRIBUTES.iter().map(|attr| attr.name).enumerate().map(|(a, b)| (b, a)).collect()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index f8d492d0e52..c0baf6011f7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -65,6 +65,8 @@ pub type LabelSource = InFile<LabelPtr>;
 
 pub type FieldPtr = AstPtr<ast::RecordExprField>;
 pub type FieldSource = InFile<FieldPtr>;
+pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
+pub type PatFieldSource = InFile<PatFieldPtr>;
 
 /// An item body together with the mapping from syntax nodes to HIR expression
 /// IDs. This is needed to go from e.g. a position in a file to the HIR
@@ -90,8 +92,8 @@ pub struct BodySourceMap {
 
     /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
     /// Instead, we use id of expression (`92`) to identify the field.
-    field_map: FxHashMap<FieldSource, ExprId>,
     field_map_back: FxHashMap<ExprId, FieldSource>,
+    pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
 
     expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
 
@@ -164,9 +166,10 @@ impl Body {
         };
         let module = def.module(db);
         let expander = Expander::new(db, file_id, module);
-        let (mut body, source_map) =
+        let (mut body, mut source_map) =
             Body::new(db, def, expander, params, body, module.krate, is_async_fn);
         body.shrink_to_fit();
+        source_map.shrink_to_fit();
 
         (Arc::new(body), Arc::new(source_map))
     }
@@ -375,9 +378,8 @@ impl BodySourceMap {
         self.field_map_back[&expr].clone()
     }
 
-    pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
-        let src = node.map(AstPtr::new);
-        self.field_map.get(&src).cloned()
+    pub fn pat_field_syntax(&self, pat: PatId) -> PatFieldSource {
+        self.pat_field_map_back[&pat].clone()
     }
 
     pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
@@ -389,4 +391,29 @@ impl BodySourceMap {
     pub fn diagnostics(&self) -> &[BodyDiagnostic] {
         &self.diagnostics
     }
+
+    fn shrink_to_fit(&mut self) {
+        let Self {
+            expr_map,
+            expr_map_back,
+            pat_map,
+            pat_map_back,
+            label_map,
+            label_map_back,
+            field_map_back,
+            pat_field_map_back,
+            expansions,
+            diagnostics,
+        } = self;
+        expr_map.shrink_to_fit();
+        expr_map_back.shrink_to_fit();
+        pat_map.shrink_to_fit();
+        pat_map_back.shrink_to_fit();
+        label_map.shrink_to_fit();
+        label_map_back.shrink_to_fit();
+        field_map_back.shrink_to_fit();
+        pat_field_map_back.shrink_to_fit();
+        expansions.shrink_to_fit();
+        diagnostics.shrink_to_fit();
+    }
 }
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 7071fcb9394..cc02df80a8f 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
@@ -25,13 +25,20 @@ use triomphe::Arc;
 
 use crate::{
     body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
+    builtin_type::BuiltinUint,
     data::adt::StructKind,
     db::DefDatabase,
     expander::Expander,
     hir::{
-        dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
-        ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
-        Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+        dummy_expr_id,
+        format_args::{
+            self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
+            FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
+            FormatPlaceholder, FormatSign, FormatTrait,
+        },
+        Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
+        Expr, ExprId, InlineAsm, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
+        OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
     },
     item_scope::BuiltinShadowMode,
     lang_item::LangItem,
@@ -42,6 +49,8 @@ use crate::{
     AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
 };
 
+type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
+
 pub(super) fn lower(
     db: &dyn DefDatabase,
     owner: DefWithBodyId,
@@ -437,7 +446,6 @@ impl ExprCollector<'_> {
                                 None => self.missing_expr(),
                             };
                             let src = self.expander.to_source(AstPtr::new(&field));
-                            self.source_map.field_map.insert(src.clone(), expr);
                             self.source_map.field_map_back.insert(expr, src);
                             Some(RecordLitField { name, expr })
                         })
@@ -579,11 +587,6 @@ impl ExprCollector<'_> {
                     syntax_ptr,
                 )
             }
-            ast::Expr::BoxExpr(e) => {
-                let expr = self.collect_expr_opt(e.expr());
-                self.alloc_expr(Expr::Box { expr }, syntax_ptr)
-            }
-
             ast::Expr::ArrayExpr(e) => {
                 let kind = e.kind();
 
@@ -653,6 +656,16 @@ impl ExprCollector<'_> {
                 }
             }
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
+            ast::Expr::AsmExpr(e) => {
+                let e = self.collect_expr_opt(e.expr());
+                self.alloc_expr(Expr::InlineAsm(InlineAsm { e }), syntax_ptr)
+            }
+            ast::Expr::OffsetOfExpr(e) => {
+                let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+                let fields = e.fields().map(|it| it.as_name()).collect();
+                self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
+            }
+            ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),
         })
     }
 
@@ -663,6 +676,7 @@ impl ExprCollector<'_> {
         let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
         let prev_binding_owner = self.current_binding_owner.take();
         self.current_binding_owner = Some(result_expr_id);
+
         (result_expr_id, prev_binding_owner)
     }
 
@@ -744,7 +758,27 @@ impl ExprCollector<'_> {
     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());
+
+        // Labels can also be used in the condition expression, like this:
+        // ```
+        // fn main() {
+        //     let mut optional = Some(0);
+        //     'my_label: while let Some(a) = match optional {
+        //         None => break 'my_label,
+        //         Some(val) => Some(val),
+        //     } {
+        //         println!("{}", a);
+        //         optional = None;
+        //     }
+        // }
+        // ```
+        let condition = match label {
+            Some(label) => {
+                self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition()))
+            }
+            None => 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(
@@ -1295,23 +1329,21 @@ impl ExprCollector<'_> {
             ast::Pat::RecordPat(p) => {
                 let path =
                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
-                let args = p
-                    .record_pat_field_list()
-                    .expect("every struct should have a field list")
+                let record_pat_field_list =
+                    &p.record_pat_field_list().expect("every struct should have a field list");
+                let args = record_pat_field_list
                     .fields()
                     .filter_map(|f| {
                         let ast_pat = f.pat()?;
                         let pat = self.collect_pat(ast_pat, binding_list);
                         let name = f.field_name()?.as_name();
+                        let src = self.expander.to_source(AstPtr::new(&f));
+                        self.source_map.pat_field_map_back.insert(pat, src);
                         Some(RecordFieldPat { name, pat })
                     })
                     .collect();
 
-                let ellipsis = p
-                    .record_pat_field_list()
-                    .expect("every struct should have a field list")
-                    .rest_pat()
-                    .is_some();
+                let ellipsis = record_pat_field_list.rest_pat().is_some();
 
                 Pat::Record { path, args, ellipsis }
             }
@@ -1531,6 +1563,401 @@ impl ExprCollector<'_> {
         }
     }
     // endregion: labels
+
+    // region: format
+    fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
+        let m = match expr {
+            ast::Expr::MacroExpr(m) => m,
+            ast::Expr::Literal(l) => {
+                return match l.kind() {
+                    ast::LiteralKind::String(s) => Some((s, true)),
+                    _ => None,
+                }
+            }
+            _ => return None,
+        };
+        let e = m.macro_call()?;
+        let macro_ptr = AstPtr::new(&e);
+        let (exp, _) = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
+            expansion.and_then(|it| this.expand_macros_to_string(it))
+        })?;
+        Some((exp, false))
+    }
+
+    fn collect_format_args(
+        &mut self,
+        f: ast::FormatArgsExpr,
+        syntax_ptr: AstPtr<ast::Expr>,
+    ) -> ExprId {
+        let mut args = FormatArgumentsCollector::new();
+        f.args().for_each(|arg| {
+            args.add(FormatArgument {
+                kind: match arg.name() {
+                    Some(name) => FormatArgumentKind::Named(name.as_name()),
+                    None => FormatArgumentKind::Normal,
+                },
+                expr: self.collect_expr_opt(arg.expr()),
+            });
+        });
+        let template = f.template();
+        let fmt_snippet = template.as_ref().map(ToString::to_string);
+        let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
+            Some((s, is_direct_literal)) => {
+                format_args::parse(&s, fmt_snippet, args, is_direct_literal, |name| {
+                    self.alloc_expr_desugared(Expr::Path(Path::from(name)))
+                })
+            }
+            None => FormatArgs { template: Default::default(), arguments: args.finish() },
+        };
+
+        // Create a list of all _unique_ (argument, format trait) combinations.
+        // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+        let mut argmap = FxIndexSet::default();
+        for piece in fmt.template.iter() {
+            let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+            if let Ok(index) = placeholder.argument.index {
+                argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
+            }
+        }
+
+        let lit_pieces =
+            fmt.template
+                .iter()
+                .enumerate()
+                .filter_map(|(i, piece)| {
+                    match piece {
+                        FormatArgsPiece::Literal(s) => Some(
+                            self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))),
+                        ),
+                        &FormatArgsPiece::Placeholder(_) => {
+                            // Inject empty string before placeholders when not already preceded by a literal piece.
+                            if i == 0
+                                || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
+                            {
+                                Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
+                                    "".into(),
+                                ))))
+                            } else {
+                                None
+                            }
+                        }
+                    }
+                })
+                .collect();
+        let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+            elements: lit_pieces,
+            is_assignee_expr: false,
+        }));
+        let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
+            expr: lit_pieces,
+            rawness: Rawness::Ref,
+            mutability: Mutability::Shared,
+        });
+        let format_options = {
+            // Generate:
+            //     &[format_spec_0, format_spec_1, format_spec_2]
+            let elements = fmt
+                .template
+                .iter()
+                .filter_map(|piece| {
+                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+                    Some(self.make_format_spec(placeholder, &mut argmap))
+                })
+                .collect();
+            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                elements,
+                is_assignee_expr: false,
+            }));
+            self.alloc_expr_desugared(Expr::Ref {
+                expr: array,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            })
+        };
+        let arguments = &*fmt.arguments.arguments;
+
+        let args = if arguments.is_empty() {
+            let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                elements: Box::default(),
+                is_assignee_expr: false,
+            }));
+            self.alloc_expr_desugared(Expr::Ref {
+                expr,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            })
+        } else {
+            // Generate:
+            //     &match (&arg0, &arg1, &…) {
+            //         args => [
+            //             <core::fmt::Argument>::new_display(args.0),
+            //             <core::fmt::Argument>::new_lower_hex(args.1),
+            //             <core::fmt::Argument>::new_debug(args.0),
+            //             …
+            //         ]
+            //     }
+            let args = argmap
+                .iter()
+                .map(|&(arg_index, ty)| {
+                    let arg = self.alloc_expr_desugared(Expr::Ref {
+                        expr: arguments[arg_index].expr,
+                        rawness: Rawness::Ref,
+                        mutability: Mutability::Shared,
+                    });
+                    self.make_argument(arg, ty)
+                })
+                .collect();
+            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+                elements: args,
+                is_assignee_expr: false,
+            }));
+            self.alloc_expr_desugared(Expr::Ref {
+                expr: array,
+                rawness: Rawness::Ref,
+                mutability: Mutability::Shared,
+            })
+        };
+
+        // Generate:
+        //     <core::fmt::Arguments>::new_v1_formatted(
+        //         lit_pieces,
+        //         args,
+        //         format_options,
+        //         unsafe { ::core::fmt::UnsafeArg::new() }
+        //     )
+
+        let Some(new_v1_formatted) =
+            LangItem::FormatArguments.ty_rel_path(self.db, self.krate, name![new_v1_formatted])
+        else {
+            return self.missing_expr();
+        };
+        let Some(unsafe_arg_new) =
+            LangItem::FormatUnsafeArg.ty_rel_path(self.db, self.krate, name![new])
+        else {
+            return self.missing_expr();
+        };
+        let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
+
+        let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
+        let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call {
+            callee: unsafe_arg_new,
+            args: Box::default(),
+            is_assignee_expr: false,
+        });
+        let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
+            id: None,
+            statements: Box::default(),
+            tail: Some(unsafe_arg_new),
+        });
+
+        self.alloc_expr(
+            Expr::Call {
+                callee: new_v1_formatted,
+                args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
+                is_assignee_expr: false,
+            },
+            syntax_ptr,
+        )
+    }
+
+    /// Generate a hir expression for a format_args placeholder specification.
+    ///
+    /// Generates
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Placeholder::new(
+    ///         …usize, // position
+    ///         '…', // fill
+    ///         <core::fmt::rt::Alignment>::…, // alignment
+    ///         …u32, // flags
+    ///         <core::fmt::rt::Count::…>, // width
+    ///         <core::fmt::rt::Count::…>, // precision
+    ///     )
+    /// ```
+    fn make_format_spec(
+        &mut self,
+        placeholder: &FormatPlaceholder,
+        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+    ) -> ExprId {
+        let position = match placeholder.argument.index {
+            Ok(arg_index) => {
+                let (i, _) =
+                    argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+                self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                    i as u128,
+                    Some(BuiltinUint::Usize),
+                )))
+            }
+            Err(_) => self.missing_expr(),
+        };
+        let &FormatOptions {
+            ref width,
+            ref precision,
+            alignment,
+            fill,
+            sign,
+            alternate,
+            zero_pad,
+            debug_hex,
+        } = &placeholder.format_options;
+        let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
+
+        let align = {
+            let align = LangItem::FormatAlignment.ty_rel_path(
+                self.db,
+                self.krate,
+                match alignment {
+                    Some(FormatAlignment::Left) => name![Left],
+                    Some(FormatAlignment::Right) => name![Right],
+                    Some(FormatAlignment::Center) => name![Center],
+                    None => name![Unknown],
+                },
+            );
+            match align {
+                Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
+                None => self.missing_expr(),
+            }
+        };
+        // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+        let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+            | ((sign == Some(FormatSign::Minus)) as u32) << 1
+            | (alternate as u32) << 2
+            | (zero_pad as u32) << 3
+            | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
+            | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
+        let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+            flags as u128,
+            Some(BuiltinUint::U32),
+        )));
+        let precision = self.make_count(&precision, argmap);
+        let width = self.make_count(&width, argmap);
+
+        let format_placeholder_new = {
+            let format_placeholder_new =
+                LangItem::FormatPlaceholder.ty_rel_path(self.db, self.krate, name![new]);
+            match format_placeholder_new {
+                Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
+                None => self.missing_expr(),
+            }
+        };
+
+        self.alloc_expr_desugared(Expr::Call {
+            callee: format_placeholder_new,
+            args: Box::new([position, fill, align, flags, precision, width]),
+            is_assignee_expr: false,
+        })
+    }
+
+    /// Generate a hir expression for a format_args Count.
+    ///
+    /// Generates:
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Count>::Is(…)
+    /// ```
+    ///
+    /// or
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Count>::Param(…)
+    /// ```
+    ///
+    /// or
+    ///
+    /// ```text
+    ///     <core::fmt::rt::Count>::Implied
+    /// ```
+    fn make_count(
+        &mut self,
+        count: &Option<FormatCount>,
+        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+    ) -> ExprId {
+        match count {
+            Some(FormatCount::Literal(n)) => {
+                match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
+                    Some(count_is) => {
+                        let count_is = self.alloc_expr_desugared(Expr::Path(count_is));
+                        let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                            *n as u128,
+                            Some(BuiltinUint::Usize),
+                        )));
+                        self.alloc_expr_desugared(Expr::Call {
+                            callee: count_is,
+                            args: Box::new([args]),
+                            is_assignee_expr: false,
+                        })
+                    }
+                    None => self.missing_expr(),
+                }
+            }
+            Some(FormatCount::Argument(arg)) => {
+                if let Ok(arg_index) = arg.index {
+                    let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+
+                    match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) {
+                        Some(count_param) => {
+                            let count_param = self.alloc_expr_desugared(Expr::Path(count_param));
+                            let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                                i as u128,
+                                Some(BuiltinUint::Usize),
+                            )));
+                            self.alloc_expr_desugared(Expr::Call {
+                                callee: count_param,
+                                args: Box::new([args]),
+                                is_assignee_expr: false,
+                            })
+                        }
+                        None => self.missing_expr(),
+                    }
+                } else {
+                    self.missing_expr()
+                }
+            }
+            None => match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Implied]) {
+                Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
+                None => self.missing_expr(),
+            },
+        }
+    }
+
+    /// Generate a hir expression representing an argument to a format_args invocation.
+    ///
+    /// Generates:
+    ///
+    /// ```text
+    ///     <core::fmt::Argument>::new_…(arg)
+    /// ```
+    fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
+        use ArgumentType::*;
+        use FormatTrait::*;
+        match LangItem::FormatArgument.ty_rel_path(
+            self.db,
+            self.krate,
+            match ty {
+                Format(Display) => name![new_display],
+                Format(Debug) => name![new_debug],
+                Format(LowerExp) => name![new_lower_exp],
+                Format(UpperExp) => name![new_upper_exp],
+                Format(Octal) => name![new_octal],
+                Format(Pointer) => name![new_pointer],
+                Format(Binary) => name![new_binary],
+                Format(LowerHex) => name![new_lower_hex],
+                Format(UpperHex) => name![new_upper_hex],
+                Usize => name![from_usize],
+            },
+        ) {
+            Some(new_fn) => {
+                let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn));
+                self.alloc_expr_desugared(Expr::Call {
+                    callee: new_fn,
+                    args: Box::new([arg]),
+                    is_assignee_expr: false,
+                })
+            }
+            None => self.missing_expr(),
+        }
+    }
+    // endregion: format
 }
 
 fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
@@ -1606,3 +2033,9 @@ fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
     (|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
         .map_or(false, |it| it.kind() == syntax::T![,])
 }
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+    Format(FormatTrait),
+    Usize,
+}
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 5d71abe37cc..fad4d7a4da6 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
@@ -2,7 +2,7 @@
 
 use std::fmt::{self, Write};
 
-use hir_expand::db::ExpandDatabase;
+use itertools::Itertools;
 use syntax::ast::HasName;
 
 use crate::{
@@ -51,8 +51,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
         }
     };
 
-    let mut p =
-        Printer { db: db.upcast(), body, buf: header, indent_level: 0, needs_indent: false };
+    let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
     if let DefWithBodyId::FunctionId(it) = owner {
         p.buf.push('(');
         body.params.iter().zip(&db.function_data(it).params).for_each(|(&param, ty)| {
@@ -76,8 +75,7 @@ pub(super) fn print_expr_hir(
     _owner: DefWithBodyId,
     expr: ExprId,
 ) -> String {
-    let mut p =
-        Printer { db: db.upcast(), body, buf: String::new(), indent_level: 0, needs_indent: false };
+    let mut p = Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false };
     p.print_expr(expr);
     p.buf
 }
@@ -98,7 +96,7 @@ macro_rules! wln {
 }
 
 struct Printer<'a> {
-    db: &'a dyn ExpandDatabase,
+    db: &'a dyn DefDatabase,
     body: &'a Body,
     buf: String,
     indent_level: usize,
@@ -142,9 +140,14 @@ impl Printer<'_> {
     }
 
     fn newline(&mut self) {
-        match self.buf.chars().rev().find(|ch| *ch != ' ') {
-            Some('\n') | None => {}
-            _ => writeln!(self).unwrap(),
+        match self.buf.chars().rev().find_position(|ch| *ch != ' ') {
+            Some((_, '\n')) | None => {}
+            Some((idx, _)) => {
+                if idx != 0 {
+                    self.buf.drain(self.buf.len() - idx..);
+                }
+                writeln!(self).unwrap()
+            }
         }
     }
 
@@ -154,6 +157,19 @@ impl Printer<'_> {
         match expr {
             Expr::Missing => w!(self, "�"),
             Expr::Underscore => w!(self, "_"),
+            Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
+            Expr::OffsetOf(offset_of) => {
+                w!(self, "builtin#offset_of(");
+                self.print_type_ref(&offset_of.container);
+                w!(
+                    self,
+                    ", {})",
+                    offset_of
+                        .fields
+                        .iter()
+                        .format_with(".", |field, f| f(&field.display(self.db.upcast())))
+                );
+            }
             Expr::Path(path) => self.print_path(path),
             Expr::If { condition, then_branch, else_branch } => {
                 w!(self, "if ");
@@ -173,7 +189,7 @@ impl Printer<'_> {
             }
             Expr::Loop { body, label } => {
                 if let Some(lbl) = label {
-                    w!(self, "{}: ", self.body[*lbl].name.display(self.db));
+                    w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast()));
                 }
                 w!(self, "loop ");
                 self.print_expr(*body);
@@ -193,7 +209,7 @@ impl Printer<'_> {
             }
             Expr::MethodCall { receiver, method_name, args, generic_args } => {
                 self.print_expr(*receiver);
-                w!(self, ".{}", method_name.display(self.db));
+                w!(self, ".{}", method_name.display(self.db.upcast()));
                 if let Some(args) = generic_args {
                     w!(self, "::<");
                     print_generic_args(self.db, args, self).unwrap();
@@ -231,13 +247,13 @@ impl Printer<'_> {
             Expr::Continue { label } => {
                 w!(self, "continue");
                 if let Some(lbl) = label {
-                    w!(self, " {}", self.body[*lbl].name.display(self.db));
+                    w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
                 }
             }
             Expr::Break { expr, label } => {
                 w!(self, "break");
                 if let Some(lbl) = label {
-                    w!(self, " {}", self.body[*lbl].name.display(self.db));
+                    w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
                 }
                 if let Some(expr) = expr {
                     self.whitespace();
@@ -276,7 +292,7 @@ impl Printer<'_> {
                 w!(self, "{{");
                 self.indented(|p| {
                     for field in &**fields {
-                        w!(p, "{}: ", field.name.display(self.db));
+                        w!(p, "{}: ", field.name.display(self.db.upcast()));
                         p.print_expr(field.expr);
                         wln!(p, ",");
                     }
@@ -293,7 +309,7 @@ impl Printer<'_> {
             }
             Expr::Field { expr, name } => {
                 self.print_expr(*expr);
-                w!(self, ".{}", name.display(self.db));
+                w!(self, ".{}", name.display(self.db.upcast()));
             }
             Expr::Await { expr } => {
                 self.print_expr(*expr);
@@ -431,7 +447,8 @@ impl Printer<'_> {
             }
             Expr::Literal(lit) => self.print_literal(lit),
             Expr::Block { id: _, statements, tail, label } => {
-                let label = label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db)));
+                let label =
+                    label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db.upcast())));
                 self.print_block(label.as_deref(), statements, tail);
             }
             Expr::Unsafe { id: _, statements, tail } => {
@@ -507,7 +524,7 @@ impl Printer<'_> {
                 w!(self, " {{");
                 self.indented(|p| {
                     for arg in args.iter() {
-                        w!(p, "{}: ", arg.name.display(self.db));
+                        w!(p, "{}: ", arg.name.display(self.db.upcast()));
                         p.print_pat(arg.pat);
                         wln!(p, ",");
                     }
@@ -666,6 +683,6 @@ impl Printer<'_> {
             BindingAnnotation::Ref => "ref ",
             BindingAnnotation::RefMut => "ref mut ",
         };
-        w!(self, "{}{}", mode, name.display(self.db));
+        w!(self, "{}{}", mode, name.display(self.db.upcast()));
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index d5582011645..1658757d2b6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -1,13 +1,13 @@
 mod block;
 
 use base_db::{fixture::WithFixture, SourceDatabase};
-use expect_test::Expect;
+use expect_test::{expect, Expect};
 
 use crate::{test_db::TestDB, ModuleDefId};
 
 use super::*;
 
-fn lower(ra_fixture: &str) -> Arc<Body> {
+fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
     let db = TestDB::with_files(ra_fixture);
 
     let krate = db.crate_graph().iter().next().unwrap();
@@ -21,8 +21,10 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
             }
         }
     }
+    let fn_def = fn_def.unwrap().into();
 
-    db.body(fn_def.unwrap().into())
+    let body = db.body(fn_def);
+    (db, body, fn_def)
 }
 
 fn def_map_at(ra_fixture: &str) -> String {
@@ -138,3 +140,84 @@ mod m {
 "#,
     );
 }
+
+#[test]
+fn desugar_builtin_format_args() {
+    // Regression test for a path resolution bug introduced with inner item handling.
+    let (db, body, def) = lower(
+        r#"
+//- minicore: fmt
+fn main() {
+    let are = "are";
+    let count = 10;
+    builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
+}
+"#,
+    );
+
+    expect![[r#"
+        fn main() {
+            let are = "are";
+            let count = 10;
+            builtin#lang(Arguments::new_v1_formatted)(
+                &[
+                    "\"hello ", " ", " friends, we ", " ", "", "\"",
+                ],
+                &[
+                    builtin#lang(Argument::new_display)(
+                        &count,
+                    ), builtin#lang(Argument::new_display)(
+                        &"fancy",
+                    ), builtin#lang(Argument::new_debug)(
+                        &are,
+                    ), builtin#lang(Argument::new_display)(
+                        &"!",
+                    ),
+                ],
+                &[
+                    builtin#lang(Placeholder::new)(
+                        0usize,
+                        ' ',
+                        builtin#lang(Alignment::Unknown),
+                        8u32,
+                        builtin#lang(Count::Implied),
+                        builtin#lang(Count::Is)(
+                            2usize,
+                        ),
+                    ), builtin#lang(Placeholder::new)(
+                        1usize,
+                        ' ',
+                        builtin#lang(Alignment::Unknown),
+                        0u32,
+                        builtin#lang(Count::Implied),
+                        builtin#lang(Count::Implied),
+                    ), builtin#lang(Placeholder::new)(
+                        2usize,
+                        ' ',
+                        builtin#lang(Alignment::Unknown),
+                        0u32,
+                        builtin#lang(Count::Implied),
+                        builtin#lang(Count::Implied),
+                    ), builtin#lang(Placeholder::new)(
+                        1usize,
+                        ' ',
+                        builtin#lang(Alignment::Unknown),
+                        0u32,
+                        builtin#lang(Count::Implied),
+                        builtin#lang(Count::Implied),
+                    ), builtin#lang(Placeholder::new)(
+                        3usize,
+                        ' ',
+                        builtin#lang(Alignment::Unknown),
+                        0u32,
+                        builtin#lang(Count::Implied),
+                        builtin#lang(Count::Implied),
+                    ),
+                ],
+                unsafe {
+                    builtin#lang(UnsafeArg::new)()
+                },
+            );
+        }"#]]
+    .assert_eq(&body.pretty_print(&db, def))
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index c8df3f3f96a..224f7328f8c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -447,6 +447,7 @@ impl VariantData {
         }
     }
 
+    // FIXME: Linear lookup
     pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
         self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index b60e7909105..b9c5ff72792 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -37,6 +37,20 @@ pub fn find_path_prefixed(
     find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
 }
 
+#[derive(Copy, Clone, Debug)]
+enum Stability {
+    Unstable,
+    Stable,
+}
+use Stability::*;
+
+fn zip_stability(a: Stability, b: Stability) -> Stability {
+    match (a, b) {
+        (Stable, Stable) => Stable,
+        _ => Unstable,
+    }
+}
+
 const MAX_PATH_LEN: usize = 15;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -95,7 +109,8 @@ fn find_path_inner(
             MAX_PATH_LEN,
             prefixed,
             prefer_no_std || db.crate_supports_no_std(crate_root.krate),
-        );
+        )
+        .map(|(item, _)| item);
     }
 
     // - if the item is already in scope, return the name under which it is
@@ -143,6 +158,7 @@ fn find_path_inner(
         prefer_no_std || db.crate_supports_no_std(crate_root.krate),
         scope_name,
     )
+    .map(|(item, _)| item)
 }
 
 fn find_path_for_module(
@@ -155,7 +171,7 @@ fn find_path_for_module(
     max_len: usize,
     prefixed: Option<PrefixKind>,
     prefer_no_std: bool,
-) -> Option<ModPath> {
+) -> Option<(ModPath, Stability)> {
     if max_len == 0 {
         return None;
     }
@@ -165,19 +181,19 @@ fn find_path_for_module(
     let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
     if prefixed.is_none() {
         if let Some(scope_name) = scope_name {
-            return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
+            return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable));
         }
     }
 
     // - if the item is the crate root, return `crate`
     if module_id == crate_root {
-        return Some(ModPath::from_segments(PathKind::Crate, None));
+        return Some((ModPath::from_segments(PathKind::Crate, None), Stable));
     }
 
     // - if relative paths are fine, check if we are searching for a parent
     if prefixed.filter(PrefixKind::is_absolute).is_none() {
         if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
-            return modpath;
+            return modpath.zip(Some(Stable));
         }
     }
 
@@ -201,14 +217,14 @@ fn find_path_for_module(
             } else {
                 PathKind::Plain
             };
-            return Some(ModPath::from_segments(kind, Some(name)));
+            return Some((ModPath::from_segments(kind, Some(name)), Stable));
         }
     }
 
     if let value @ Some(_) =
         find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
     {
-        return value;
+        return value.zip(Some(Stable));
     }
     calculate_best_path(
         db,
@@ -301,11 +317,19 @@ fn calculate_best_path(
     mut prefixed: Option<PrefixKind>,
     prefer_no_std: bool,
     scope_name: Option<Name>,
-) -> Option<ModPath> {
+) -> Option<(ModPath, Stability)> {
     if max_len <= 1 {
         return None;
     }
     let mut best_path = None;
+    let update_best_path =
+        |best_path: &mut Option<_>, new_path: (ModPath, Stability)| match best_path {
+            Some((old_path, old_stability)) => {
+                *old_path = new_path.0;
+                *old_stability = zip_stability(*old_stability, new_path.1);
+            }
+            None => *best_path = Some(new_path),
+        };
     // Recursive case:
     // - otherwise, look for modules containing (reexporting) it and import it from one of those
     if item.krate(db) == Some(from.krate) {
@@ -328,14 +352,14 @@ fn calculate_best_path(
                 prefixed,
                 prefer_no_std,
             ) {
-                path.push_segment(name);
+                path.0.push_segment(name);
 
-                let new_path = match best_path {
+                let new_path = match best_path.take() {
                     Some(best_path) => select_best_path(best_path, path, prefer_no_std),
                     None => path,
                 };
-                best_path_len = new_path.len();
-                best_path = Some(new_path);
+                best_path_len = new_path.0.len();
+                update_best_path(&mut best_path, new_path);
             }
         }
     } else {
@@ -354,7 +378,7 @@ fn calculate_best_path(
 
                 // Determine best path for containing module and append last segment from `info`.
                 // FIXME: we should guide this to look up the path locally, or from the same crate again?
-                let mut path = find_path_for_module(
+                let (mut path, path_stability) = find_path_for_module(
                     db,
                     def_map,
                     visited_modules,
@@ -367,16 +391,19 @@ fn calculate_best_path(
                 )?;
                 cov_mark::hit!(partially_imported);
                 path.push_segment(info.name.clone());
-                Some(path)
+                Some((
+                    path,
+                    zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }),
+                ))
             })
         });
 
         for path in extern_paths {
-            let new_path = match best_path {
+            let new_path = match best_path.take() {
                 Some(best_path) => select_best_path(best_path, path, prefer_no_std),
                 None => path,
             };
-            best_path = Some(new_path);
+            update_best_path(&mut best_path, new_path);
         }
     }
     if let Some(module) = item.module(db) {
@@ -387,15 +414,24 @@ fn calculate_best_path(
     }
     match prefixed.map(PrefixKind::prefix) {
         Some(prefix) => best_path.or_else(|| {
-            scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
+            scope_name.map(|scope_name| (ModPath::from_segments(prefix, Some(scope_name)), Stable))
         }),
         None => best_path,
     }
 }
 
-fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
+fn select_best_path(
+    old_path: (ModPath, Stability),
+    new_path: (ModPath, Stability),
+    prefer_no_std: bool,
+) -> (ModPath, Stability) {
+    match (old_path.1, new_path.1) {
+        (Stable, Unstable) => return old_path,
+        (Unstable, Stable) => return new_path,
+        _ => {}
+    }
     const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
-    match (old_path.segments().first(), new_path.segments().first()) {
+    match (old_path.0.segments().first(), new_path.0.segments().first()) {
         (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
             let rank = match prefer_no_std {
                 false => |name: &Name| match name {
@@ -416,7 +452,7 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
             match nrank.cmp(&orank) {
                 Ordering::Less => old_path,
                 Ordering::Equal => {
-                    if new_path.len() < old_path.len() {
+                    if new_path.0.len() < old_path.0.len() {
                         new_path
                     } else {
                         old_path
@@ -426,7 +462,7 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
             }
         }
         _ => {
-            if new_path.len() < old_path.len() {
+            if new_path.0.len() < old_path.0.len() {
                 new_path
             } else {
                 old_path
@@ -1360,4 +1396,29 @@ pub mod ops {
             "std::ops::Deref",
         );
     }
+
+    #[test]
+    fn respect_unstable_modules() {
+        check_found_path(
+            r#"
+//- /main.rs crate:main deps:std,core
+#![no_std]
+extern crate std;
+$0
+//- /longer.rs crate:std deps:core
+pub mod error {
+    pub use core::error::Error;
+}
+//- /core.rs crate:core
+pub mod error {
+    #![unstable(feature = "error_in_core", issue = "103765")]
+    pub trait Error {}
+}
+"#,
+            "std::error::Error",
+            "std::error::Error",
+            "std::error::Error",
+            "std::error::Error",
+        );
+    }
 }
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 6591c92ac62..591ee77c70a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -13,6 +13,7 @@
 //! See also a neighboring `body` module.
 
 pub mod type_ref;
+pub mod format_args;
 
 use std::fmt;
 
@@ -117,7 +118,6 @@ impl From<ast::LiteralKind> for Literal {
     fn from(ast_lit_kind: ast::LiteralKind) -> Self {
         use ast::LiteralKind;
         match ast_lit_kind {
-            // FIXME: these should have actual values filled in, but unsure on perf impact
             LiteralKind::IntNumber(lit) => {
                 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
                     Literal::Float(
@@ -281,6 +281,19 @@ pub enum Expr {
     Array(Array),
     Literal(Literal),
     Underscore,
+    OffsetOf(OffsetOf),
+    InlineAsm(InlineAsm),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct OffsetOf {
+    pub container: Interned<TypeRef>,
+    pub fields: Box<[Name]>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InlineAsm {
+    pub e: ExprId,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -341,7 +354,8 @@ impl Expr {
     pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
         match self {
             Expr::Missing => {}
-            Expr::Path(_) => {}
+            Expr::Path(_) | Expr::OffsetOf(_) => {}
+            Expr::InlineAsm(it) => f(it.e),
             Expr::If { condition, then_branch, else_branch } => {
                 f(*condition);
                 f(*then_branch);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
new file mode 100644
index 00000000000..75025a984fc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
@@ -0,0 +1,502 @@
+//! Parses `format_args` input.
+use std::mem;
+
+use hir_expand::name::Name;
+use rustc_parse_format as parse;
+use syntax::{
+    ast::{self, IsString},
+    AstToken, SmolStr, TextRange,
+};
+
+use crate::hir::ExprId;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgs {
+    pub template: Box<[FormatArgsPiece]>,
+    pub arguments: FormatArguments,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArguments {
+    pub arguments: Box<[FormatArgument]>,
+    pub num_unnamed_args: usize,
+    pub num_explicit_args: usize,
+    pub names: Box<[(Name, usize)]>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum FormatArgsPiece {
+    Literal(Box<str>),
+    Placeholder(FormatPlaceholder),
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct FormatPlaceholder {
+    /// Index into [`FormatArgs::arguments`].
+    pub argument: FormatArgPosition,
+    /// The span inside the format string for the full `{…}` placeholder.
+    pub span: Option<TextRange>,
+    /// `{}`, `{:?}`, or `{:x}`, etc.
+    pub format_trait: FormatTrait,
+    /// `{}` or `{:.5}` or `{:-^20}`, etc.
+    pub format_options: FormatOptions,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgPosition {
+    /// Which argument this position refers to (Ok),
+    /// or would've referred to if it existed (Err).
+    pub index: Result<usize, usize>,
+    /// What kind of position this is. See [`FormatArgPositionKind`].
+    pub kind: FormatArgPositionKind,
+    /// The span of the name or number.
+    pub span: Option<TextRange>,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub enum FormatArgPositionKind {
+    /// `{}` or `{:.*}`
+    Implicit,
+    /// `{1}` or `{:1$}` or `{:.1$}`
+    Number,
+    /// `{a}` or `{:a$}` or `{:.a$}`
+    Named,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum FormatTrait {
+    /// `{}`
+    Display,
+    /// `{:?}`
+    Debug,
+    /// `{:e}`
+    LowerExp,
+    /// `{:E}`
+    UpperExp,
+    /// `{:o}`
+    Octal,
+    /// `{:p}`
+    Pointer,
+    /// `{:b}`
+    Binary,
+    /// `{:x}`
+    LowerHex,
+    /// `{:X}`
+    UpperHex,
+}
+
+#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
+pub struct FormatOptions {
+    /// The width. E.g. `{:5}` or `{:width$}`.
+    pub width: Option<FormatCount>,
+    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
+    pub precision: Option<FormatCount>,
+    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
+    pub alignment: Option<FormatAlignment>,
+    /// The fill character. E.g. the `.` in `{:.>10}`.
+    pub fill: Option<char>,
+    /// The `+` or `-` flag.
+    pub sign: Option<FormatSign>,
+    /// The `#` flag.
+    pub alternate: bool,
+    /// The `0` flag. E.g. the `0` in `{:02x}`.
+    pub zero_pad: bool,
+    /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
+    pub debug_hex: Option<FormatDebugHex>,
+}
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatSign {
+    /// The `+` flag.
+    Plus,
+    /// The `-` flag.
+    Minus,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatDebugHex {
+    /// The `x` flag in `{:x?}`.
+    Lower,
+    /// The `X` flag in `{:X?}`.
+    Upper,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatAlignment {
+    /// `{:<}`
+    Left,
+    /// `{:>}`
+    Right,
+    /// `{:^}`
+    Center,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatCount {
+    /// `{:5}` or `{:.5}`
+    Literal(usize),
+    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
+    Argument(FormatArgPosition),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgument {
+    pub kind: FormatArgumentKind,
+    pub expr: ExprId,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum FormatArgumentKind {
+    /// `format_args(…, arg)`
+    Normal,
+    /// `format_args(…, arg = 1)`
+    Named(Name),
+    /// `format_args("… {arg} …")`
+    Captured(Name),
+}
+
+// Only used in parse_args and report_invalid_references,
+// to indicate how a referred argument was used.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum PositionUsedAs {
+    Placeholder(Option<TextRange>),
+    Precision,
+    Width,
+}
+use PositionUsedAs::*;
+
+pub(crate) fn parse(
+    s: &ast::String,
+    fmt_snippet: Option<String>,
+    mut args: FormatArgumentsCollector,
+    is_direct_literal: bool,
+    mut synth: impl FnMut(Name) -> ExprId,
+) -> FormatArgs {
+    let text = s.text();
+    let str_style = match s.quote_offsets() {
+        Some(offsets) => {
+            let raw = u32::from(offsets.quotes.0.len()) - 1;
+            (raw != 0).then_some(raw as usize)
+        }
+        None => None,
+    };
+    let mut parser =
+        parse::Parser::new(text, str_style, fmt_snippet, false, parse::ParseMode::Format);
+
+    let mut pieces = Vec::new();
+    while let Some(piece) = parser.next() {
+        if !parser.errors.is_empty() {
+            break;
+        } else {
+            pieces.push(piece);
+        }
+    }
+    let is_source_literal = parser.is_source_literal;
+    if !parser.errors.is_empty() {
+        // FIXME: Diagnose
+        return FormatArgs { template: Default::default(), arguments: args.finish() };
+    }
+
+    let to_span = |inner_span: parse::InnerSpan| {
+        is_source_literal.then(|| {
+            TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
+        })
+    };
+
+    let mut used = vec![false; args.explicit_args().len()];
+    let mut invalid_refs = Vec::new();
+    let mut numeric_refences_to_named_arg = Vec::new();
+
+    enum ArgRef<'a> {
+        Index(usize),
+        Name(&'a str, Option<TextRange>),
+    }
+    let mut lookup_arg = |arg: ArgRef<'_>,
+                          span: Option<TextRange>,
+                          used_as: PositionUsedAs,
+                          kind: FormatArgPositionKind|
+     -> FormatArgPosition {
+        let index = match arg {
+            ArgRef::Index(index) => {
+                if let Some(arg) = args.by_index(index) {
+                    used[index] = true;
+                    if arg.kind.ident().is_some() {
+                        // This was a named argument, but it was used as a positional argument.
+                        numeric_refences_to_named_arg.push((index, span, used_as));
+                    }
+                    Ok(index)
+                } else {
+                    // Doesn't exist as an explicit argument.
+                    invalid_refs.push((index, span, used_as, kind));
+                    Err(index)
+                }
+            }
+            ArgRef::Name(name, _span) => {
+                let name = Name::new_text_dont_use(SmolStr::new(name));
+                if let Some((index, _)) = args.by_name(&name) {
+                    // Name found in `args`, so we resolve it to its index.
+                    if index < args.explicit_args().len() {
+                        // Mark it as used, if it was an explicit argument.
+                        used[index] = true;
+                    }
+                    Ok(index)
+                } else {
+                    // Name not found in `args`, so we add it as an implicitly captured argument.
+                    if !is_direct_literal {
+                        // For the moment capturing variables from format strings expanded from macros is
+                        // disabled (see RFC #2795)
+                        // FIXME: Diagnose
+                    }
+                    Ok(args.add(FormatArgument {
+                        kind: FormatArgumentKind::Captured(name.clone()),
+                        // FIXME: This is problematic, we might want to synthesize a dummy
+                        // expression proper and/or desugar these.
+                        expr: synth(name),
+                    }))
+                }
+            }
+        };
+        FormatArgPosition { index, kind, span }
+    };
+
+    let mut template = Vec::new();
+    let mut unfinished_literal = String::new();
+    let mut placeholder_index = 0;
+
+    for piece in pieces {
+        match piece {
+            parse::Piece::String(s) => {
+                unfinished_literal.push_str(s);
+            }
+            parse::Piece::NextArgument(arg) => {
+                let parse::Argument { position, position_span, format } = *arg;
+                if !unfinished_literal.is_empty() {
+                    template.push(FormatArgsPiece::Literal(
+                        mem::take(&mut unfinished_literal).into_boxed_str(),
+                    ));
+                }
+
+                let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s));
+                placeholder_index += 1;
+
+                let position_span = to_span(position_span);
+                let argument = match position {
+                    parse::ArgumentImplicitlyIs(i) => lookup_arg(
+                        ArgRef::Index(i),
+                        position_span,
+                        Placeholder(span),
+                        FormatArgPositionKind::Implicit,
+                    ),
+                    parse::ArgumentIs(i) => lookup_arg(
+                        ArgRef::Index(i),
+                        position_span,
+                        Placeholder(span),
+                        FormatArgPositionKind::Number,
+                    ),
+                    parse::ArgumentNamed(name) => lookup_arg(
+                        ArgRef::Name(name, position_span),
+                        position_span,
+                        Placeholder(span),
+                        FormatArgPositionKind::Named,
+                    ),
+                };
+
+                let alignment = match format.align {
+                    parse::AlignUnknown => None,
+                    parse::AlignLeft => Some(FormatAlignment::Left),
+                    parse::AlignRight => Some(FormatAlignment::Right),
+                    parse::AlignCenter => Some(FormatAlignment::Center),
+                };
+
+                let format_trait = match format.ty {
+                    "" => FormatTrait::Display,
+                    "?" => FormatTrait::Debug,
+                    "e" => FormatTrait::LowerExp,
+                    "E" => FormatTrait::UpperExp,
+                    "o" => FormatTrait::Octal,
+                    "p" => FormatTrait::Pointer,
+                    "b" => FormatTrait::Binary,
+                    "x" => FormatTrait::LowerHex,
+                    "X" => FormatTrait::UpperHex,
+                    _ => {
+                        // FIXME: Diagnose
+                        FormatTrait::Display
+                    }
+                };
+
+                let precision_span = format.precision_span.and_then(to_span);
+                let precision = match format.precision {
+                    parse::CountIs(n) => Some(FormatCount::Literal(n)),
+                    parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+                        ArgRef::Name(name, to_span(name_span)),
+                        precision_span,
+                        Precision,
+                        FormatArgPositionKind::Named,
+                    ))),
+                    parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+                        ArgRef::Index(i),
+                        precision_span,
+                        Precision,
+                        FormatArgPositionKind::Number,
+                    ))),
+                    parse::CountIsStar(i) => Some(FormatCount::Argument(lookup_arg(
+                        ArgRef::Index(i),
+                        precision_span,
+                        Precision,
+                        FormatArgPositionKind::Implicit,
+                    ))),
+                    parse::CountImplied => None,
+                };
+
+                let width_span = format.width_span.and_then(to_span);
+                let width = match format.width {
+                    parse::CountIs(n) => Some(FormatCount::Literal(n)),
+                    parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+                        ArgRef::Name(name, to_span(name_span)),
+                        width_span,
+                        Width,
+                        FormatArgPositionKind::Named,
+                    ))),
+                    parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+                        ArgRef::Index(i),
+                        width_span,
+                        Width,
+                        FormatArgPositionKind::Number,
+                    ))),
+                    parse::CountIsStar(_) => unreachable!(),
+                    parse::CountImplied => None,
+                };
+
+                template.push(FormatArgsPiece::Placeholder(FormatPlaceholder {
+                    argument,
+                    span,
+                    format_trait,
+                    format_options: FormatOptions {
+                        fill: format.fill,
+                        alignment,
+                        sign: format.sign.map(|s| match s {
+                            parse::Sign::Plus => FormatSign::Plus,
+                            parse::Sign::Minus => FormatSign::Minus,
+                        }),
+                        alternate: format.alternate,
+                        zero_pad: format.zero_pad,
+                        debug_hex: format.debug_hex.map(|s| match s {
+                            parse::DebugHex::Lower => FormatDebugHex::Lower,
+                            parse::DebugHex::Upper => FormatDebugHex::Upper,
+                        }),
+                        precision,
+                        width,
+                    },
+                }));
+            }
+        }
+    }
+
+    if !unfinished_literal.is_empty() {
+        template.push(FormatArgsPiece::Literal(unfinished_literal.into_boxed_str()));
+    }
+
+    if !invalid_refs.is_empty() {
+        // FIXME: Diagnose
+    }
+
+    let unused = used
+        .iter()
+        .enumerate()
+        .filter(|&(_, used)| !used)
+        .map(|(i, _)| {
+            let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_));
+            (args.explicit_args()[i].expr, named)
+        })
+        .collect::<Vec<_>>();
+
+    if !unused.is_empty() {
+        // FIXME: Diagnose
+    }
+
+    FormatArgs { template: template.into_boxed_slice(), arguments: args.finish() }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgumentsCollector {
+    arguments: Vec<FormatArgument>,
+    num_unnamed_args: usize,
+    num_explicit_args: usize,
+    names: Vec<(Name, usize)>,
+}
+
+impl FormatArgumentsCollector {
+    pub(crate) fn finish(self) -> FormatArguments {
+        FormatArguments {
+            arguments: self.arguments.into_boxed_slice(),
+            num_unnamed_args: self.num_unnamed_args,
+            num_explicit_args: self.num_explicit_args,
+            names: self.names.into_boxed_slice(),
+        }
+    }
+
+    pub fn new() -> Self {
+        Self { arguments: vec![], names: vec![], num_unnamed_args: 0, num_explicit_args: 0 }
+    }
+
+    pub fn add(&mut self, arg: FormatArgument) -> usize {
+        let index = self.arguments.len();
+        if let Some(name) = arg.kind.ident() {
+            self.names.push((name.clone(), index));
+        } else if self.names.is_empty() {
+            // Only count the unnamed args before the first named arg.
+            // (Any later ones are errors.)
+            self.num_unnamed_args += 1;
+        }
+        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
+            // This is an explicit argument.
+            // Make sure that all arguments so far are explicit.
+            assert_eq!(
+                self.num_explicit_args,
+                self.arguments.len(),
+                "captured arguments must be added last"
+            );
+            self.num_explicit_args += 1;
+        }
+        self.arguments.push(arg);
+        index
+    }
+
+    pub fn by_name(&self, name: &Name) -> Option<(usize, &FormatArgument)> {
+        let &(_, i) = self.names.iter().find(|(n, _)| n == name)?;
+        Some((i, &self.arguments[i]))
+    }
+
+    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
+        (i < self.num_explicit_args).then(|| &self.arguments[i])
+    }
+
+    pub fn unnamed_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_unnamed_args]
+    }
+
+    pub fn named_args(&self) -> &[FormatArgument] {
+        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
+    }
+
+    pub fn explicit_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_explicit_args]
+    }
+
+    pub fn all_args(&self) -> &[FormatArgument] {
+        &self.arguments[..]
+    }
+
+    pub fn all_args_mut(&mut self) -> &mut Vec<FormatArgument> {
+        &mut self.arguments
+    }
+}
+
+impl FormatArgumentKind {
+    pub fn ident(&self) -> Option<&Name> {
+        match self {
+            Self::Normal => None,
+            Self::Named(id) => Some(id),
+            Self::Captured(id) => Some(id),
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 6038caaf8fc..44b7f1b4f63 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -32,6 +32,8 @@ pub struct ImportInfo {
     pub is_trait_assoc_item: bool,
     /// Whether this item is annotated with `#[doc(hidden)]`.
     pub is_doc_hidden: bool,
+    /// Whether this item is annotated with `#[unstable(..)]`.
+    pub is_unstable: bool,
 }
 
 /// A map from publicly exported items to its name.
@@ -113,7 +115,6 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
 
         for (name, per_ns) in visible_items {
             for (item, import) in per_ns.iter_items() {
-                // FIXME: Not yet used, but will be once we handle doc(hidden) import sources
                 let attr_id = if let Some(import) = import {
                     match import {
                         ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
@@ -125,28 +126,59 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
                         ItemInNs::Macros(id) => Some(id.into()),
                     }
                 };
-                let is_doc_hidden =
-                    attr_id.map_or(false, |attr_id| db.attrs(attr_id).has_doc_hidden());
+                let status @ (is_doc_hidden, is_unstable) =
+                    attr_id.map_or((false, false), |attr_id| {
+                        let attrs = db.attrs(attr_id);
+                        (attrs.has_doc_hidden(), attrs.is_unstable())
+                    });
 
                 let import_info = ImportInfo {
                     name: name.clone(),
                     container: module,
                     is_trait_assoc_item: false,
                     is_doc_hidden,
+                    is_unstable,
                 };
 
                 match depth_map.entry(item) {
-                    Entry::Vacant(entry) => _ = entry.insert((depth, is_doc_hidden)),
+                    Entry::Vacant(entry) => _ = entry.insert((depth, status)),
                     Entry::Occupied(mut entry) => {
-                        let &(occ_depth, occ_is_doc_hidden) = entry.get();
-                        // Prefer the one that is not doc(hidden),
-                        // Otherwise, if both have the same doc(hidden)-ness and the new path is shorter, prefer that one.
-                        let overwrite_entry = occ_is_doc_hidden && !is_doc_hidden
-                            || occ_is_doc_hidden == is_doc_hidden && depth < occ_depth;
-                        if !overwrite_entry {
+                        let &(occ_depth, (occ_is_doc_hidden, occ_is_unstable)) = entry.get();
+                        (depth, occ_depth);
+                        let overwrite = match (
+                            is_doc_hidden,
+                            occ_is_doc_hidden,
+                            is_unstable,
+                            occ_is_unstable,
+                        ) {
+                            // no change of hiddeness or unstableness
+                            (true, true, true, true)
+                            | (true, true, false, false)
+                            | (false, false, true, true)
+                            | (false, false, false, false) => depth < occ_depth,
+
+                            // either less hidden or less unstable, accept
+                            (true, true, false, true)
+                            | (false, true, true, true)
+                            | (false, true, false, true)
+                            | (false, true, false, false)
+                            | (false, false, false, true) => true,
+                            // more hidden or unstable, discard
+                            (true, true, true, false)
+                            | (true, false, true, true)
+                            | (true, false, true, false)
+                            | (true, false, false, false)
+                            | (false, false, true, false) => false,
+
+                            // exchanges doc(hidden) for unstable (and vice-versa),
+                            (true, false, false, true) | (false, true, true, false) => {
+                                depth < occ_depth
+                            }
+                        };
+                        if !overwrite {
                             continue;
                         }
-                        entry.insert((depth, is_doc_hidden));
+                        entry.insert((depth, status));
                     }
                 }
 
@@ -171,7 +203,7 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
             }
         }
     }
-
+    map.shrink_to_fit();
     map
 }
 
@@ -200,11 +232,13 @@ fn collect_trait_assoc_items(
             ItemInNs::Values(module_def_id)
         };
 
+        let attrs = &db.attrs(item.into());
         let assoc_item_info = ImportInfo {
             container: trait_import_info.container,
             name: assoc_item_name.clone(),
             is_trait_assoc_item: true,
-            is_doc_hidden: db.attrs(item.into()).has_doc_hidden(),
+            is_doc_hidden: attrs.has_doc_hidden(),
+            is_unstable: attrs.is_unstable(),
         };
         map.insert(assoc_item, assoc_item_info);
     }
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 3e1922750b9..4c812b62a46 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
@@ -177,7 +177,7 @@ impl ItemTree {
     }
 
     pub fn pretty_print(&self, db: &dyn DefDatabase) -> String {
-        pretty::print_item_tree(db.upcast(), self)
+        pretty::print_item_tree(db, self)
     }
 
     fn data(&self) -> &ItemTreeData {
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 4b852dd613e..417bd37c8a9 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
@@ -2,8 +2,6 @@
 
 use std::fmt::{self, Write};
 
-use hir_expand::db::ExpandDatabase;
-
 use crate::{
     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
     pretty::{print_path, print_type_bounds, print_type_ref},
@@ -12,7 +10,7 @@ use crate::{
 
 use super::*;
 
-pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> String {
+pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String {
     let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
 
     if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
@@ -45,7 +43,7 @@ macro_rules! wln {
 }
 
 struct Printer<'a> {
-    db: &'a dyn ExpandDatabase,
+    db: &'a dyn DefDatabase,
     tree: &'a ItemTree,
     buf: String,
     indent_level: usize,
@@ -91,7 +89,7 @@ impl Printer<'_> {
                 self,
                 "#{}[{}{}]{}",
                 inner,
-                attr.path.display(self.db),
+                attr.path.display(self.db.upcast()),
                 attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
                 separated_by,
             );
@@ -106,7 +104,7 @@ impl Printer<'_> {
 
     fn print_visibility(&mut self, vis: RawVisibilityId) {
         match &self.tree[vis] {
-            RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db)),
+            RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db.upcast())),
             RawVisibility::Public => w!(self, "pub "),
         };
     }
@@ -121,7 +119,7 @@ impl Printer<'_> {
                         let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
                         this.print_attrs_of(field, "\n");
                         this.print_visibility(*visibility);
-                        w!(this, "{}: ", name.display(self.db));
+                        w!(this, "{}: ", name.display(self.db.upcast()));
                         this.print_type_ref(type_ref);
                         wln!(this, ",");
                     }
@@ -135,7 +133,7 @@ impl Printer<'_> {
                         let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
                         this.print_attrs_of(field, "\n");
                         this.print_visibility(*visibility);
-                        w!(this, "{}: ", name.display(self.db));
+                        w!(this, "{}: ", name.display(self.db.upcast()));
                         this.print_type_ref(type_ref);
                         wln!(this, ",");
                     }
@@ -168,20 +166,20 @@ impl Printer<'_> {
     fn print_use_tree(&mut self, use_tree: &UseTree) {
         match &use_tree.kind {
             UseTreeKind::Single { path, alias } => {
-                w!(self, "{}", path.display(self.db));
+                w!(self, "{}", path.display(self.db.upcast()));
                 if let Some(alias) = alias {
                     w!(self, " as {}", alias);
                 }
             }
             UseTreeKind::Glob { path } => {
                 if let Some(path) = path {
-                    w!(self, "{}::", path.display(self.db));
+                    w!(self, "{}::", path.display(self.db.upcast()));
                 }
                 w!(self, "*");
             }
             UseTreeKind::Prefixed { prefix, list } => {
                 if let Some(prefix) = prefix {
-                    w!(self, "{}::", prefix.display(self.db));
+                    w!(self, "{}::", prefix.display(self.db.upcast()));
                 }
                 w!(self, "{{");
                 for (i, tree) in list.iter().enumerate() {
@@ -209,7 +207,7 @@ impl Printer<'_> {
             ModItem::ExternCrate(it) => {
                 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "extern crate {}", name.display(self.db));
+                w!(self, "extern crate {}", name.display(self.db.upcast()));
                 if let Some(alias) = alias {
                     w!(self, " as {}", alias);
                 }
@@ -256,7 +254,7 @@ impl Printer<'_> {
                 if let Some(abi) = abi {
                     w!(self, "extern \"{}\" ", abi);
                 }
-                w!(self, "fn {}", name.display(self.db));
+                w!(self, "fn {}", name.display(self.db.upcast()));
                 self.print_generic_params(explicit_generic_params);
                 w!(self, "(");
                 if !params.is_empty() {
@@ -290,7 +288,7 @@ impl Printer<'_> {
             ModItem::Struct(it) => {
                 let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "struct {}", name.display(self.db));
+                w!(self, "struct {}", name.display(self.db.upcast()));
                 self.print_generic_params(generic_params);
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
@@ -302,7 +300,7 @@ impl Printer<'_> {
             ModItem::Union(it) => {
                 let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "union {}", name.display(self.db));
+                w!(self, "union {}", name.display(self.db.upcast()));
                 self.print_generic_params(generic_params);
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
@@ -314,14 +312,14 @@ impl Printer<'_> {
             ModItem::Enum(it) => {
                 let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "enum {}", name.display(self.db));
+                w!(self, "enum {}", name.display(self.db.upcast()));
                 self.print_generic_params(generic_params);
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for variant in variants.clone() {
                         let Variant { name, fields, ast_id: _ } = &this.tree[variant];
                         this.print_attrs_of(variant, "\n");
-                        w!(this, "{}", name.display(self.db));
+                        w!(this, "{}", name.display(self.db.upcast()));
                         this.print_fields(fields);
                         wln!(this, ",");
                     }
@@ -333,7 +331,7 @@ impl Printer<'_> {
                 self.print_visibility(*visibility);
                 w!(self, "const ");
                 match name {
-                    Some(name) => w!(self, "{}", name.display(self.db)),
+                    Some(name) => w!(self, "{}", name.display(self.db.upcast())),
                     None => w!(self, "_"),
                 }
                 w!(self, ": ");
@@ -347,7 +345,7 @@ impl Printer<'_> {
                 if *mutable {
                     w!(self, "mut ");
                 }
-                w!(self, "{}: ", name.display(self.db));
+                w!(self, "{}: ", name.display(self.db.upcast()));
                 self.print_type_ref(type_ref);
                 w!(self, " = _;");
                 wln!(self);
@@ -369,7 +367,7 @@ impl Printer<'_> {
                 if *is_auto {
                     w!(self, "auto ");
                 }
-                w!(self, "trait {}", name.display(self.db));
+                w!(self, "trait {}", name.display(self.db.upcast()));
                 self.print_generic_params(generic_params);
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
@@ -382,7 +380,7 @@ impl Printer<'_> {
             ModItem::TraitAlias(it) => {
                 let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "trait {}", name.display(self.db));
+                w!(self, "trait {}", name.display(self.db.upcast()));
                 self.print_generic_params(generic_params);
                 w!(self, " = ");
                 self.print_where_clause(generic_params);
@@ -415,7 +413,7 @@ impl Printer<'_> {
                 let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
                     &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "type {}", name.display(self.db));
+                w!(self, "type {}", name.display(self.db.upcast()));
                 self.print_generic_params(generic_params);
                 if !bounds.is_empty() {
                     w!(self, ": ");
@@ -432,7 +430,7 @@ impl Printer<'_> {
             ModItem::Mod(it) => {
                 let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "mod {}", name.display(self.db));
+                w!(self, "mod {}", name.display(self.db.upcast()));
                 match kind {
                     ModKind::Inline { items } => {
                         w!(self, " {{");
@@ -450,16 +448,16 @@ impl Printer<'_> {
             }
             ModItem::MacroCall(it) => {
                 let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it];
-                wln!(self, "{}!(...);", path.display(self.db));
+                wln!(self, "{}!(...);", path.display(self.db.upcast()));
             }
             ModItem::MacroRules(it) => {
                 let MacroRules { name, ast_id: _ } = &self.tree[it];
-                wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db));
+                wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db.upcast()));
             }
             ModItem::MacroDef(it) => {
                 let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
-                wln!(self, "macro {} {{ ... }}", name.display(self.db));
+                wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast()));
             }
         }
 
@@ -491,7 +489,7 @@ impl Printer<'_> {
             }
             first = false;
             self.print_attrs_of(idx, " ");
-            w!(self, "{}", lt.name.display(self.db));
+            w!(self, "{}", lt.name.display(self.db.upcast()));
         }
         for (idx, x) in params.type_or_consts.iter() {
             if !first {
@@ -501,11 +499,11 @@ impl Printer<'_> {
             self.print_attrs_of(idx, " ");
             match x {
                 TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
-                    Some(name) => w!(self, "{}", name.display(self.db)),
+                    Some(name) => w!(self, "{}", name.display(self.db.upcast())),
                     None => w!(self, "_anon_{}", idx.into_raw()),
                 },
                 TypeOrConstParamData::ConstParamData(konst) => {
-                    w!(self, "const {}: ", konst.name.display(self.db));
+                    w!(self, "const {}: ", konst.name.display(self.db.upcast()));
                     self.print_type_ref(&konst.ty);
                 }
             }
@@ -540,8 +538,8 @@ impl Printer<'_> {
                         wln!(
                             this,
                             "{}: {},",
-                            target.name.display(self.db),
-                            bound.name.display(self.db)
+                            target.name.display(self.db.upcast()),
+                            bound.name.display(self.db.upcast())
                         );
                         continue;
                     }
@@ -551,7 +549,7 @@ impl Printer<'_> {
                             if i != 0 {
                                 w!(this, ", ");
                             }
-                            w!(this, "{}", lt.display(self.db));
+                            w!(this, "{}", lt.display(self.db.upcast()));
                         }
                         w!(this, "> ");
                         (target, bound)
@@ -562,7 +560,7 @@ impl Printer<'_> {
                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
                     WherePredicateTypeTarget::TypeOrConstParam(id) => {
                         match &params.type_or_consts[*id].name() {
-                            Some(name) => w!(this, "{}", name.display(self.db)),
+                            Some(name) => w!(this, "{}", name.display(self.db.upcast())),
                             None => w!(this, "_anon_{}", id.into_raw()),
                         }
                     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 627479bb7c1..1ae6bd4c919 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -2,6 +2,7 @@
 //!
 //! This attribute to tell the compiler about semi built-in std library
 //! features, such as Fn family of traits.
+use hir_expand::name::Name;
 use rustc_hash::FxHashMap;
 use syntax::SmolStr;
 use triomphe::Arc;
@@ -238,7 +239,17 @@ impl LangItem {
 
     pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
         let t = db.lang_item(start_crate, *self)?;
-        Some(Path::LangItem(t))
+        Some(Path::LangItem(t, None))
+    }
+
+    pub fn ty_rel_path(
+        &self,
+        db: &dyn DefDatabase,
+        start_crate: CrateId,
+        seg: Name,
+    ) -> Option<Path> {
+        let t = db.lang_item(start_crate, *self)?;
+        Some(Path::LangItem(t, Some(seg)))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index e523c229179..52781d98892 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,10 +1,11 @@
 //! Context for lowering paths.
+use std::cell::OnceCell;
+
 use hir_expand::{
     ast_id_map::{AstIdMap, AstIdNode},
     hygiene::Hygiene,
     AstId, HirFileId, InFile,
 };
-use once_cell::unsync::OnceCell;
 use syntax::ast;
 use triomphe::Arc;
 
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..4aedb22c6bc 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
@@ -23,6 +23,45 @@ fn main() { 0 as u32; }
 }
 
 #[test]
+fn test_asm_expand() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+macro_rules! asm {() => {}}
+
+fn main() {
+    let i: u64 = 3;
+    let o: u64;
+    unsafe {
+        asm!(
+            "mov {0}, {1}",
+            "add {0}, 5",
+            out(reg) o,
+            in(reg) i,
+        );
+    }
+}
+"#,
+        expect![[r##"
+#[rustc_builtin_macro]
+macro_rules! asm {() => {}}
+
+fn main() {
+    let i: u64 = 3;
+    let o: u64;
+    unsafe {
+        builtin #asm ( {
+            $crate::format_args!("mov {0}, {1}");
+            $crate::format_args!("add {0}, 5");
+        }
+        );
+    }
+}
+"##]],
+    );
+}
+
+#[test]
 fn test_line_expand() {
     check(
         r#"
@@ -201,7 +240,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(arg2), ::core::fmt::Debug::fmt), ]);
+    builtin #format_args ("{} {:?}", arg1(a, b, c), arg2);
 }
 "##]],
     );
@@ -219,10 +258,10 @@ macro_rules! format_args {
 
 fn main() {
     format_args!(x = 2);
-    format_args!(x =);
-    format_args!(x =, x = 2);
-    format_args!("{}", x =);
-    format_args!(=, "{}", x =);
+    format_args!/*+errors*/(x =);
+    format_args!/*+errors*/(x =, x = 2);
+    format_args!/*+errors*/("{}", x =);
+    format_args!/*+errors*/(=, "{}", x =);
     format_args!(x = 2, "{}", 5);
 }
 "#,
@@ -234,12 +273,19 @@ macro_rules! format_args {
 }
 
 fn main() {
-    /* error: no rule matches input tokens */;
-    /* 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 */;
-    ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]);
+    builtin #format_args (x = 2);
+    /* parse error: expected expression */
+builtin #format_args (x = );
+    /* parse error: expected expression */
+/* parse error: expected R_PAREN */
+/* parse error: expected expression, item or let statement */
+builtin #format_args (x = , x = 2);
+    /* parse error: expected expression */
+builtin #format_args ("{}", x = );
+    /* parse error: expected expression */
+/* parse error: expected expression */
+builtin #format_args ( = , "{}", x = );
+    builtin #format_args (x = 2, "{}", 5);
 }
 "##]],
     );
@@ -267,7 +313,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
+    builtin #format_args ("{} {:?}", a::<A, B>(), b);
 }
 "##]],
     );
@@ -300,7 +346,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
+    builtin #format_args (r#"{},mismatch,"{}","{}""#, location_csv_pat(db, &analysis, vfs, &sm, pat_id), mismatch.expected.display(db), mismatch.actual.display(db));
 }
 "##]],
     );
@@ -334,7 +380,7 @@ macro_rules! format_args {
 }
 
 fn main() {
-    ::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::ArgumentV1::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
+    builtin #format_args (concat!("xxx{}y", "{:?}zzz"), 2, b);
 }
 "##]],
     );
@@ -364,8 +410,8 @@ macro_rules! format_args {
 
 fn main() {
     let _ =
-        /* error: expected field name or number *//* parse error: expected field name or number */
-::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(), ::core::fmt::Debug::fmt), ]);
+        /* parse error: expected field name or number */
+builtin #format_args ("{} {:?}", a.);
 }
 "##]],
     );
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 2170cadcf83..d0906213243 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
@@ -117,7 +117,7 @@ fn main(foo: ()) {
 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), ])
+    builtin #format_args ("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar")
 }
 "##]],
     );
@@ -150,8 +150,8 @@ macro_rules! identity {
 }
 
 fn main(foo: ()) {
-    // format_args/*+tokenids*/!("{} {} {}"#1,#3 format_args!("{}", 0#10),#12 foo#13,#14 identity!(10#18),#21 "bar"#22)
-::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 " "#4294967295,#4294967295 " "#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#42949672950#10)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#4294967295foo#13)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#429496729510#18)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295
+    // format_args/*+tokenids*/!("{} {} {}"#1,#2 format_args#3!#4("{}"#6,#7 0#8),#9 foo#10,#11 identity#12!#13(10#15),#16 "bar"#17)
+builtin#4294967295 ##4294967295format_args#4294967295 (#0"{} {} {}"#1,#2 format_args#3!#4(#5"{}"#6,#7 0#8)#5,#9 foo#10,#11 identity#12!#13(#1410#15)#14,#16 "bar"#17)#0
 }
 
 "##]],
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index 97554f93f1c..b416f45ff20 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -929,8 +929,8 @@ fn main() {
 macro_rules! format_args {}
 
 fn main() {
-    /* error: expected field name or number *//* parse error: expected field name or number */
-::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(line.1.), ::core::fmt::Display::fmt), ]);
+    /* parse error: expected field name or number */
+builtin #format_args ("{}", line.1.);
 }
 
 "##]],
@@ -956,19 +956,15 @@ fn main() {
 macro_rules! format_args {}
 
 fn main() {
-    /* error: expected COMMA, expected R_BRACK, expected COMMA, expected COMMA, expected expression, expected R_PAREN *//* parse error: expected COMMA */
+    /* parse error: expected COMMA */
 /* parse error: expected R_BRACK */
 /* parse error: expected COMMA */
 /* parse error: expected COMMA */
 /* parse error: expected expression */
 /* parse error: expected R_PAREN */
-/* parse error: expected R_PAREN */
-/* parse error: expected expression, item or let statement */
-/* parse error: expected expression, item or let statement */
-/* parse error: expected expression, item or let statement */
 /* parse error: expected expression, item or let statement */
 /* parse error: expected expression, item or let statement */
-::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(&[0 2]), ::core::fmt::Display::fmt), ]);
+builtin #format_args ("{}", &[0 2]);
 }
 
 "##]],
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index f2110410980..9a9fa0e02b0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -93,7 +93,7 @@ use crate::{
 #[derive(Debug, PartialEq, Eq)]
 pub struct DefMap {
     _c: Count<Self>,
-    /// When this is a block def map, this will hold the block id of the the block and module that
+    /// When this is a block def map, this will hold the block id of the block and module that
     /// contains this block.
     block: Option<BlockInfo>,
     /// The modules and their data declared in this crate.
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 e9e71a8747f..2d4586146db 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
@@ -1828,7 +1828,11 @@ impl ModCollector<'_, '_> {
             let Some(paths) = attr.parse_path_comma_token_tree(db.upcast(), &hygiene) else {
                 // `#[macro_use]` (without any paths) found, forget collected names and just import
                 // all visible macros.
-                self.def_collector.import_macros_from_extern_crate(target_crate, None, Some(extern_crate_id));
+                self.def_collector.import_macros_from_extern_crate(
+                    target_crate,
+                    None,
+                    Some(extern_crate_id),
+                );
                 return;
             };
             for path in paths {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index 06530cc7ebd..3894172a5ad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -47,7 +47,7 @@ pub enum Path {
     },
     /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
     /// links via a normal path since they might be private and not accessible in the usage place.
-    LangItem(LangItemTarget),
+    LangItem(LangItemTarget, Option<Name>),
 }
 
 /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -122,33 +122,40 @@ impl Path {
     pub fn kind(&self) -> &PathKind {
         match self {
             Path::Normal { mod_path, .. } => &mod_path.kind,
-            Path::LangItem(_) => &PathKind::Abs,
+            Path::LangItem(..) => &PathKind::Abs,
         }
     }
 
     pub fn type_anchor(&self) -> Option<&TypeRef> {
         match self {
             Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
-            Path::LangItem(_) => None,
+            Path::LangItem(..) => None,
         }
     }
 
     pub fn segments(&self) -> PathSegments<'_> {
-        let Path::Normal { mod_path, generic_args, .. } = self else {
-            return PathSegments { segments: &[], generic_args: None };
-        };
-        let s =
-            PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() };
-        if let Some(generic_args) = s.generic_args {
-            assert_eq!(s.segments.len(), generic_args.len());
+        match self {
+            Path::Normal { mod_path, generic_args, .. } => {
+                let s = PathSegments {
+                    segments: mod_path.segments(),
+                    generic_args: generic_args.as_deref(),
+                };
+                if let Some(generic_args) = s.generic_args {
+                    assert_eq!(s.segments.len(), generic_args.len());
+                }
+                s
+            }
+            Path::LangItem(_, seg) => PathSegments {
+                segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
+                generic_args: None,
+            },
         }
-        s
     }
 
     pub fn mod_path(&self) -> Option<&ModPath> {
         match self {
             Path::Normal { mod_path, .. } => Some(&mod_path),
-            Path::LangItem(_) => None,
+            Path::LangItem(..) => None,
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index 11d58a6ba09..f4f5541e373 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -2,18 +2,54 @@
 
 use std::fmt::{self, Write};
 
-use hir_expand::{db::ExpandDatabase, mod_path::PathKind};
+use hir_expand::mod_path::PathKind;
 use intern::Interned;
 use itertools::Itertools;
 
 use crate::{
+    db::DefDatabase,
+    lang_item::LangItemTarget,
     path::{GenericArg, GenericArgs, Path},
     type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
 };
 
-pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
-    if let Path::LangItem(it) = path {
-        return write!(buf, "$lang_item::{it:?}");
+pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
+    if let Path::LangItem(it, s) = path {
+        write!(buf, "builtin#lang(")?;
+        match *it {
+            LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?,
+            LangItemTarget::EnumId(it) => {
+                write!(buf, "{}", db.enum_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::Function(it) => {
+                write!(buf, "{}", db.function_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::Static(it) => {
+                write!(buf, "{}", db.static_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::Struct(it) => {
+                write!(buf, "{}", db.struct_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::Union(it) => {
+                write!(buf, "{}", db.union_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::TypeAlias(it) => {
+                write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::Trait(it) => {
+                write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))?
+            }
+            LangItemTarget::EnumVariant(it) => write!(
+                buf,
+                "{}",
+                db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast())
+            )?,
+        }
+
+        if let Some(s) = s {
+            write!(buf, "::{}", s.display(db.upcast()))?;
+        }
+        return write!(buf, ")");
     }
     match path.type_anchor() {
         Some(anchor) => {
@@ -44,7 +80,7 @@ pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Wri
             write!(buf, "::")?;
         }
 
-        write!(buf, "{}", segment.name.display(db))?;
+        write!(buf, "{}", segment.name.display(db.upcast()))?;
         if let Some(generics) = segment.args_and_bindings {
             write!(buf, "::<")?;
             print_generic_args(db, generics, buf)?;
@@ -57,7 +93,7 @@ pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Wri
 }
 
 pub(crate) fn print_generic_args(
-    db: &dyn ExpandDatabase,
+    db: &dyn DefDatabase,
     generics: &GenericArgs,
     buf: &mut dyn Write,
 ) -> fmt::Result {
@@ -83,7 +119,7 @@ pub(crate) fn print_generic_args(
             write!(buf, ", ")?;
         }
         first = false;
-        write!(buf, "{}", binding.name.display(db))?;
+        write!(buf, "{}", binding.name.display(db.upcast()))?;
         if !binding.bounds.is_empty() {
             write!(buf, ": ")?;
             print_type_bounds(db, &binding.bounds, buf)?;
@@ -97,19 +133,19 @@ pub(crate) fn print_generic_args(
 }
 
 pub(crate) fn print_generic_arg(
-    db: &dyn ExpandDatabase,
+    db: &dyn DefDatabase,
     arg: &GenericArg,
     buf: &mut dyn Write,
 ) -> fmt::Result {
     match arg {
         GenericArg::Type(ty) => print_type_ref(db, ty, buf),
-        GenericArg::Const(c) => write!(buf, "{}", c.display(db)),
-        GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db)),
+        GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast())),
+        GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast())),
     }
 }
 
 pub(crate) fn print_type_ref(
-    db: &dyn ExpandDatabase,
+    db: &dyn DefDatabase,
     type_ref: &TypeRef,
     buf: &mut dyn Write,
 ) -> fmt::Result {
@@ -143,7 +179,7 @@ pub(crate) fn print_type_ref(
             };
             write!(buf, "&")?;
             if let Some(lt) = lt {
-                write!(buf, "{} ", lt.name.display(db))?;
+                write!(buf, "{} ", lt.name.display(db.upcast()))?;
             }
             write!(buf, "{mtbl}")?;
             print_type_ref(db, pointee, buf)?;
@@ -151,7 +187,7 @@ pub(crate) fn print_type_ref(
         TypeRef::Array(elem, len) => {
             write!(buf, "[")?;
             print_type_ref(db, elem, buf)?;
-            write!(buf, "; {}]", len.display(db))?;
+            write!(buf, "; {}]", len.display(db.upcast()))?;
         }
         TypeRef::Slice(elem) => {
             write!(buf, "[")?;
@@ -198,7 +234,7 @@ pub(crate) fn print_type_ref(
 }
 
 pub(crate) fn print_type_bounds(
-    db: &dyn ExpandDatabase,
+    db: &dyn DefDatabase,
     bounds: &[Interned<TypeBound>],
     buf: &mut dyn Write,
 ) -> fmt::Result {
@@ -216,10 +252,14 @@ pub(crate) fn print_type_bounds(
                 print_path(db, path, buf)?;
             }
             TypeBound::ForLifetime(lifetimes, path) => {
-                write!(buf, "for<{}> ", lifetimes.iter().map(|it| it.display(db)).format(", "))?;
+                write!(
+                    buf,
+                    "for<{}> ",
+                    lifetimes.iter().map(|it| it.display(db.upcast())).format(", ")
+                )?;
                 print_path(db, path, buf)?;
             }
-            TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db))?,
+            TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast()))?,
             TypeBound::Error => write!(buf, "{{unknown}}")?,
         }
     }
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 2f9187009e2..50da9ed06a0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -156,22 +156,19 @@ impl Resolver {
     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
         let path = match path {
             Path::Normal { mod_path, .. } => mod_path,
-            Path::LangItem(l) => {
-                return Some((
-                    match *l {
-                        LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
-                        LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
-                        LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
-                        LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
-                        LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
-                        LangItemTarget::Trait(it) => TypeNs::TraitId(it),
-                        LangItemTarget::Function(_)
-                        | LangItemTarget::ImplDef(_)
-                        | LangItemTarget::Static(_) => return None,
-                    },
-                    None,
-                    None,
-                ))
+            Path::LangItem(l, seg) => {
+                let type_ns = match *l {
+                    LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
+                    LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
+                    LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
+                    LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
+                    LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
+                    LangItemTarget::Trait(it) => TypeNs::TraitId(it),
+                    LangItemTarget::Function(_)
+                    | LangItemTarget::ImplDef(_)
+                    | LangItemTarget::Static(_) => return None,
+                };
+                return Some((type_ns, seg.as_ref().map(|_| 1), None));
             }
         };
         let first_name = path.segments().first()?;
@@ -256,7 +253,7 @@ impl Resolver {
     ) -> Option<ResolveValueResult> {
         let path = match path {
             Path::Normal { mod_path, .. } => mod_path,
-            Path::LangItem(l) => {
+            Path::LangItem(l, None) => {
                 return Some(ResolveValueResult::ValueNs(
                     match *l {
                         LangItemTarget::Function(it) => ValueNs::FunctionId(it),
@@ -272,6 +269,20 @@ impl Resolver {
                     None,
                 ))
             }
+            Path::LangItem(l, Some(_)) => {
+                let type_ns = match *l {
+                    LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
+                    LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
+                    LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
+                    LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
+                    LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
+                    LangItemTarget::Trait(it) => TypeNs::TraitId(it),
+                    LangItemTarget::Function(_)
+                    | LangItemTarget::ImplDef(_)
+                    | LangItemTarget::Static(_) => return None,
+                };
+                return Some(ResolveValueResult::Partial(type_ns, 1, None));
+            }
         };
         let n_segments = path.segments().len();
         let tmp = name![self];
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 95c6baf42da..30b19b6e51b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -1,13 +1,9 @@
 //! Builtin macro
 
-use std::mem;
-
-use ::tt::Ident;
 use base_db::{AnchoredPath, Edition, FileId};
 use cfg::CfgExpr;
 use either::Either;
 use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap};
-use rustc_hash::FxHashMap;
 use syntax::{
     ast::{self, AstToken},
     SmolStr,
@@ -97,11 +93,11 @@ register_builtin! {
     (unreachable, Unreachable) => unreachable_expand,
     (log_syntax, LogSyntax) => log_syntax_expand,
     (trace_macros, TraceMacros) => trace_macros_expand,
-
-    EAGER:
     (format_args, FormatArgs) => format_args_expand,
     (const_format_args, ConstFormatArgs) => format_args_expand,
     (format_args_nl, FormatArgsNl) => format_args_nl_expand,
+
+    EAGER:
     (compile_error, CompileError) => compile_error_expand,
     (concat, Concat) => concat_expand,
     (concat_idents, ConcatIdents) => concat_idents_expand,
@@ -247,151 +243,15 @@ fn format_args_expand_general(
     _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
-    end_string: &str,
+    // FIXME: Make use of this so that mir interpretation works properly
+    _end_string: &str,
 ) -> ExpandResult<tt::Subtree> {
-    let args = parse_exprs_with_sep(tt, ',');
-
-    let expand_error =
-        ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into());
-
-    let mut key_args = FxHashMap::default();
-    let mut args = args.into_iter().filter_map(|mut arg| {
-        // Remove `key =`.
-        if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
-        {
-            // but not with `==`
-            if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
-            {
-                let key = arg.token_trees.drain(..2).next().unwrap();
-                key_args.insert(key.to_string(), arg);
-                return None;
-            }
-        }
-        Some(arg)
-    }).collect::<Vec<_>>().into_iter();
-    // ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`)
-    let Some(format_subtree) = args.next() else {
-        return expand_error;
-    };
-    let format_string = (|| {
-        let token_tree = format_subtree.token_trees.get(0)?;
-        match token_tree {
-            tt::TokenTree::Leaf(l) => match l {
-                tt::Leaf::Literal(l) => {
-                    if let Some(mut text) = l.text.strip_prefix('r') {
-                        let mut raw_sharps = String::new();
-                        while let Some(t) = text.strip_prefix('#') {
-                            text = t;
-                            raw_sharps.push('#');
-                        }
-                        text =
-                            text.strip_suffix(&raw_sharps)?.strip_prefix('"')?.strip_suffix('"')?;
-                        Some((text, l.span, Some(raw_sharps)))
-                    } else {
-                        let text = l.text.strip_prefix('"')?.strip_suffix('"')?;
-                        let span = l.span;
-                        Some((text, span, None))
-                    }
-                }
-                _ => None,
-            },
-            tt::TokenTree::Subtree(_) => None,
-        }
-    })();
-    let Some((format_string, _format_string_span, raw_sharps)) = format_string else {
-        return expand_error;
-    };
-    let mut format_iter = format_string.chars().peekable();
-    let mut parts = vec![];
-    let mut last_part = String::new();
-    let mut arg_tts = vec![];
-    let mut err = None;
-    while let Some(c) = format_iter.next() {
-        // Parsing the format string. See https://doc.rust-lang.org/std/fmt/index.html#syntax for the grammar and more info
-        match c {
-            '{' => {
-                if format_iter.peek() == Some(&'{') {
-                    format_iter.next();
-                    last_part.push('{');
-                    continue;
-                }
-                let mut argument = String::new();
-                while ![Some(&'}'), Some(&':')].contains(&format_iter.peek()) {
-                    argument.push(match format_iter.next() {
-                        Some(c) => c,
-                        None => return expand_error,
-                    });
-                }
-                let format_spec = match format_iter.next().unwrap() {
-                    '}' => "".to_owned(),
-                    ':' => {
-                        let mut s = String::new();
-                        while let Some(c) = format_iter.next() {
-                            if c == '}' {
-                                break;
-                            }
-                            s.push(c);
-                        }
-                        s
-                    }
-                    _ => unreachable!(),
-                };
-                parts.push(mem::take(&mut last_part));
-                let arg_tree = if argument.is_empty() {
-                    match args.next() {
-                        Some(it) => it,
-                        None => {
-                            err = Some(mbe::ExpandError::NoMatchingRule.into());
-                            tt::Subtree::empty()
-                        }
-                    }
-                } else if let Some(tree) = key_args.get(&argument) {
-                    tree.clone()
-                } else {
-                    // FIXME: we should pick the related substring of the `_format_string_span` as the span. You
-                    // can use `.char_indices()` instead of `.char()` for `format_iter` to find the substring interval.
-                    let ident = Ident::new(argument, tt::TokenId::unspecified());
-                    quote!(#ident)
-                };
-                let formatter = match &*format_spec {
-                    "?" => quote!(::core::fmt::Debug::fmt),
-                    "" => quote!(::core::fmt::Display::fmt),
-                    _ => {
-                        // FIXME: implement the rest and return expand error here
-                        quote!(::core::fmt::Display::fmt)
-                    }
-                };
-                arg_tts.push(quote! { ::core::fmt::ArgumentV1::new(&(#arg_tree), #formatter), });
-            }
-            '}' => {
-                if format_iter.peek() == Some(&'}') {
-                    format_iter.next();
-                    last_part.push('}');
-                } else {
-                    return expand_error;
-                }
-            }
-            _ => last_part.push(c),
-        }
-    }
-    last_part += end_string;
-    if !last_part.is_empty() {
-        parts.push(last_part);
-    }
-    let part_tts = parts.into_iter().map(|it| {
-        let text = if let Some(raw) = &raw_sharps {
-            format!("r{raw}\"{}\"{raw}", it).into()
-        } else {
-            format!("\"{}\"", it).into()
-        };
-        let l = tt::Literal { span: tt::TokenId::unspecified(), text };
-        quote!(#l ,)
+    let pound = quote! {@PUNCT '#'};
+    let mut tt = tt.clone();
+    tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
+    return ExpandResult::ok(quote! {
+        builtin #pound format_args #tt
     });
-    let arg_tts = arg_tts.into_iter().flat_map(|arg| arg.token_trees);
-    let expanded = quote! {
-        ::core::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts])
-    };
-    ExpandResult { value: expanded, err }
 }
 
 fn asm_expand(
@@ -415,10 +275,12 @@ fn asm_expand(
         }
     }
 
-    let expanded = quote! {{
-        ##literals
-        loop {}
-    }};
+    let pound = quote! {@PUNCT '#'};
+    let expanded = quote! {
+        builtin #pound asm (
+            {##literals}
+        )
+    };
     ExpandResult::ok(expanded)
 }
 
@@ -692,7 +554,7 @@ pub(crate) fn include_arg_to_tt(
     arg_id: MacroCallId,
 ) -> Result<(triomphe::Arc<(::tt::Subtree<::tt::TokenId>, TokenMap)>, FileId), ExpandError> {
     let loc = db.lookup_intern_macro_call(arg_id);
-    let Some(EagerCallInfo { arg,arg_id, .. }) = loc.eager.as_deref() else {
+    let Some(EagerCallInfo { arg, arg_id, .. }) = loc.eager.as_deref() else {
         panic!("include_arg_to_tt called on non include macro call: {:?}", &loc.eager);
     };
     let path = parse_string(&arg.0)?;
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 ade4a592893..ca65db1136c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -242,7 +242,7 @@ impl HygieneFrame {
                 krate,
                 call_site: None,
                 def_site: None,
-            }
+            };
         };
 
         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/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 7c179c0cf95..a876f48bda4 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -54,6 +54,12 @@ impl Name {
         Name(Repr::Text(text))
     }
 
+    // FIXME: See above, unfortunately some places really need this right now
+    #[doc(hidden)]
+    pub const fn new_text_dont_use(text: SmolStr) -> Name {
+        Name(Repr::Text(text))
+    }
+
     pub fn new_tuple_field(idx: usize) -> Name {
         Name(Repr::TupleField(idx))
     }
@@ -302,6 +308,16 @@ pub mod known {
         rust_2018,
         rust_2021,
         v1,
+        new_display,
+        new_debug,
+        new_lower_exp,
+        new_upper_exp,
+        new_octal,
+        new_pointer,
+        new_binary,
+        new_lower_hex,
+        new_upper_hex,
+        from_usize,
         // Components of known path (type name)
         Iterator,
         IntoIterator,
@@ -327,6 +343,13 @@ pub mod known {
         Not,
         None,
         Index,
+        Left,
+        Right,
+        Center,
+        Unknown,
+        Is,
+        Param,
+        Implied,
         // Components of known path (function name)
         filter_map,
         next,
@@ -335,6 +358,8 @@ pub mod known {
         is_empty,
         as_str,
         new,
+        new_v1_formatted,
+        none,
         // Builtin macros
         asm,
         assert,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index abc19d63abf..b95ae05ccd4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -32,7 +32,8 @@ once_cell = "1.17.0"
 triomphe.workspace = true
 nohash-hasher.workspace = true
 typed-arena = "2.0.1"
-rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
+
+rustc_index.workspace = true
 
 # local deps
 stdx.workspace = true
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 2855f789001..44a4ac27af0 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
@@ -499,24 +499,26 @@ fn offset() {
         r#"
         //- minicore: coerce_unsized, index, slice
         extern "rust-intrinsic" {
-            pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
+            pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
+            pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
         }
 
-        const GOAL: u8 = unsafe {
-            let ar: &[(u8, u8, u8)] = &[
+        const GOAL: i32 = unsafe {
+            let ar: &[(i32, i32, i32)] = &[
                 (10, 11, 12),
                 (20, 21, 22),
                 (30, 31, 32),
                 (40, 41, 42),
                 (50, 51, 52),
             ];
-            let ar: *const [(u8, u8, u8)] = ar;
-            let ar = ar as *const (u8, u8, u8);
-            let element = *offset(ar, 2);
-            element.1
+            let ar: *const [(i32, i32, i32)] = ar;
+            let ar = ar as *const (i32, i32, i32);
+            let element3 = *offset(ar, 2usize);
+            let element4 = *arith_offset(ar, 3);
+            element3.1 * 100 + element4.0
         };
         "#,
-        31,
+        3140,
     );
 }
 
@@ -585,6 +587,24 @@ fn write_bytes() {
 }
 
 #[test]
+fn write_via_move() {
+    check_number(
+        r#"
+        extern "rust-intrinsic" {
+            fn write_via_move<T>(ptr: *mut T, value: T);
+        }
+
+        const GOAL: i32 = unsafe {
+            let mut x = 2;
+            write_via_move(&mut x, 100);
+            x
+        };
+        "#,
+        100,
+    );
+}
+
+#[test]
 fn copy() {
     check_number(
         r#"
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 a94a962c1f8..36d69edf9d5 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
@@ -163,25 +163,56 @@ impl<'a> DeclValidator<'a> {
                         || allows.contains(allow::NONSTANDARD_STYLE)
                 })
         };
+        let db = self.db.upcast();
+        let file_id_is_derive = || {
+            match id {
+                AttrDefId::ModuleId(m) => {
+                    m.def_map(db)[m.local_id].origin.file_id().map(Into::into)
+                }
+                AttrDefId::FunctionId(f) => Some(f.lookup(db).id.file_id()),
+                AttrDefId::StaticId(sid) => Some(sid.lookup(db).id.file_id()),
+                AttrDefId::ConstId(cid) => Some(cid.lookup(db).id.file_id()),
+                AttrDefId::TraitId(tid) => Some(tid.lookup(db).id.file_id()),
+                AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).id.file_id()),
+                AttrDefId::ImplId(iid) => Some(iid.lookup(db).id.file_id()),
+                AttrDefId::ExternBlockId(id) => Some(id.lookup(db).id.file_id()),
+                AttrDefId::ExternCrateId(id) => Some(id.lookup(db).id.file_id()),
+                AttrDefId::UseId(id) => Some(id.lookup(db).id.file_id()),
+                // These warnings should not explore macro definitions at all
+                AttrDefId::MacroId(_) => None,
+                AttrDefId::AdtId(aid) => match aid {
+                    AdtId::StructId(sid) => Some(sid.lookup(db).id.file_id()),
+                    AdtId::EnumId(eid) => Some(eid.lookup(db).id.file_id()),
+                    // Unions aren't yet supported
+                    AdtId::UnionId(_) => None,
+                },
+                AttrDefId::FieldId(_) => None,
+                AttrDefId::EnumVariantId(_) => None,
+                AttrDefId::TypeAliasId(_) => None,
+                AttrDefId::GenericParamId(_) => None,
+            }
+            .map_or(false, |file_id| {
+                file_id.is_custom_derive(db.upcast()) || file_id.is_builtin_derive(db.upcast())
+            })
+        };
 
-        is_allowed(id)
-            // go upwards one step or give up
-            || match id {
-                AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()),
-                AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()),
-                AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
-                AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
-                AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
-                AttrDefId::TraitAliasId(taid) => Some(taid.lookup(self.db.upcast()).container.into()),
-                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()),
+        let parent = || {
+            match id {
+                AttrDefId::ModuleId(m) => m.containing_module(db).map(|v| v.into()),
+                AttrDefId::FunctionId(f) => Some(f.lookup(db).container.into()),
+                AttrDefId::StaticId(sid) => Some(sid.lookup(db).container.into()),
+                AttrDefId::ConstId(cid) => Some(cid.lookup(db).container.into()),
+                AttrDefId::TraitId(tid) => Some(tid.lookup(db).container.into()),
+                AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).container.into()),
+                AttrDefId::ImplId(iid) => Some(iid.lookup(db).container.into()),
+                AttrDefId::ExternBlockId(id) => Some(id.lookup(db).container.into()),
+                AttrDefId::ExternCrateId(id) => Some(id.lookup(db).container.into()),
+                AttrDefId::UseId(id) => Some(id.lookup(db).container.into()),
                 // These warnings should not explore macro definitions at all
                 AttrDefId::MacroId(_) => None,
                 AttrDefId::AdtId(aid) => match aid {
-                    AdtId::StructId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
-                    AdtId::EnumId(eid) => Some(eid.lookup(self.db.upcast()).container.into()),
+                    AdtId::StructId(sid) => Some(sid.lookup(db).container.into()),
+                    AdtId::EnumId(eid) => Some(eid.lookup(db).container.into()),
                     // Unions aren't yet supported
                     AdtId::UnionId(_) => None,
                 },
@@ -191,6 +222,12 @@ impl<'a> DeclValidator<'a> {
                 AttrDefId::GenericParamId(_) => None,
             }
             .is_some_and(|mid| self.allowed(mid, allow_name, true))
+        };
+        is_allowed(id)
+            // FIXME: this is a hack to avoid false positives in derive macros currently
+            || file_id_is_derive()
+            // go upwards one step or give up
+            || parent()
     }
 
     fn validate_func(&mut self, func: FunctionId) {
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 0fb4934444b..78d3c667a1f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -194,7 +194,8 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum InferenceDiagnostic {
     NoSuchField {
-        expr: ExprId,
+        field: ExprOrPatId,
+        private: bool,
     },
     PrivateField {
         expr: ExprId,
@@ -228,6 +229,11 @@ pub enum InferenceDiagnostic {
         expected: usize,
         found: usize,
     },
+    MismatchedTupleStructPatArgCount {
+        pat: ExprOrPatId,
+        expected: usize,
+        found: usize,
+    },
     ExpectedFunction {
         call_expr: ExprId,
         found: Ty,
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
index 9e1c74b16fa..a116d444731 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
@@ -39,8 +39,14 @@ impl CastCheck {
 }
 
 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; };
+    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 23efe616f4f..13d6b5643ac 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
@@ -452,6 +452,8 @@ impl InferenceContext<'_> {
 
     fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
         match &self.body[tgt_expr] {
+            Expr::OffsetOf(_) => (),
+            Expr::InlineAsm(e) => self.walk_expr_without_adjust(e.e),
             Expr::If { condition, then_branch, else_branch } => {
                 self.consume_expr(*condition);
                 self.consume_expr(*then_branch);
@@ -467,13 +469,13 @@ impl InferenceContext<'_> {
                         Statement::Let { pat, type_ref: _, initializer, else_branch } => {
                             if let Some(else_branch) = else_branch {
                                 self.consume_expr(*else_branch);
-                                if let Some(initializer) = initializer {
-                                    self.consume_expr(*initializer);
-                                }
-                                return;
                             }
                             if let Some(initializer) = initializer {
-                                self.walk_expr(*initializer);
+                                if else_branch.is_some() {
+                                    self.consume_expr(*initializer);
+                                } else {
+                                    self.walk_expr(*initializer);
+                                }
                                 if let Some(place) = self.place_of_expr(*initializer) {
                                     self.consume_with_pat(place, *pat);
                                 }
@@ -620,6 +622,7 @@ impl InferenceContext<'_> {
             | Expr::Tuple { exprs, is_assignee_expr: _ } => {
                 self.consume_exprs(exprs.iter().copied())
             }
+
             Expr::Missing
             | Expr::Continue { .. }
             | Expr::Path(_)
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 8b352141084..0c3c725a7c7 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
@@ -514,9 +514,6 @@ impl InferenceContext<'_> {
             }
             Expr::RecordLit { path, fields, spread, .. } => {
                 let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
-                if let Some(variant) = def_id {
-                    self.write_variant_resolution(tgt_expr.into(), variant);
-                }
 
                 if let Some(t) = expected.only_has_type(&mut self.table) {
                     self.unify(&ty, &t);
@@ -526,26 +523,56 @@ impl InferenceContext<'_> {
                     .as_adt()
                     .map(|(_, s)| s.clone())
                     .unwrap_or_else(|| Substitution::empty(Interner));
-                let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
-                let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
-                for field in fields.iter() {
-                    let field_def =
-                        variant_data.as_ref().and_then(|it| match it.field(&field.name) {
-                            Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }),
-                            None => {
-                                self.push_diagnostic(InferenceDiagnostic::NoSuchField {
-                                    expr: field.expr,
-                                });
-                                None
-                            }
-                        });
-                    let field_ty = field_def.map_or(self.err_ty(), |it| {
-                        field_types[it.local_id].clone().substitute(Interner, &substs)
-                    });
-                    // Field type might have some unknown types
-                    // FIXME: we may want to emit a single type variable for all instance of type fields?
-                    let field_ty = self.insert_type_vars(field_ty);
-                    self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
+                if let Some(variant) = def_id {
+                    self.write_variant_resolution(tgt_expr.into(), variant);
+                }
+                match def_id {
+                    _ if fields.is_empty() => {}
+                    Some(def) => {
+                        let field_types = self.db.field_types(def);
+                        let variant_data = def.variant_data(self.db.upcast());
+                        let visibilities = self.db.field_visibilities(def);
+                        for field in fields.iter() {
+                            let field_def = {
+                                match variant_data.field(&field.name) {
+                                    Some(local_id) => {
+                                        if !visibilities[local_id].is_visible_from(
+                                            self.db.upcast(),
+                                            self.resolver.module(),
+                                        ) {
+                                            self.push_diagnostic(
+                                                InferenceDiagnostic::NoSuchField {
+                                                    field: field.expr.into(),
+                                                    private: true,
+                                                },
+                                            );
+                                        }
+                                        Some(local_id)
+                                    }
+                                    None => {
+                                        self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+                                            field: field.expr.into(),
+                                            private: false,
+                                        });
+                                        None
+                                    }
+                                }
+                            };
+                            let field_ty = field_def.map_or(self.err_ty(), |it| {
+                                field_types[it].clone().substitute(Interner, &substs)
+                            });
+
+                            // Field type might have some unknown types
+                            // FIXME: we may want to emit a single type variable for all instance of type fields?
+                            let field_ty = self.insert_type_vars(field_ty);
+                            self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
+                        }
+                    }
+                    None => {
+                        for field in fields.iter() {
+                            self.infer_expr_coerce(field.expr, &Expectation::None);
+                        }
+                    }
                 }
                 if let Some(expr) = spread {
                     self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
@@ -843,6 +870,11 @@ impl InferenceContext<'_> {
                 });
                 expected
             }
+            Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
+            Expr::InlineAsm(it) => {
+                self.infer_expr_no_expect(it.e);
+                self.result.standard_types.unit.clone()
+            }
         };
         // use a new type variable if we got unknown here
         let ty = self.insert_type_vars_shallow(ty);
@@ -1122,7 +1154,7 @@ impl InferenceContext<'_> {
             Expr::Underscore => rhs_ty.clone(),
             _ => {
                 // `lhs` is a place expression, a unit struct, or an enum variant.
-                let lhs_ty = self.infer_expr(lhs, &Expectation::none());
+                let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none());
 
                 // This is the only branch where this function may coerce any type.
                 // We are returning early to avoid the unifiability check below.
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 396ca0044ff..b8a1af96fba 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
@@ -35,6 +35,8 @@ impl InferenceContext<'_> {
     fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
         match &self.body[tgt_expr] {
             Expr::Missing => (),
+            Expr::InlineAsm(e) => self.infer_mut_expr_without_adjust(e.e, Mutability::Not),
+            Expr::OffsetOf(_) => (),
             &Expr::If { condition, then_branch, else_branch } => {
                 self.infer_mut_expr(condition, Mutability::Not);
                 self.infer_mut_expr(then_branch, Mutability::Not);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 5da0ab76b88..4e28ec06023 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -15,7 +15,8 @@ use crate::{
     infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
     lower::lower_to_chalk_mutability,
     primitive::UintTy,
-    static_lifetime, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt, TyKind,
+    static_lifetime, InferenceDiagnostic, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt,
+    TyKind,
 };
 
 /// Used to generalize patterns and assignee expressions.
@@ -74,29 +75,68 @@ impl InferenceContext<'_> {
         if let Some(variant) = def {
             self.write_variant_resolution(id.into(), variant);
         }
+        if let Some(var) = &var_data {
+            let cmp = if ellipsis.is_some() { usize::gt } else { usize::ne };
+
+            if cmp(&subs.len(), &var.fields().len()) {
+                self.push_diagnostic(InferenceDiagnostic::MismatchedTupleStructPatArgCount {
+                    pat: id.into(),
+                    expected: var.fields().len(),
+                    found: subs.len(),
+                });
+            }
+        }
+
         self.unify(&ty, expected);
 
         let substs =
             ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
 
-        let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
-        let (pre, post) = match ellipsis {
-            Some(idx) => subs.split_at(idx),
-            None => (subs, &[][..]),
-        };
-        let post_idx_offset = field_tys.iter().count().saturating_sub(post.len());
-
-        let pre_iter = pre.iter().enumerate();
-        let post_iter = (post_idx_offset..).zip(post.iter());
-        for (i, &subpat) in pre_iter.chain(post_iter) {
-            let expected_ty = var_data
-                .as_ref()
-                .and_then(|d| d.field(&Name::new_tuple_field(i)))
-                .map_or(self.err_ty(), |field| {
-                    field_tys[field].clone().substitute(Interner, &substs)
-                });
-            let expected_ty = self.normalize_associated_types_in(expected_ty);
-            T::infer(self, subpat, &expected_ty, default_bm);
+        match def {
+            _ if subs.len() == 0 => {}
+            Some(def) => {
+                let field_types = self.db.field_types(def);
+                let variant_data = def.variant_data(self.db.upcast());
+                let visibilities = self.db.field_visibilities(def);
+
+                let (pre, post) = match ellipsis {
+                    Some(idx) => subs.split_at(idx),
+                    None => (subs, &[][..]),
+                };
+                let post_idx_offset = field_types.iter().count().saturating_sub(post.len());
+
+                let pre_iter = pre.iter().enumerate();
+                let post_iter = (post_idx_offset..).zip(post.iter());
+
+                for (i, &subpat) in pre_iter.chain(post_iter) {
+                    let field_def = {
+                        match variant_data.field(&Name::new_tuple_field(i)) {
+                            Some(local_id) => {
+                                if !visibilities[local_id]
+                                    .is_visible_from(self.db.upcast(), self.resolver.module())
+                                {
+                                    // FIXME(DIAGNOSE): private tuple field
+                                }
+                                Some(local_id)
+                            }
+                            None => None,
+                        }
+                    };
+
+                    let expected_ty = field_def.map_or(self.err_ty(), |f| {
+                        field_types[f].clone().substitute(Interner, &substs)
+                    });
+                    let expected_ty = self.normalize_associated_types_in(expected_ty);
+
+                    T::infer(self, subpat, &expected_ty, default_bm);
+                }
+            }
+            None => {
+                let err_ty = self.err_ty();
+                for &inner in subs {
+                    T::infer(self, inner, &err_ty, default_bm);
+                }
+            }
         }
 
         ty
@@ -109,7 +149,7 @@ impl InferenceContext<'_> {
         expected: &Ty,
         default_bm: T::BindingMode,
         id: T,
-        subs: impl Iterator<Item = (Name, T)>,
+        subs: impl Iterator<Item = (Name, T)> + ExactSizeIterator,
     ) -> Ty {
         let (ty, def) = self.resolve_variant(path, false);
         if let Some(variant) = def {
@@ -121,17 +161,51 @@ impl InferenceContext<'_> {
         let substs =
             ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
 
-        let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
-        let var_data = def.map(|it| it.variant_data(self.db.upcast()));
+        match def {
+            _ if subs.len() == 0 => {}
+            Some(def) => {
+                let field_types = self.db.field_types(def);
+                let variant_data = def.variant_data(self.db.upcast());
+                let visibilities = self.db.field_visibilities(def);
+
+                for (name, inner) in subs {
+                    let field_def = {
+                        match variant_data.field(&name) {
+                            Some(local_id) => {
+                                if !visibilities[local_id]
+                                    .is_visible_from(self.db.upcast(), self.resolver.module())
+                                {
+                                    self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+                                        field: inner.into(),
+                                        private: true,
+                                    });
+                                }
+                                Some(local_id)
+                            }
+                            None => {
+                                self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+                                    field: inner.into(),
+                                    private: false,
+                                });
+                                None
+                            }
+                        }
+                    };
 
-        for (name, inner) in subs {
-            let expected_ty = var_data
-                .as_ref()
-                .and_then(|it| it.field(&name))
-                .map_or(self.err_ty(), |f| field_tys[f].clone().substitute(Interner, &substs));
-            let expected_ty = self.normalize_associated_types_in(expected_ty);
+                    let expected_ty = field_def.map_or(self.err_ty(), |f| {
+                        field_types[f].clone().substitute(Interner, &substs)
+                    });
+                    let expected_ty = self.normalize_associated_types_in(expected_ty);
 
-            T::infer(self, inner, &expected_ty, default_bm);
+                    T::infer(self, inner, &expected_ty, default_bm);
+                }
+            }
+            None => {
+                let err_ty = self.err_ty();
+                for (_, inner) in subs {
+                    T::infer(self, inner, &err_ty, default_bm);
+                }
+            }
         }
 
         ty
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 2a51c84db3a..c6bbf2f6140 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -178,13 +178,30 @@ impl InferenceContext<'_> {
         remaining_index: usize,
         id: ExprOrPatId,
     ) -> Option<(ValueNs, Substitution)> {
-        assert!(remaining_index < path.segments().len());
         // there may be more intermediate segments between the resolved one and
         // the end. Only the last segment needs to be resolved to a value; from
         // the segments before that, we need to get either a type or a trait ref.
 
-        let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
-        let remaining_segments = path.segments().skip(remaining_index);
+        let _d;
+        let (resolved_segment, remaining_segments) = match path {
+            Path::Normal { .. } => {
+                assert!(remaining_index < path.segments().len());
+                (
+                    path.segments().get(remaining_index - 1).unwrap(),
+                    path.segments().skip(remaining_index),
+                )
+            }
+            Path::LangItem(..) => (
+                PathSegment {
+                    name: {
+                        _d = hir_expand::name::known::Unknown;
+                        &_d
+                    },
+                    args_and_bindings: None,
+                },
+                path.segments(),
+            ),
+        };
         let is_before_last = remaining_segments.len() == 1;
 
         match (def, is_before_last) {
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 b15339d4434..1a6106c0244 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -24,7 +24,7 @@ pub use self::{
 
 macro_rules! user_error {
     ($it: expr) => {
-        return Err(LayoutError::UserError(format!($it)))
+        return Err(LayoutError::UserError(format!($it).into()))
     };
 }
 
@@ -50,7 +50,7 @@ pub type Variants = hir_def::layout::Variants<RustcEnumVariantIdx>;
 
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum LayoutError {
-    UserError(String),
+    UserError(Box<str>),
     SizeOverflow,
     TargetLayoutNotAvailable,
     HasPlaceholder,
@@ -109,7 +109,8 @@ fn layout_of_simd_ty(
     // * the homogeneous field type and the number of fields.
     let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) {
         // Extract the number of elements from the layout of the array field:
-        let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields else {
+        let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields
+        else {
             user_error!("Array with non array layout");
         };
 
@@ -233,9 +234,9 @@ pub fn layout_of_ty_query(
             cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
         }
         TyKind::Array(element, count) => {
-            let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(
-                "unevaluated or mistyped const generic parameter".to_string(),
-            ))? as u64;
+            let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(Box::from(
+                "unevaluated or mistyped const generic parameter",
+            )))? as u64;
             let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
             let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 1c92e80f335..85ef649b895 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -163,7 +163,7 @@ fn repr_discr(
             return Err(LayoutError::UserError(
                 "Integer::repr_discr: `#[repr]` hint too small for \
                       discriminant range of enum "
-                    .to_string(),
+                    .into(),
             ));
         }
         return Ok((discr, ity.is_signed()));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 333ad473a8b..ffdbb9de934 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -212,14 +212,14 @@ fn recursive() {
     }
     check_fail(
         r#"struct Goal(Goal);"#,
-        LayoutError::UserError("infinite sized recursive type".to_string()),
+        LayoutError::UserError("infinite sized recursive type".into()),
     );
     check_fail(
         r#"
         struct Foo<T>(Foo<T>);
         struct Goal(Foo<i32>);
         "#,
-        LayoutError::UserError("infinite sized recursive type".to_string()),
+        LayoutError::UserError("infinite sized recursive type".into()),
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
index 576e7f3fc61..bbe855a14de 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
@@ -255,3 +255,17 @@ fn ellipsis_pattern() {
         }
     }
 }
+
+#[test]
+fn regression_15623() {
+    size_and_align_expr! {
+        let a = 2;
+        let b = 3;
+        let c = 5;
+        move || {
+            let 0 = a else { return b; };
+            let y = c;
+            y
+        }
+    }
+}
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 9be083d0117..e953058ccca 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -1,6 +1,6 @@
 //! MIR definitions and implementation
 
-use std::{fmt::Display, iter};
+use std::{collections::hash_map::Entry, fmt::Display, iter};
 
 use crate::{
     consteval::usize_const,
@@ -37,6 +37,7 @@ pub use monomorphization::{
     monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
     monomorphized_mir_body_query, monomorphized_mir_body_recover,
 };
+use rustc_hash::FxHashMap;
 use smallvec::{smallvec, SmallVec};
 use stdx::{impl_from, never};
 use triomphe::Arc;
@@ -165,8 +166,8 @@ impl<V, T> ProjectionElem<V, T> {
                 TyKind::Adt(_, subst) => {
                     db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
                 }
-                _ => {
-                    never!("Only adt has field");
+                ty => {
+                    never!("Only adt has field, found {:?}", ty);
                     return TyKind::Error.intern(Interner);
                 }
             },
@@ -223,35 +224,93 @@ impl<V, T> ProjectionElem<V, T> {
 
 type PlaceElem = ProjectionElem<LocalId, Ty>;
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ProjectionId(u32);
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ProjectionStore {
+    id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
+    proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
+}
+
+impl Default for ProjectionStore {
+    fn default() -> Self {
+        let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
+        // Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
+        this.intern(Box::new([]));
+        this
+    }
+}
+
+impl ProjectionStore {
+    fn shrink_to_fit(&mut self) {
+        self.id_to_proj.shrink_to_fit();
+        self.proj_to_id.shrink_to_fit();
+    }
+
+    fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
+        self.proj_to_id.get(projection).copied()
+    }
+
+    fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
+        let new_id = ProjectionId(self.proj_to_id.len() as u32);
+        match self.proj_to_id.entry(projection) {
+            Entry::Occupied(id) => *id.get(),
+            Entry::Vacant(e) => {
+                let key_clone = e.key().clone();
+                e.insert(new_id);
+                self.id_to_proj.insert(new_id, key_clone);
+                new_id
+            }
+        }
+    }
+}
+
+impl ProjectionId {
+    const EMPTY: ProjectionId = ProjectionId(0);
+
+    fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
+        store.id_to_proj.get(&self).unwrap()
+    }
+
+    fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
+        let mut current = self.lookup(store).to_vec();
+        current.push(projection);
+        store.intern(current.into())
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Place {
     pub local: LocalId,
-    pub projection: Box<[PlaceElem]>,
+    pub projection: ProjectionId,
 }
 
 impl Place {
-    fn is_parent(&self, child: &Place) -> bool {
-        self.local == child.local && child.projection.starts_with(&self.projection)
+    fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
+        self.local == child.local
+            && child.projection.lookup(store).starts_with(&self.projection.lookup(store))
     }
 
     /// 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])
-            .map(|x| Place { local: self.local, projection: x.to_vec().into() })
+    fn iterate_over_parents<'a>(
+        &'a self,
+        store: &'a ProjectionStore,
+    ) -> impl Iterator<Item = Place> + 'a {
+        let projection = self.projection.lookup(store);
+        (0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
+            Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
+        })
     }
 
-    fn project(&self, projection: PlaceElem) -> Place {
-        Place {
-            local: self.local,
-            projection: self.projection.iter().cloned().chain([projection]).collect(),
-        }
+    fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
+        Place { local: self.local, projection: self.projection.project(projection, store) }
     }
 }
 
 impl From<LocalId> for Place {
     fn from(local: LocalId) -> Self {
-        Self { local, projection: vec![].into() }
+        Self { local, projection: ProjectionId::EMPTY }
     }
 }
 
@@ -997,6 +1056,7 @@ pub struct BasicBlock {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct MirBody {
+    pub projection_store: ProjectionStore,
     pub basic_blocks: Arena<BasicBlock>,
     pub locals: Arena<Local>,
     pub start_block: BasicBlockId,
@@ -1009,11 +1069,15 @@ pub struct MirBody {
 }
 
 impl MirBody {
-    fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) {
-        fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) {
+    fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
+        fn for_operand(
+            op: &mut Operand,
+            f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
+            store: &mut ProjectionStore,
+        ) {
             match op {
                 Operand::Copy(p) | Operand::Move(p) => {
-                    f(p);
+                    f(p, store);
                 }
                 Operand::Constant(_) | Operand::Static(_) => (),
             }
@@ -1022,30 +1086,30 @@ impl MirBody {
             for statement in &mut block.statements {
                 match &mut statement.kind {
                     StatementKind::Assign(p, r) => {
-                        f(p);
+                        f(p, &mut self.projection_store);
                         match r {
                             Rvalue::ShallowInitBoxWithAlloc(_) => (),
                             Rvalue::ShallowInitBox(o, _)
                             | Rvalue::UnaryOp(_, o)
                             | Rvalue::Cast(_, o, _)
                             | Rvalue::Repeat(o, _)
-                            | Rvalue::Use(o) => for_operand(o, &mut f),
+                            | Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store),
                             Rvalue::CopyForDeref(p)
                             | Rvalue::Discriminant(p)
                             | Rvalue::Len(p)
-                            | Rvalue::Ref(_, p) => f(p),
+                            | Rvalue::Ref(_, p) => f(p, &mut self.projection_store),
                             Rvalue::CheckedBinaryOp(_, o1, o2) => {
-                                for_operand(o1, &mut f);
-                                for_operand(o2, &mut f);
+                                for_operand(o1, &mut f, &mut self.projection_store);
+                                for_operand(o2, &mut f, &mut self.projection_store);
                             }
                             Rvalue::Aggregate(_, ops) => {
                                 for op in ops.iter_mut() {
-                                    for_operand(op, &mut f);
+                                    for_operand(op, &mut f, &mut self.projection_store);
                                 }
                             }
                         }
                     }
-                    StatementKind::Deinit(p) => f(p),
+                    StatementKind::Deinit(p) => f(p, &mut self.projection_store),
                     StatementKind::StorageLive(_)
                     | StatementKind::StorageDead(_)
                     | StatementKind::Nop => (),
@@ -1053,7 +1117,9 @@ impl MirBody {
             }
             match &mut block.terminator {
                 Some(x) => match &mut x.kind {
-                    TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f),
+                    TerminatorKind::SwitchInt { discr, .. } => {
+                        for_operand(discr, &mut f, &mut self.projection_store)
+                    }
                     TerminatorKind::FalseEdge { .. }
                     | TerminatorKind::FalseUnwind { .. }
                     | TerminatorKind::Goto { .. }
@@ -1063,23 +1129,24 @@ impl MirBody {
                     | TerminatorKind::Return
                     | TerminatorKind::Unreachable => (),
                     TerminatorKind::Drop { place, .. } => {
-                        f(place);
+                        f(place, &mut self.projection_store);
                     }
                     TerminatorKind::DropAndReplace { place, value, .. } => {
-                        f(place);
-                        for_operand(value, &mut f);
+                        f(place, &mut self.projection_store);
+                        for_operand(value, &mut f, &mut self.projection_store);
                     }
                     TerminatorKind::Call { func, args, destination, .. } => {
-                        for_operand(func, &mut f);
-                        args.iter_mut().for_each(|x| for_operand(x, &mut f));
-                        f(destination);
+                        for_operand(func, &mut f, &mut self.projection_store);
+                        args.iter_mut()
+                            .for_each(|x| for_operand(x, &mut f, &mut self.projection_store));
+                        f(destination, &mut self.projection_store);
                     }
                     TerminatorKind::Assert { cond, .. } => {
-                        for_operand(cond, &mut f);
+                        for_operand(cond, &mut f, &mut self.projection_store);
                     }
                     TerminatorKind::Yield { value, resume_arg, .. } => {
-                        for_operand(value, &mut f);
-                        f(resume_arg);
+                        for_operand(value, &mut f, &mut self.projection_store);
+                        f(resume_arg, &mut self.projection_store);
                     }
                 },
                 None => (),
@@ -1096,7 +1163,9 @@ impl MirBody {
             binding_locals,
             param_locals,
             closures,
+            projection_store,
         } = self;
+        projection_store.shrink_to_fit();
         basic_blocks.shrink_to_fit();
         locals.shrink_to_fit();
         binding_locals.shrink_to_fit();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index c70d7f63fd8..41fb129652a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -42,30 +42,27 @@ pub struct BorrowckResult {
 fn all_mir_bodies(
     db: &dyn HirDatabase,
     def: DefWithBodyId,
-) -> Box<dyn Iterator<Item = Result<Arc<MirBody>, MirLowerError>> + '_> {
+    mut cb: impl FnMut(Arc<MirBody>),
+) -> Result<(), MirLowerError> {
     fn for_closure(
         db: &dyn HirDatabase,
         c: ClosureId,
-    ) -> Box<dyn Iterator<Item = Result<Arc<MirBody>, MirLowerError>> + '_> {
+        cb: &mut impl FnMut(Arc<MirBody>),
+    ) -> Result<(), MirLowerError> {
         match db.mir_body_for_closure(c) {
             Ok(body) => {
-                let closures = body.closures.clone();
-                Box::new(
-                    iter::once(Ok(body))
-                        .chain(closures.into_iter().flat_map(|it| for_closure(db, it))),
-                )
+                cb(body.clone());
+                body.closures.iter().map(|&it| for_closure(db, it, cb)).collect()
             }
-            Err(e) => Box::new(iter::once(Err(e))),
+            Err(e) => Err(e),
         }
     }
     match db.mir_body(def) {
         Ok(body) => {
-            let closures = body.closures.clone();
-            Box::new(
-                iter::once(Ok(body)).chain(closures.into_iter().flat_map(|it| for_closure(db, it))),
-            )
+            cb(body.clone());
+            body.closures.iter().map(|&it| for_closure(db, it, &mut cb)).collect()
         }
-        Err(e) => Box::new(iter::once(Err(e))),
+        Err(e) => Err(e),
     }
 }
 
@@ -74,17 +71,15 @@ pub fn borrowck_query(
     def: DefWithBodyId,
 ) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
     let _p = profile::span("borrowck_query");
-    let r = all_mir_bodies(db, def)
-        .map(|body| {
-            let body = body?;
-            Ok(BorrowckResult {
-                mutability_of_locals: mutability_of_locals(db, &body),
-                moved_out_of_ref: moved_out_of_ref(db, &body),
-                mir_body: body,
-            })
-        })
-        .collect::<Result<Vec<_>, MirLowerError>>()?;
-    Ok(r.into())
+    let mut res = vec![];
+    all_mir_bodies(db, def, |body| {
+        res.push(BorrowckResult {
+            mutability_of_locals: mutability_of_locals(db, &body),
+            moved_out_of_ref: moved_out_of_ref(db, &body),
+            mir_body: body,
+        });
+    })?;
+    Ok(res.into())
 }
 
 fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> {
@@ -93,7 +88,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
         Operand::Copy(p) | Operand::Move(p) => {
             let mut ty: Ty = body.locals[p.local].ty.clone();
             let mut is_dereference_of_ref = false;
-            for proj in &*p.projection {
+            for proj in p.projection.lookup(&body.projection_store) {
                 if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
                     is_dereference_of_ref = true;
                 }
@@ -125,6 +120,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
         Operand::Constant(_) | Operand::Static(_) => (),
     };
     for (_, block) in body.basic_blocks.iter() {
+        db.unwind_if_cancelled();
         for statement in &block.statements {
             match &statement.kind {
                 StatementKind::Assign(_, r) => match r {
@@ -183,6 +179,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
             None => (),
         }
     }
+    result.shrink_to_fit();
     result
 }
 
@@ -199,7 +196,7 @@ enum ProjectionCase {
 fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
     let mut is_part_of = false;
     let mut ty = body.locals[lvalue.local].ty.clone();
-    for proj in lvalue.projection.iter() {
+    for proj in lvalue.projection.lookup(&body.projection_store).iter() {
         match proj {
             ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
             ProjectionElem::Deref // It's direct in case of `Box<T>`
@@ -258,7 +255,7 @@ fn ever_initialized_map(
         for statement in &block.statements {
             match &statement.kind {
                 StatementKind::Assign(p, _) => {
-                    if p.projection.len() == 0 && p.local == l {
+                    if p.projection.lookup(&body.projection_store).len() == 0 && p.local == l {
                         is_ever_initialized = true;
                     }
                 }
@@ -277,21 +274,37 @@ fn ever_initialized_map(
             );
             return;
         };
-        let targets = match &terminator.kind {
-            TerminatorKind::Goto { target } => vec![*target],
-            TerminatorKind::SwitchInt { targets, .. } => targets.all_targets().to_vec(),
+        let mut process = |target, is_ever_initialized| {
+            if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
+                result[target].insert(l, is_ever_initialized);
+                dfs(db, body, target, l, result);
+            }
+        };
+        match &terminator.kind {
+            TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
+            TerminatorKind::SwitchInt { targets, .. } => {
+                targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
+            }
             TerminatorKind::UnwindResume
             | TerminatorKind::Abort
             | TerminatorKind::Return
-            | TerminatorKind::Unreachable => vec![],
+            | TerminatorKind::Unreachable => (),
             TerminatorKind::Call { target, cleanup, destination, .. } => {
-                if destination.projection.len() == 0 && destination.local == l {
+                if destination.projection.lookup(&body.projection_store).len() == 0
+                    && destination.local == l
+                {
                     is_ever_initialized = true;
                 }
-                target.into_iter().chain(cleanup.into_iter()).copied().collect()
+                target
+                    .into_iter()
+                    .chain(cleanup.into_iter())
+                    .for_each(|&it| process(it, is_ever_initialized));
             }
             TerminatorKind::Drop { target, unwind, place: _ } => {
-                Some(target).into_iter().chain(unwind.into_iter()).copied().collect()
+                iter::once(target)
+                    .into_iter()
+                    .chain(unwind.into_iter())
+                    .for_each(|&it| process(it, is_ever_initialized));
             }
             TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Assert { .. }
@@ -300,13 +313,7 @@ fn ever_initialized_map(
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. } => {
                 never!("We don't emit these MIR terminators yet");
-                vec![]
-            }
-        };
-        for target in targets {
-            if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
-                result[target].insert(l, is_ever_initialized);
-                dfs(db, body, target, l, result);
+                ()
             }
         }
     }
@@ -315,6 +322,7 @@ fn ever_initialized_map(
         dfs(db, body, body.start_block, l, &mut result);
     }
     for l in body.locals.iter().map(|it| it.0) {
+        db.unwind_if_cancelled();
         if !result[body.start_block].contains_idx(l) {
             result[body.start_block].insert(l, false);
             dfs(db, body, body.start_block, l, &mut result);
@@ -384,7 +392,7 @@ fn mutability_of_locals(
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Yield { .. } => (),
             TerminatorKind::Call { destination, .. } => {
-                if destination.projection.len() == 0 {
+                if destination.projection.lookup(&body.projection_store).len() == 0 {
                     if ever_init_map.get(destination.local).copied().unwrap_or_default() {
                         push_mut_span(destination.local, MirSpan::Unknown);
                     } else {
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 3944feb128c..4364e0d323b 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
@@ -46,8 +46,8 @@ use crate::{
 
 use super::{
     return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
-    MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind,
-    UnOp,
+    MirSpan, Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind,
+    TerminatorKind, UnOp,
 };
 
 mod shim;
@@ -215,9 +215,7 @@ impl Interval {
     }
 
     fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> {
-        // FIXME: this could be more efficient
-        let bytes = &interval.get(memory)?.to_vec();
-        memory.write_memory(self.addr, bytes)
+        memory.copy_from_interval(self.addr, interval)
     }
 
     fn slice(self, range: Range<usize>) -> Interval {
@@ -341,7 +339,7 @@ pub enum MirEvalError {
     InvalidVTableId(usize),
     CoerceUnsizedError(Ty),
     LangItemNotFound(LangItem),
-    BrokenLayout(Layout),
+    BrokenLayout(Box<Layout>),
 }
 
 impl MirEvalError {
@@ -410,7 +408,7 @@ impl MirEvalError {
                 err.pretty_print(f, db, span_formatter)?;
             }
             MirEvalError::ConstEvalError(name, err) => {
-                MirLowerError::ConstEvalError(name.clone(), err.clone()).pretty_print(
+                MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
                     f,
                     db,
                     span_formatter,
@@ -485,17 +483,18 @@ struct DropFlags {
 }
 
 impl DropFlags {
-    fn add_place(&mut self, p: Place) {
-        if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {
+    fn add_place(&mut self, p: Place, store: &ProjectionStore) {
+        if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) {
             return;
         }
-        self.need_drop.retain(|it| !p.is_parent(it));
+        self.need_drop.retain(|it| !p.is_parent(it, store));
         self.need_drop.insert(p);
     }
 
-    fn remove_place(&mut self, p: &Place) -> bool {
+    fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool {
         // FIXME: replace parents with parts
-        if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) {
+        if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(&it))
+        {
             self.need_drop.remove(&parent);
             return true;
         }
@@ -656,7 +655,7 @@ impl Evaluator<'_> {
         let mut addr = locals.ptr[p.local].addr;
         let mut ty: Ty = locals.body.locals[p.local].ty.clone();
         let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
-        for proj in &*p.projection {
+        for proj in p.projection.lookup(&locals.body.projection_store) {
             let prev_ty = ty.clone();
             ty = self.projected_ty(ty, proj.clone());
             match proj {
@@ -837,7 +836,9 @@ impl Evaluator<'_> {
                                 let addr = self.place_addr(l, &locals)?;
                                 let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
                                 self.write_memory(addr, &result)?;
-                                locals.drop_flags.add_place(l.clone());
+                                locals
+                                    .drop_flags
+                                    .add_place(l.clone(), &locals.body.projection_store);
                             }
                             StatementKind::Deinit(_) => not_supported!("de-init statement"),
                             StatementKind::StorageLive(_)
@@ -889,7 +890,9 @@ impl Evaluator<'_> {
                                 )?,
                                 it => not_supported!("unknown function type {it:?}"),
                             };
-                            locals.drop_flags.add_place(destination.clone());
+                            locals
+                                .drop_flags
+                                .add_place(destination.clone(), &locals.body.projection_store);
                             if let Some(stack_frame) = stack_frame {
                                 self.code_stack.push(my_stack_frame);
                                 current_block_idx = stack_frame.locals.body.start_block;
@@ -970,7 +973,7 @@ impl Evaluator<'_> {
     ) -> Result<()> {
         let mut remain_args = body.param_locals.len();
         for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
-            locals.drop_flags.add_place(l.into());
+            locals.drop_flags.add_place(l.into(), &locals.body.projection_store);
             match value {
                 IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
                 IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
@@ -1629,7 +1632,7 @@ impl Evaluator<'_> {
         if let Some((offset, size, value)) = tag {
             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())),
+                None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))),
             }
         }
         for (i, op) in values.enumerate() {
@@ -1637,7 +1640,7 @@ impl Evaluator<'_> {
             let op = op.get(&self)?;
             match result.get_mut(offset..offset + op.len()) {
                 Some(it) => it.copy_from_slice(op),
-                None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+                None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))),
             }
         }
         Ok(result)
@@ -1646,7 +1649,7 @@ impl Evaluator<'_> {
     fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<Interval> {
         Ok(match it {
             Operand::Copy(p) | Operand::Move(p) => {
-                locals.drop_flags.remove_place(p);
+                locals.drop_flags.remove_place(p, &locals.body.projection_store);
                 self.eval_place(p, locals)?
             }
             Operand::Static(st) => {
@@ -1760,6 +1763,48 @@ impl Evaluator<'_> {
         Ok(())
     }
 
+    fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<()> {
+        if r.size == 0 {
+            return Ok(());
+        }
+
+        let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_string());
+
+        match (addr, r.addr) {
+            (Stack(dst), Stack(src)) => {
+                if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
+                    return Err(oob());
+                }
+                self.stack.copy_within(src..src + r.size, dst)
+            }
+            (Heap(dst), Heap(src)) => {
+                if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
+                    return Err(oob());
+                }
+                self.heap.copy_within(src..src + r.size, dst)
+            }
+            (Stack(dst), Heap(src)) => {
+                self.stack
+                    .get_mut(dst..dst + r.size)
+                    .ok_or_else(oob)?
+                    .copy_from_slice(self.heap.get(src..src + r.size).ok_or_else(oob)?);
+            }
+            (Heap(dst), Stack(src)) => {
+                self.heap
+                    .get_mut(dst..dst + r.size)
+                    .ok_or_else(oob)?
+                    .copy_from_slice(self.stack.get(src..src + r.size).ok_or_else(oob)?);
+            }
+            _ => {
+                return Err(MirEvalError::UndefinedBehavior(format!(
+                    "invalid memory write at address {addr:?}"
+                )))
+            }
+        }
+
+        Ok(())
+    }
+
     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
@@ -2468,7 +2513,7 @@ impl Evaluator<'_> {
 
     fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> {
         let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
-        if !locals.drop_flags.remove_place(place) {
+        if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
             return Ok(());
         }
         let metadata = match metadata {
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 52943e97ac0..803ef631f1e 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
@@ -4,7 +4,10 @@
 use std::cmp;
 
 use chalk_ir::TyKind;
-use hir_def::resolver::HasResolver;
+use hir_def::{
+    builtin_type::{BuiltinInt, BuiltinUint},
+    resolver::HasResolver,
+};
 use hir_expand::mod_path::ModPath;
 
 use super::*;
@@ -300,21 +303,36 @@ impl Evaluator<'_> {
             BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_string())),
             PanicFmt => {
                 let message = (|| {
-                    let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db.upcast());
+                    let resolver = self
+                        .db
+                        .crate_def_map(self.crate_id)
+                        .crate_root()
+                        .resolver(self.db.upcast());
                     let Some(format_fn) = resolver.resolve_path_in_value_ns_fully(
                         self.db.upcast(),
-                        &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments(
-                            hir_expand::mod_path::PathKind::Abs,
-                            [name![std], name![fmt], name![format]].into_iter(),
-                        )),
+                        &hir_def::path::Path::from_known_path_with_no_generic(
+                            ModPath::from_segments(
+                                hir_expand::mod_path::PathKind::Abs,
+                                [name![std], name![fmt], name![format]].into_iter(),
+                            ),
+                        ),
                     ) else {
                         not_supported!("std::fmt::format not found");
                     };
-                    let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") };
-                    let message_string = self.interpret_mir(self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())))?;
-                    let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
+                    let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else {
+                        not_supported!("std::fmt::format is not a function")
+                    };
+                    let message_string = self.interpret_mir(
+                        self.db
+                            .mir_body(format_fn.into())
+                            .map_err(|e| MirEvalError::MirLowerError(format_fn, e))?,
+                        args.map(|x| IntervalOrOwned::Owned(x.clone())),
+                    )?;
+                    let addr =
+                        Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
                     let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]);
-                    Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned())
+                    Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?)
+                        .into_owned())
                 })()
                 .unwrap_or_else(|e| format!("Failed to render panic format args: {e:?}"));
                 Err(MirEvalError::Panic(message))
@@ -483,9 +501,7 @@ impl Evaluator<'_> {
             }
             "syscall" => {
                 let Some((id, rest)) = args.split_first() else {
-                    return Err(MirEvalError::TypeError(
-                        "syscall arg1 is not provided",
-                    ));
+                    return Err(MirEvalError::TypeError("syscall arg1 is not provided"));
                 };
                 let id = from_bytes!(i64, id.get(self)?);
                 self.exec_syscall(id, rest, destination, locals, span)
@@ -710,7 +726,8 @@ impl Evaluator<'_> {
         }
         match name {
             "size_of" => {
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::TypeError("size_of generic arg is not provided"));
                 };
@@ -718,14 +735,17 @@ impl Evaluator<'_> {
                 destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size])
             }
             "min_align_of" | "pref_align_of" => {
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                else {
                     return Err(MirEvalError::TypeError("align_of generic arg is not provided"));
                 };
                 let align = self.layout(ty)?.align.abi.bytes();
                 destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size])
             }
             "size_of_val" => {
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::TypeError("size_of_val generic arg is not provided"));
                 };
@@ -741,8 +761,12 @@ impl Evaluator<'_> {
                 }
             }
             "min_align_of_val" => {
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
-                    return Err(MirEvalError::TypeError("min_align_of_val generic arg is not provided"));
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                else {
+                    return Err(MirEvalError::TypeError(
+                        "min_align_of_val generic arg is not provided",
+                    ));
                 };
                 let [arg] = args else {
                     return Err(MirEvalError::TypeError("min_align_of_val args are not provided"));
@@ -756,7 +780,8 @@ impl Evaluator<'_> {
                 }
             }
             "type_name" => {
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
                 };
@@ -779,7 +804,8 @@ impl Evaluator<'_> {
                     .write_from_bytes(self, &len.to_le_bytes())
             }
             "needs_drop" => {
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::TypeError("size_of generic arg is not provided"));
                 };
@@ -831,9 +857,12 @@ impl Evaluator<'_> {
                 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))
+                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"));
+                    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;
@@ -940,7 +969,8 @@ impl Evaluator<'_> {
                         "copy_nonoverlapping args are not provided",
                     ));
                 };
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::TypeError(
                         "copy_nonoverlapping generic arg is not provided",
@@ -959,9 +989,45 @@ impl Evaluator<'_> {
                 let [ptr, offset] = args else {
                     return Err(MirEvalError::TypeError("offset args are not provided"));
                 };
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
-                else {
-                    return Err(MirEvalError::TypeError("offset generic arg is not provided"));
+                let ty = if name == "offset" {
+                    let Some(ty0) =
+                        generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                    else {
+                        return Err(MirEvalError::TypeError("offset generic arg is not provided"));
+                    };
+                    let Some(ty1) =
+                        generic_args.as_slice(Interner).get(1).and_then(|it| it.ty(Interner))
+                    else {
+                        return Err(MirEvalError::TypeError("offset generic arg is not provided"));
+                    };
+                    if !matches!(
+                        ty1.as_builtin(),
+                        Some(
+                            BuiltinType::Int(BuiltinInt::Isize)
+                                | BuiltinType::Uint(BuiltinUint::Usize)
+                        )
+                    ) {
+                        return Err(MirEvalError::TypeError(
+                            "offset generic arg is not usize or isize",
+                        ));
+                    }
+                    match ty0.as_raw_ptr() {
+                        Some((ty, _)) => ty,
+                        None => {
+                            return Err(MirEvalError::TypeError(
+                                "offset generic arg is not a raw pointer",
+                            ));
+                        }
+                    }
+                } else {
+                    let Some(ty) =
+                        generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                    else {
+                        return Err(MirEvalError::TypeError(
+                            "arith_offset generic arg is not provided",
+                        ));
+                    };
+                    ty
                 };
                 let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, false));
                 let offset = u128::from_le_bytes(pad16(offset.get(self)?, false));
@@ -1079,7 +1145,8 @@ impl Evaluator<'_> {
                 let [arg] = args else {
                     return Err(MirEvalError::TypeError("discriminant_value arg is not provided"));
                 };
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::TypeError(
                         "discriminant_value generic arg is not provided",
@@ -1133,17 +1200,32 @@ impl Evaluator<'_> {
                 let addr = Address::from_bytes(arg.interval.get(self)?)?;
                 destination.write_from_interval(self, Interval { addr, size: destination.size })
             }
+            "write_via_move" => {
+                let [ptr, val] = args else {
+                    return Err(MirEvalError::TypeError("write_via_move args are not provided"));
+                };
+                let dst = Address::from_bytes(ptr.get(self)?)?;
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                else {
+                    return Err(MirEvalError::TypeError(
+                        "write_via_copy generic arg is not provided",
+                    ));
+                };
+                let size = self.size_of_sized(ty, locals, "write_via_move ptr type")?;
+                Interval { addr: dst, size }.write_from_interval(self, val.interval)?;
+                Ok(())
+            }
             "write_bytes" => {
                 let [dst, val, count] = args else {
                     return Err(MirEvalError::TypeError("write_bytes args are not provided"));
                 };
                 let count = from_bytes!(usize, count.get(self)?);
                 let val = from_bytes!(u8, val.get(self)?);
-                let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                let Some(ty) =
+                    generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
                 else {
-                    return Err(MirEvalError::TypeError(
-                        "write_bytes generic arg is not provided",
-                    ));
+                    return Err(MirEvalError::TypeError("write_bytes generic arg is not provided"));
                 };
                 let dst = Address::from_bytes(dst.get(self)?)?;
                 let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
index ec746310487..51900662426 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -45,7 +45,9 @@ impl Evaluator<'_> {
                 };
                 match try_const_usize(self.db, len) {
                     Some(len) => {
-                        let Some(ty) = subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
+                        let Some(ty) =
+                            subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+                        else {
                             return Err(MirEvalError::TypeError("simd type with no ty param"));
                         };
                         Ok((len as usize, ty.clone()))
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 51cf882d053..dd2dba717f9 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
@@ -71,7 +71,7 @@ struct MirLowerCtx<'a> {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum MirLowerError {
-    ConstEvalError(String, Box<ConstEvalError>),
+    ConstEvalError(Box<str>, Box<ConstEvalError>),
     LayoutError(LayoutError),
     IncompleteExpr,
     IncompletePattern,
@@ -84,7 +84,7 @@ pub enum MirLowerError {
     UnsizedTemporary(Ty),
     MissingFunctionDefinition(DefWithBodyId, ExprId),
     TypeMismatch(TypeMismatch),
-    /// This should be never happen. Type mismatch should catch everything.
+    /// This should never happen. Type mismatch should catch everything.
     TypeError(&'static str),
     NotSupported(String),
     ContinueWithoutLoop,
@@ -244,6 +244,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         let locals = Arena::new();
         let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();
         let mir = MirBody {
+            projection_store: ProjectionStore::default(),
             basic_blocks,
             locals,
             start_block,
@@ -370,6 +371,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
         mut current: BasicBlockId,
     ) -> Result<Option<BasicBlockId>> {
         match &self.body.exprs[expr_id] {
+            Expr::OffsetOf(_) => {
+                not_supported!("builtin#offset_of")
+            }
+            Expr::InlineAsm(_) => {
+                not_supported!("builtin#asm")
+            }
             Expr::Missing => {
                 if let DefWithBodyId::FunctionId(f) = self.owner {
                     let assoc = f.lookup(self.db.upcast());
@@ -803,36 +810,34 @@ impl<'ctx> MirLowerCtx<'ctx> {
                             current = c;
                             operands[u32::from(field_id.into_raw()) as usize] = Some(op);
                         }
-                        self.push_assignment(
-                            current,
-                            place,
-                            Rvalue::Aggregate(
-                                AggregateKind::Adt(variant_id, subst),
-                                match spread_place {
-                                    Some(sp) => operands
-                                        .into_iter()
-                                        .enumerate()
-                                        .map(|(i, it)| match it {
-                                            Some(it) => it,
-                                            None => {
-                                                let p =
-                                                    sp.project(ProjectionElem::Field(FieldId {
-                                                        parent: variant_id,
-                                                        local_id: LocalFieldId::from_raw(
-                                                            RawIdx::from(i as u32),
-                                                        ),
-                                                    }));
-                                                Operand::Copy(p)
-                                            }
-                                        })
-                                        .collect(),
-                                    None => operands.into_iter().collect::<Option<_>>().ok_or(
-                                        MirLowerError::TypeError("missing field in record literal"),
-                                    )?,
-                                },
-                            ),
-                            expr_id.into(),
+                        let rvalue = Rvalue::Aggregate(
+                            AggregateKind::Adt(variant_id, subst),
+                            match spread_place {
+                                Some(sp) => operands
+                                    .into_iter()
+                                    .enumerate()
+                                    .map(|(i, it)| match it {
+                                        Some(it) => it,
+                                        None => {
+                                            let p = sp.project(
+                                                ProjectionElem::Field(FieldId {
+                                                    parent: variant_id,
+                                                    local_id: LocalFieldId::from_raw(RawIdx::from(
+                                                        i as u32,
+                                                    )),
+                                                }),
+                                                &mut self.result.projection_store,
+                                            );
+                                            Operand::Copy(p)
+                                        }
+                                    })
+                                    .collect(),
+                                None => operands.into_iter().collect::<Option<_>>().ok_or(
+                                    MirLowerError::TypeError("missing field in record literal"),
+                                )?,
+                            },
                         );
+                        self.push_assignment(current, place, rvalue, expr_id.into());
                         Ok(Some(current))
                     }
                     VariantId::UnionId(union_id) => {
@@ -841,10 +846,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         };
                         let local_id =
                             variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
-                        let place = place.project(PlaceElem::Field(FieldId {
-                            parent: union_id.into(),
-                            local_id,
-                        }));
+                        let place = place.project(
+                            PlaceElem::Field(FieldId { parent: union_id.into(), local_id }),
+                            &mut self.result.projection_store,
+                        );
                         self.lower_expr_to_place(*expr, place, current)
                     }
                 }
@@ -898,7 +903,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 else {
                     return Ok(None);
                 };
-                let p = place.project(ProjectionElem::Deref);
+                let p = place.project(ProjectionElem::Deref, &mut self.result.projection_store);
                 self.push_assignment(current, p, operand.into(), expr_id.into());
                 Ok(Some(current))
             }
@@ -1120,27 +1125,31 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 for capture in captures.iter() {
                     let p = Place {
                         local: self.binding_local(capture.place.local)?,
-                        projection: capture
-                            .place
-                            .projections
-                            .clone()
-                            .into_iter()
-                            .map(|it| match it {
-                                ProjectionElem::Deref => ProjectionElem::Deref,
-                                ProjectionElem::Field(it) => ProjectionElem::Field(it),
-                                ProjectionElem::TupleOrClosureField(it) => {
-                                    ProjectionElem::TupleOrClosureField(it)
-                                }
-                                ProjectionElem::ConstantIndex { offset, from_end } => {
-                                    ProjectionElem::ConstantIndex { offset, from_end }
-                                }
-                                ProjectionElem::Subslice { from, to } => {
-                                    ProjectionElem::Subslice { from, to }
-                                }
-                                ProjectionElem::OpaqueCast(it) => ProjectionElem::OpaqueCast(it),
-                                ProjectionElem::Index(it) => match it {},
-                            })
-                            .collect(),
+                        projection: self.result.projection_store.intern(
+                            capture
+                                .place
+                                .projections
+                                .clone()
+                                .into_iter()
+                                .map(|it| match it {
+                                    ProjectionElem::Deref => ProjectionElem::Deref,
+                                    ProjectionElem::Field(it) => ProjectionElem::Field(it),
+                                    ProjectionElem::TupleOrClosureField(it) => {
+                                        ProjectionElem::TupleOrClosureField(it)
+                                    }
+                                    ProjectionElem::ConstantIndex { offset, from_end } => {
+                                        ProjectionElem::ConstantIndex { offset, from_end }
+                                    }
+                                    ProjectionElem::Subslice { from, to } => {
+                                        ProjectionElem::Subslice { from, to }
+                                    }
+                                    ProjectionElem::OpaqueCast(it) => {
+                                        ProjectionElem::OpaqueCast(it)
+                                    }
+                                    ProjectionElem::Index(it) => match it {},
+                                })
+                                .collect(),
+                        ),
                     };
                     match &capture.kind {
                         CaptureKind::ByRef(bk) => {
@@ -1201,7 +1210,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     let Some(values) = elements
                         .iter()
                         .map(|it| {
-                            let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else {
+                            let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)?
+                            else {
                                 return Ok(None);
                             };
                             current = c;
@@ -1254,12 +1264,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
         match &self.body.exprs[lhs] {
             Expr::Tuple { exprs, is_assignee_expr: _ } => {
                 for (i, expr) in exprs.iter().enumerate() {
-                    let Some(c) = self.lower_destructing_assignment(
-                        current,
-                        *expr,
-                        rhs.project(ProjectionElem::TupleOrClosureField(i)),
-                        span,
-                    )? else {
+                    let rhs = rhs.project(
+                        ProjectionElem::TupleOrClosureField(i),
+                        &mut self.result.projection_store,
+                    );
+                    let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
+                    else {
                         return Ok(None);
                     };
                     current = c;
@@ -1268,8 +1278,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             }
             Expr::Underscore => Ok(Some(current)),
             _ => {
-                let Some((lhs_place, current)) =
-                    self.lower_expr_as_place(current, lhs, false)?
+                let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)?
                 else {
                     return Ok(None);
                 };
@@ -1286,9 +1295,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         rhs: ExprId,
         span: MirSpan,
     ) -> Result<Option<BasicBlockId>> {
-        let Some((rhs_op, current)) =
-            self.lower_expr_to_some_operand(rhs, current)?
-        else {
+        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) {
@@ -1303,9 +1310,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             self.push_assignment(current, temp.clone(), rhs_op.into(), span);
             return self.lower_destructing_assignment(current, lhs, temp, span);
         }
-        let Some((lhs_place, current)) =
-            self.lower_expr_as_place(current, lhs, false)?
-        else {
+        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);
@@ -1320,17 +1325,21 @@ impl<'ctx> MirLowerCtx<'ctx> {
         placeholder_subst
     }
 
-    fn push_field_projection(&self, place: &mut Place, expr_id: ExprId) -> Result<()> {
+    fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> {
         if let Expr::Field { expr, name } = &self.body[expr_id] {
             if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) {
                 let index = name
                     .as_tuple_index()
                     .ok_or(MirLowerError::TypeError("named field on tuple"))?;
-                *place = place.project(ProjectionElem::TupleOrClosureField(index))
+                *place = place.project(
+                    ProjectionElem::TupleOrClosureField(index),
+                    &mut self.result.projection_store,
+                )
             } else {
                 let field =
                     self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?;
-                *place = place.project(ProjectionElem::Field(field));
+                *place =
+                    place.project(ProjectionElem::Field(field), &mut self.result.projection_store);
             }
         } else {
             not_supported!("")
@@ -1447,7 +1456,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             let name = const_id.name(self.db.upcast());
             self.db
                 .const_eval(const_id.into(), subst, None)
-                .map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
+                .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))?
         };
         Ok(Operand::Constant(c))
     }
@@ -1844,7 +1853,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     data.name.display(self.db.upcast()),
                     data.variants[variant.local_id].name.display(self.db.upcast())
                 );
-                Err(MirLowerError::ConstEvalError(name, Box::new(e)))
+                Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
             }
         }
     }
@@ -1992,13 +2001,14 @@ pub fn mir_body_for_closure_query(
         FnTrait::FnOnce => vec![],
         FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref],
     };
-    ctx.result.walk_places(|p| {
+    ctx.result.walk_places(|p, store| {
         if let Some(it) = upvar_map.get(&p.local) {
             let r = it.iter().find(|it| {
-                if p.projection.len() < it.0.place.projections.len() {
+                if p.projection.lookup(&store).len() < it.0.place.projections.len() {
                     return false;
                 }
-                for (it, y) in p.projection.iter().zip(it.0.place.projections.iter()) {
+                for (it, y) in p.projection.lookup(&store).iter().zip(it.0.place.projections.iter())
+                {
                     match (it, y) {
                         (ProjectionElem::Deref, ProjectionElem::Deref) => (),
                         (ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (),
@@ -2016,13 +2026,18 @@ pub fn mir_body_for_closure_query(
                     p.local = closure_local;
                     let mut next_projs = closure_projection.clone();
                     next_projs.push(PlaceElem::TupleOrClosureField(it.1));
-                    let prev_projs = mem::take(&mut p.projection);
+                    let prev_projs = p.projection;
                     if it.0.kind != CaptureKind::ByValue {
                         next_projs.push(ProjectionElem::Deref);
                     }
-                    next_projs
-                        .extend(prev_projs.iter().cloned().skip(it.0.place.projections.len()));
-                    p.projection = next_projs.into();
+                    next_projs.extend(
+                        prev_projs
+                            .lookup(&store)
+                            .iter()
+                            .cloned()
+                            .skip(it.0.place.projections.len()),
+                    );
+                    p.projection = store.intern(next_projs.into());
                 }
                 None => err = Some(p.clone()),
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index 213f151ab67..8c078eb4ad7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -70,7 +70,7 @@ impl MirLowerCtx<'_> {
                     else {
                         return Ok(None);
                     };
-                    it.0 = it.0.project(ProjectionElem::Deref);
+                    it.0 = it.0.project(ProjectionElem::Deref, &mut self.result.projection_store);
                     Ok(Some(it))
                 }
                 Adjust::Deref(Some(od)) => {
@@ -152,7 +152,10 @@ impl MirLowerCtx<'_> {
                             Operand::Static(s).into(),
                             expr_id.into(),
                         );
-                        Ok(Some((temp.project(ProjectionElem::Deref), current)))
+                        Ok(Some((
+                            temp.project(ProjectionElem::Deref, &mut self.result.projection_store),
+                            current,
+                        )))
                     }
                     _ => try_rvalue(self),
                 }
@@ -203,7 +206,7 @@ impl MirLowerCtx<'_> {
                     else {
                         return Ok(None);
                     };
-                    r = r.project(ProjectionElem::Deref);
+                    r = r.project(ProjectionElem::Deref, &mut self.result.projection_store);
                     Ok(Some((r, current)))
                 }
                 _ => try_rvalue(self),
@@ -267,7 +270,8 @@ impl MirLowerCtx<'_> {
                 else {
                     return Ok(None);
                 };
-                p_base = p_base.project(ProjectionElem::Index(l_index));
+                p_base = p_base
+                    .project(ProjectionElem::Index(l_index), &mut self.result.projection_store);
                 Ok(Some((p_base, current)))
             }
             _ => try_rvalue(self),
@@ -308,7 +312,7 @@ impl MirLowerCtx<'_> {
         else {
             return Ok(None);
         };
-        result = result.project(ProjectionElem::Deref);
+        result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
         Ok(Some((result, current)))
     }
 
@@ -363,7 +367,7 @@ impl MirLowerCtx<'_> {
         else {
             return Ok(None);
         };
-        result = result.project(ProjectionElem::Deref);
+        result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
         Ok(Some((result, current)))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 1cdfd919742..270f75ad967 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -81,13 +81,16 @@ impl MirLowerCtx<'_> {
         mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
         let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
-        cond_place.projection = cond_place
-            .projection
-            .iter()
-            .cloned()
-            .chain((0..cnt).map(|_| ProjectionElem::Deref))
-            .collect::<Vec<_>>()
-            .into();
+        cond_place.projection = self.result.projection_store.intern(
+            cond_place
+                .projection
+                .lookup(&self.result.projection_store)
+                .iter()
+                .cloned()
+                .chain((0..cnt).map(|_| ProjectionElem::Deref))
+                .collect::<Vec<_>>()
+                .into(),
+        );
         Ok(match &self.body.pats[pattern] {
             Pat::Missing => return Err(MirLowerError::IncompletePattern),
             Pat::Wild => (current, current_else),
@@ -262,20 +265,23 @@ impl MirLowerCtx<'_> {
                     }
                 }
                 for (i, &pat) in prefix.iter().enumerate() {
-                    let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
-                        offset: i as u64,
-                        from_end: false,
-                    });
+                    let next_place = (&mut cond_place).project(
+                        ProjectionElem::ConstantIndex { offset: i as u64, from_end: false },
+                        &mut self.result.projection_store,
+                    );
                     (current, current_else) =
                         self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
                 }
                 if let Some(slice) = slice {
                     if mode == MatchingMode::Bind {
                         if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
-                            let next_place = (&mut cond_place).project(ProjectionElem::Subslice {
-                                from: prefix.len() as u64,
-                                to: suffix.len() as u64,
-                            });
+                            let next_place = (&mut cond_place).project(
+                                ProjectionElem::Subslice {
+                                    from: prefix.len() as u64,
+                                    to: suffix.len() as u64,
+                                },
+                                &mut self.result.projection_store,
+                            );
                             (current, current_else) = self.pattern_match_binding(
                                 id,
                                 next_place,
@@ -287,10 +293,10 @@ impl MirLowerCtx<'_> {
                     }
                 }
                 for (i, &pat) in suffix.iter().enumerate() {
-                    let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
-                        offset: i as u64,
-                        from_end: true,
-                    });
+                    let next_place = (&mut cond_place).project(
+                        ProjectionElem::ConstantIndex { offset: i as u64, from_end: true },
+                        &mut self.result.projection_store,
+                    );
                     (current, current_else) =
                         self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
                 }
@@ -412,13 +418,11 @@ impl MirLowerCtx<'_> {
                     mode,
                 )?
             }
-            Pat::Ref { pat, mutability: _ } => self.pattern_match_inner(
-                current,
-                current_else,
-                cond_place.project(ProjectionElem::Deref),
-                *pat,
-                mode,
-            )?,
+            Pat::Ref { pat, mutability: _ } => {
+                let cond_place =
+                    cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
+                self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
+            }
             Pat::Box { .. } => not_supported!("box pattern"),
             Pat::ConstBlock(_) => not_supported!("const block pattern"),
         })
@@ -594,7 +598,7 @@ impl MirLowerCtx<'_> {
         mode: MatchingMode,
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
         for (proj, arg) in args {
-            let cond_place = cond_place.project(proj);
+            let cond_place = cond_place.project(proj, &mut self.result.projection_store);
             (current, current_else) =
                 self.pattern_match_inner(current, current_else, cond_place, arg, mode)?;
         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 781ffaecad5..0108859ff32 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -329,7 +329,7 @@ impl<'a> MirPrettyCtx<'a> {
                 }
             }
         }
-        f(self, p.local, &p.projection);
+        f(self, p.local, &p.projection.lookup(&self.body.projection_store));
     }
 
     fn operand(&mut self, r: &Operand) {
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 2ad7946c8ac..8140c4107b8 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
@@ -3,55 +3,6 @@ use expect_test::expect;
 use super::{check, check_infer, check_no_mismatches, check_types};
 
 #[test]
-fn infer_box() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:std
-fn test() {
-    let x = box 1;
-    let t = (x, box x, box &1, box [1]);
-    t;
-} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
-
-//- /std.rs crate:std
-#[prelude_import] use prelude::*;
-mod prelude {}
-
-mod boxed {
-    #[lang = "owned_box"]
-    pub struct Box<T: ?Sized> {
-        inner: *mut T,
-    }
-}
-"#,
-    );
-}
-
-#[test]
-fn infer_box_with_allocator() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:std
-fn test() {
-    let x = box 1;
-    let t = (x, box x, box &1, box [1]);
-    t;
-} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
-
-//- /std.rs crate:std
-#[prelude_import] use prelude::*;
-mod boxed {
-    #[lang = "owned_box"]
-    pub struct Box<T: ?Sized, A: Allocator> {
-        inner: *mut T,
-        allocator: A,
-    }
-}
-"#,
-    );
-}
-
-#[test]
 fn infer_adt_self() {
     check_types(
         r#"
@@ -2763,8 +2714,8 @@ impl<T> [T] {
 }
 
 fn test() {
-    let vec = <[_]>::into_vec(box [1i32]);
-    let v: Vec<Box<dyn B>> = <[_]> :: into_vec(box [box Astruct]);
+    let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32]));
+    let v: Vec<Box<dyn B>> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)]));
 }
 
 trait B{}
@@ -2774,20 +2725,20 @@ impl B for Astruct {}
         expect![[r#"
             604..608 'self': Box<[T], A>
             637..669 '{     ...     }': Vec<T, A>
-            683..796 '{     ...t]); }': ()
+            683..853 '{     ...])); }': ()
             693..696 'vec': Vec<i32, Global>
             699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
-            699..726 '<[_]>:...1i32])': Vec<i32, Global>
-            715..725 'box [1i32]': Box<[i32; 1], Global>
-            719..725 '[1i32]': [i32; 1]
-            720..724 '1i32': i32
-            736..737 'v': Vec<Box<dyn B, Global>, Global>
-            757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
-            757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
-            775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
-            779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
-            780..791 'box Astruct': Box<Astruct, Global>
-            784..791 'Astruct': Astruct
+            699..745 '<[_]>:...i32]))': Vec<i32, Global>
+            715..744 '#[rust...1i32])': Box<[i32; 1], Global>
+            737..743 '[1i32]': [i32; 1]
+            738..742 '1i32': i32
+            755..756 'v': Vec<Box<dyn B, Global>, Global>
+            776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
+            776..850 '<[_]> ...ct)]))': Vec<Box<dyn B, Global>, Global>
+            794..849 '#[rust...uct)])': Box<[Box<dyn B, Global>; 1], Global>
+            816..848 '[#[rus...ruct)]': [Box<dyn B, Global>; 1]
+            817..847 '#[rust...truct)': Box<Astruct, Global>
+            839..846 'Astruct': Astruct
         "#]],
     )
 }
@@ -3649,3 +3600,30 @@ fn main() {
 "#,
     );
 }
+
+#[test]
+fn offset_of() {
+    check_types(
+        r#"
+fn main() {
+    builtin#offset_of((,), 0);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
+}
+"#,
+    );
+}
+
+#[test]
+fn builtin_format_args() {
+    check(
+        r#"
+//- minicore: fmt
+fn main() {
+    let are = "are";
+    let count = 10;
+    builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'_>
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 542df8b3468..d36b885ec14 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -162,16 +162,16 @@ unsafe impl Allocator for Global {}
 
 #[lang = "owned_box"]
 #[fundamental]
-pub struct Box<T: ?Sized, A: Allocator = Global>;
+pub struct Box<T: ?Sized, A: Allocator = Global>(T);
 
 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 
 fn send() ->  Box<dyn Future<Output = ()> + Send + 'static>{
-    box async move {}
+    Box(async move {})
 }
 
 fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
-    box async move {}
+    Box(async move {})
 }
     "#,
     );
@@ -3057,7 +3057,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
 
 fn foo() {
     let s = None;
-    let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
+    let f: Box<dyn FnOnce(&Option<i32>)> = Box { inner: &mut (|ps| {}) };
     f(&s);
 }"#,
         expect![[r#"
@@ -3068,19 +3068,19 @@ fn foo() {
             186..197 '*self.inner': T
             187..191 'self': &Box<T>
             187..197 'self.inner': *mut T
-            218..308 '{     ...&s); }': ()
+            218..324 '{     ...&s); }': ()
             228..229 's': Option<i32>
             232..236 'None': Option<i32>
             246..247 'f': Box<dyn FnOnce(&Option<i32>)>
-            281..294 'box (|ps| {})': Box<impl Fn(&Option<i32>)>
-            286..293 '|ps| {}': impl Fn(&Option<i32>)
-            287..289 'ps': &Option<i32>
-            291..293 '{}': ()
-            300..301 'f': Box<dyn FnOnce(&Option<i32>)>
-            300..305 'f(&s)': ()
-            302..304 '&s': &Option<i32>
-            303..304 's': Option<i32>
-            281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<impl Fn(&Option<i32>)>
+            281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
+            294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>)
+            300..307 '|ps| {}': impl Fn(&Option<i32>)
+            301..303 'ps': &Option<i32>
+            305..307 '{}': ()
+            316..317 'f': Box<dyn FnOnce(&Option<i32>)>
+            316..321 'f(&s)': ()
+            318..320 '&s': &Option<i32>
+            319..320 's': Option<i32>
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index 121e5a0a249..796490abd7f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -1,39 +1,27 @@
 //! Attributes & documentation for hir types.
 
 use hir_def::{
-    attr::{AttrsWithOwner, Documentation},
+    attr::AttrsWithOwner,
     item_scope::ItemInNs,
     path::{ModPath, Path},
     per_ns::Namespace,
     resolver::{HasResolver, Resolver, TypeNs},
-    AssocItemId, AttrDefId, GenericParamId, ModuleDefId,
+    AssocItemId, AttrDefId, ModuleDefId,
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use hir_ty::db::HirDatabase;
 use syntax::{ast, AstNode};
 
 use crate::{
-    Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, Enum, ExternCrateDecl, Field,
-    Function, GenericParam, Impl, LifetimeParam, Macro, Module, ModuleDef, Static, Struct, Trait,
-    TraitAlias, TypeAlias, TypeParam, Union, Variant, VariantDef,
+    Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl,
+    Field, Function, GenericParam, Impl, LifetimeParam, Macro, Module, ModuleDef, Static, Struct,
+    Trait, TraitAlias, TypeAlias, TypeParam, Union, Variant, VariantDef,
 };
 
 pub trait HasAttrs {
     fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner;
-    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
-    fn resolve_doc_path(
-        self,
-        db: &dyn HirDatabase,
-        link: &str,
-        ns: Option<Namespace>,
-    ) -> Option<DocLinkDef>;
-}
-
-/// Subset of `ide_db::Definition` that doc links can resolve to.
-pub enum DocLinkDef {
-    ModuleDef(ModuleDef),
-    Field(Field),
-    SelfType(Trait),
+    #[doc(hidden)]
+    fn attr_id(self) -> AttrDefId;
 }
 
 macro_rules! impl_has_attrs {
@@ -43,18 +31,8 @@ macro_rules! impl_has_attrs {
                 let def = AttrDefId::$def_id(self.into());
                 db.attrs_with_owner(def)
             }
-            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
-                let def = AttrDefId::$def_id(self.into());
-                db.attrs(def).docs()
-            }
-            fn resolve_doc_path(
-                self,
-                db: &dyn HirDatabase,
-                link: &str,
-                ns: Option<Namespace>
-            ) -> Option<DocLinkDef> {
-                let def = AttrDefId::$def_id(self.into());
-                resolve_doc_path(db, def, link, ns)
+            fn attr_id(self) -> AttrDefId {
+                AttrDefId::$def_id(self.into())
             }
         }
     )*};
@@ -74,6 +52,7 @@ impl_has_attrs![
     (Module, ModuleId),
     (GenericParam, GenericParamId),
     (Impl, ImplId),
+    (ExternCrateDecl, ExternCrateId),
 ];
 
 macro_rules! impl_has_attrs_enum {
@@ -82,16 +61,8 @@ macro_rules! impl_has_attrs_enum {
             fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
                 $enum::$variant(self).attrs(db)
             }
-            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
-                $enum::$variant(self).docs(db)
-            }
-            fn resolve_doc_path(
-                self,
-                db: &dyn HirDatabase,
-                link: &str,
-                ns: Option<Namespace>
-            ) -> Option<DocLinkDef> {
-                $enum::$variant(self).resolve_doc_path(db, link, ns)
+            fn attr_id(self) -> AttrDefId {
+                $enum::$variant(self).attr_id()
             }
         }
     )*};
@@ -108,70 +79,35 @@ impl HasAttrs for AssocItem {
             AssocItem::TypeAlias(it) => it.attrs(db),
         }
     }
-
-    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+    fn attr_id(self) -> AttrDefId {
         match self {
-            AssocItem::Function(it) => it.docs(db),
-            AssocItem::Const(it) => it.docs(db),
-            AssocItem::TypeAlias(it) => it.docs(db),
-        }
-    }
-
-    fn resolve_doc_path(
-        self,
-        db: &dyn HirDatabase,
-        link: &str,
-        ns: Option<Namespace>,
-    ) -> Option<DocLinkDef> {
-        match self {
-            AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
-            AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
-            AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
+            AssocItem::Function(it) => it.attr_id(),
+            AssocItem::Const(it) => it.attr_id(),
+            AssocItem::TypeAlias(it) => it.attr_id(),
         }
     }
 }
 
-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<DocLinkDef> {
-        let def = AttrDefId::ExternCrateId(self.into());
-        resolve_doc_path(db, def, link, ns)
-    }
+/// Resolves the item `link` points to in the scope of `def`.
+pub fn resolve_doc_path_on(
+    db: &dyn HirDatabase,
+    def: impl HasAttrs,
+    link: &str,
+    ns: Option<Namespace>,
+) -> Option<DocLinkDef> {
+    // AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
+    // AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
+
+    resolve_doc_path_on_(db, link, def.attr_id(), ns)
 }
 
-/// Resolves the item `link` points to in the scope of `def`.
-fn resolve_doc_path(
+fn resolve_doc_path_on_(
     db: &dyn HirDatabase,
-    def: AttrDefId,
     link: &str,
+    attr_id: AttrDefId,
     ns: Option<Namespace>,
 ) -> Option<DocLinkDef> {
-    let resolver = match def {
+    let resolver = match attr_id {
         AttrDefId::ModuleId(it) => it.resolver(db.upcast()),
         AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
         AttrDefId::AdtId(it) => it.resolver(db.upcast()),
@@ -187,12 +123,7 @@ fn resolve_doc_path(
         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 {
-            GenericParamId::TypeParamId(it) => it.parent(),
-            GenericParamId::ConstParamId(it) => it.parent(),
-            GenericParamId::LifetimeParamId(it) => it.parent,
-        }
-        .resolver(db.upcast()),
+        AttrDefId::GenericParamId(_) => return None,
     };
 
     let mut modpath = modpath_from_str(db, link)?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 80c3bcdca8b..479138b67f8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -43,6 +43,7 @@ diagnostics![
     MacroExpansionParseError,
     MalformedDerive,
     MismatchedArgCount,
+    MismatchedTupleStructPatArgCount,
     MissingFields,
     MissingMatchArms,
     MissingUnsafe,
@@ -172,7 +173,8 @@ pub struct MalformedDerive {
 
 #[derive(Debug)]
 pub struct NoSuchField {
-    pub field: InFile<AstPtr<ast::RecordExprField>>,
+    pub field: InFile<Either<AstPtr<ast::RecordExprField>, AstPtr<ast::RecordPatField>>>,
+    pub private: bool,
 }
 
 #[derive(Debug)]
@@ -183,6 +185,13 @@ pub struct PrivateAssocItem {
 }
 
 #[derive(Debug)]
+pub struct MismatchedTupleStructPatArgCount {
+    pub expr_or_pat: InFile<Either<AstPtr<ast::Expr>, AstPtr<ast::Pat>>>,
+    pub expected: usize,
+    pub found: usize,
+}
+
+#[derive(Debug)]
 pub struct ExpectedFunction {
     pub call: InFile<AstPtr<ast::Expr>>,
     pub found: Type,
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 512fe7e0428..b215ed38f28 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -88,13 +88,14 @@ use triomphe::Arc;
 use crate::db::{DefDatabase, HirDatabase};
 
 pub use crate::{
-    attrs::{DocLinkDef, HasAttrs},
+    attrs::{resolve_doc_path_on, HasAttrs},
     diagnostics::{
         AnyDiagnostic, BreakOutsideOfLoop, CaseType, ExpectedFunction, InactiveCode,
         IncoherentImpl, IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError,
-        MacroExpansionParseError, MalformedDerive, MismatchedArgCount, MissingFields,
-        MissingMatchArms, MissingUnsafe, MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem,
-        PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel,
+        MacroExpansionParseError, MalformedDerive, MismatchedArgCount,
+        MismatchedTupleStructPatArgCount, MissingFields, MissingMatchArms, MissingUnsafe,
+        MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
+        ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel,
         UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
         UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
         UnresolvedProcMacro, UnusedMut,
@@ -115,7 +116,7 @@ pub use crate::{
 pub use {
     cfg::{CfgAtom, CfgExpr, CfgOptions},
     hir_def::{
-        attr::{builtin::AttributeTemplate, Attrs, AttrsWithOwner, Documentation},
+        attr::{builtin::AttributeTemplate, AttrSourceMap, Attrs, AttrsWithOwner},
         data::adt::StructKind,
         find_path::PrefixKind,
         import_map,
@@ -130,7 +131,7 @@ pub use {
         {AdtId, ModuleDefId},
     },
     hir_expand::{
-        attrs::Attr,
+        attrs::{Attr, AttrId},
         name::{known, Name},
         ExpandResult, HirFileId, InFile, MacroFile, Origin,
     },
@@ -563,8 +564,8 @@ impl Module {
             emit_def_diagnostic(db, acc, diag);
         }
 
-        for decl in self.declarations(db) {
-            match decl {
+        for def in self.declarations(db) {
+            match def {
                 ModuleDef::Module(m) => {
                     // Only add diagnostics from inline modules
                     if def_map[m.id.local_id].origin.is_inline() {
@@ -575,7 +576,7 @@ impl Module {
                     for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
                         emit_def_diagnostic(db, acc, diag);
                     }
-                    acc.extend(decl.diagnostics(db))
+                    acc.extend(def.diagnostics(db))
                 }
                 ModuleDef::Adt(adt) => {
                     match adt {
@@ -599,10 +600,10 @@ impl Module {
                             }
                         }
                     }
-                    acc.extend(decl.diagnostics(db))
+                    acc.extend(def.diagnostics(db))
                 }
                 ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m),
-                _ => acc.extend(decl.diagnostics(db)),
+                _ => acc.extend(def.diagnostics(db)),
             }
         }
         self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m));
@@ -1446,6 +1447,7 @@ impl DefWithBody {
     }
 
     pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
+        db.unwind_if_cancelled();
         let krate = self.module(db).id.krate();
 
         let (body, source_map) = db.body_with_source_map(self.into());
@@ -1501,11 +1503,19 @@ impl DefWithBody {
         let infer = db.infer(self.into());
         let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
         let expr_syntax = |expr| source_map.expr_syntax(expr).expect("unexpected synthetic");
+        let pat_syntax = |pat| source_map.pat_syntax(pat).expect("unexpected synthetic");
         for d in &infer.diagnostics {
             match d {
-                &hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
-                    let field = source_map.field_syntax(expr);
-                    acc.push(NoSuchField { field }.into())
+                &hir_ty::InferenceDiagnostic::NoSuchField { field: expr, private } => {
+                    let expr_or_pat = match expr {
+                        ExprOrPatId::ExprId(expr) => {
+                            source_map.field_syntax(expr).map(Either::Left)
+                        }
+                        ExprOrPatId::PatId(pat) => {
+                            source_map.pat_field_syntax(pat).map(Either::Right)
+                        }
+                    };
+                    acc.push(NoSuchField { field: expr_or_pat, private }.into())
                 }
                 &hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
                     acc.push(
@@ -1521,10 +1531,7 @@ impl DefWithBody {
                 &hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => {
                     let expr_or_pat = match id {
                         ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left),
-                        ExprOrPatId::PatId(pat) => source_map
-                            .pat_syntax(pat)
-                            .expect("unexpected synthetic")
-                            .map(Either::Right),
+                        ExprOrPatId::PatId(pat) => pat_syntax(pat).map(Either::Right),
                     };
                     let item = item.into();
                     acc.push(PrivateAssocItem { expr_or_pat, item }.into())
@@ -1596,6 +1603,23 @@ impl DefWithBody {
                         .into(),
                     )
                 }
+                &hir_ty::InferenceDiagnostic::MismatchedTupleStructPatArgCount {
+                    pat,
+                    expected,
+                    found,
+                } => {
+                    let expr_or_pat = match pat {
+                        ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left),
+                        ExprOrPatId::PatId(pat) => source_map
+                            .pat_syntax(pat)
+                            .expect("unexpected synthetic")
+                            .map(|it| it.unwrap_left())
+                            .map(Either::Right),
+                    };
+                    acc.push(
+                        MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into(),
+                    )
+                }
             }
         }
         for (pat_or_expr, mismatch) in infer.type_mismatches() {
@@ -4838,3 +4862,10 @@ pub enum ItemContainer {
     ExternBlock(),
     Crate(CrateId),
 }
+
+/// Subset of `ide_db::Definition` that doc links can resolve to.
+pub enum DocLinkDef {
+    ModuleDef(ModuleDef),
+    Field(Field),
+    SelfType(Trait),
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index b8d4ecd4414..a42e0978b25 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -127,165 +127,24 @@ impl<DB> fmt::Debug for Semantics<'_, DB> {
     }
 }
 
+impl<'db, DB> ops::Deref for Semantics<'db, DB> {
+    type Target = SemanticsImpl<'db>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.imp
+    }
+}
+
 impl<'db, DB: HirDatabase> Semantics<'db, DB> {
     pub fn new(db: &DB) -> Semantics<'_, DB> {
         let impl_ = SemanticsImpl::new(db);
         Semantics { db, imp: impl_ }
     }
 
-    pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
-        self.imp.parse(file_id)
-    }
-
-    pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
-        self.imp.parse_or_expand(file_id)
-    }
-
-    pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
-        self.imp.expand(macro_call)
-    }
-
-    /// If `item` has an attribute macro attached to it, expands it.
-    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
-        self.imp.expand_attr_macro(item)
-    }
-
-    pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
-        self.imp.expand_derive_as_pseudo_attr_macro(attr)
-    }
-
-    pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<Option<Macro>>> {
-        self.imp.resolve_derive_macro(derive)
-    }
-
-    pub fn expand_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<SyntaxNode>> {
-        self.imp.expand_derive_macro(derive)
-    }
-
-    pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
-        self.imp.is_attr_macro_call(item)
-    }
-
-    pub fn is_derive_annotated(&self, item: &ast::Adt) -> bool {
-        self.imp.is_derive_annotated(item)
-    }
-
-    /// Expand the macro call with a different token tree, mapping the `token_to_map` down into the
-    /// expansion. `token_to_map` should be a token from the `speculative args` node.
-    pub fn speculative_expand(
-        &self,
-        actual_macro_call: &ast::MacroCall,
-        speculative_args: &ast::TokenTree,
-        token_to_map: SyntaxToken,
-    ) -> Option<(SyntaxNode, SyntaxToken)> {
-        self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map)
-    }
-
-    /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the
-    /// expansion. `token_to_map` should be a token from the `speculative args` node.
-    pub fn speculative_expand_attr_macro(
-        &self,
-        actual_macro_call: &ast::Item,
-        speculative_args: &ast::Item,
-        token_to_map: SyntaxToken,
-    ) -> Option<(SyntaxNode, SyntaxToken)> {
-        self.imp.speculative_expand_attr(actual_macro_call, speculative_args, token_to_map)
-    }
-
-    pub fn speculative_expand_derive_as_pseudo_attr_macro(
-        &self,
-        actual_macro_call: &ast::Attr,
-        speculative_args: &ast::Attr,
-        token_to_map: SyntaxToken,
-    ) -> Option<(SyntaxNode, SyntaxToken)> {
-        self.imp.speculative_expand_derive_as_pseudo_attr_macro(
-            actual_macro_call,
-            speculative_args,
-            token_to_map,
-        )
-    }
-
-    /// Descend the token into its macro call if it is part of one, returning the token in the
-    /// expansion that it is associated with. If `offset` points into the token's range, it will
-    /// be considered for the mapping in case of inline format args.
-    pub fn descend_into_macros_single(&self, token: SyntaxToken, offset: TextSize) -> SyntaxToken {
-        self.imp.descend_into_macros_single(token, offset)
-    }
-
-    /// Descend the token into its macro call if it is part of one, returning the tokens in the
-    /// expansion that it is associated with. If `offset` points into the token's range, it will
-    /// be considered for the mapping in case of inline format args.
-    pub fn descend_into_macros(
-        &self,
-        token: SyntaxToken,
-        offset: TextSize,
-    ) -> SmallVec<[SyntaxToken; 1]> {
-        self.imp.descend_into_macros(token, offset)
-    }
-
-    /// Descend the token into macrocalls to all its mapped counterparts that have the same text as the input token.
-    ///
-    /// Returns the original non descended token if none of the mapped counterparts have the same text.
-    pub fn descend_into_macros_with_same_text(
-        &self,
-        token: SyntaxToken,
-        offset: TextSize,
-    ) -> SmallVec<[SyntaxToken; 1]> {
-        self.imp.descend_into_macros_with_same_text(token, offset)
-    }
-
-    pub fn descend_into_macros_with_kind_preference(
-        &self,
-        token: SyntaxToken,
-        offset: TextSize,
-    ) -> SyntaxToken {
-        self.imp.descend_into_macros_with_kind_preference(token, offset)
-    }
-
-    /// Maps a node down by mapping its first and last token down.
-    pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
-        self.imp.descend_node_into_attributes(node)
-    }
-
-    /// Search for a definition's source and cache its syntax tree
-    pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
-    where
-        Def::Ast: AstNode,
-    {
-        self.imp.source(def)
-    }
-
     pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
         self.imp.find_file(syntax_node).file_id
     }
 
-    /// Attempts to map the node out of macro expanded files returning the original file range.
-    /// If upmapping is not possible, this will fall back to the range of the macro call of the
-    /// macro file the node resides in.
-    pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
-        self.imp.original_range(node)
-    }
-
-    /// Attempts to map the node out of macro expanded files returning the original file range.
-    pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
-        self.imp.original_range_opt(node)
-    }
-
-    /// Attempts to map the node out of macro expanded files.
-    /// This only work for attribute expansions, as other ones do not have nodes as input.
-    pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
-        self.imp.original_ast_node(node)
-    }
-    /// Attempts to map the node out of macro expanded files.
-    /// This only work for attribute expansions, as other ones do not have nodes as input.
-    pub fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
-        self.imp.original_syntax_node(node)
-    }
-
-    pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
-        self.imp.diagnostics_display_range(diagnostics)
-    }
-
     pub fn token_ancestors_with_macros(
         &self,
         token: SyntaxToken,
@@ -293,19 +152,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
     }
 
-    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
-    pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
-        self.imp.ancestors_with_macros(node)
-    }
-
-    pub fn ancestors_at_offset_with_macros(
-        &self,
-        node: &SyntaxNode,
-        offset: TextSize,
-    ) -> impl Iterator<Item = SyntaxNode> + '_ {
-        self.imp.ancestors_at_offset_with_macros(node, offset)
-    }
-
     /// Find an AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
     /// search up until it is of the target AstNode type
     pub fn find_node_at_offset_with_macros<N: AstNode>(
@@ -336,53 +182,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
     }
 
-    pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
-        self.imp.resolve_lifetime_param(lifetime)
-    }
-
-    pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
-        self.imp.resolve_label(lifetime)
-    }
-
-    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
-        self.imp.resolve_type(ty)
-    }
-
-    pub fn resolve_trait(&self, trait_: &ast::Path) -> Option<Trait> {
-        self.imp.resolve_trait(trait_)
-    }
-
-    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
-        self.imp.expr_adjustments(expr)
-    }
-
-    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
-        self.imp.type_of_expr(expr)
-    }
-
-    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
-        self.imp.type_of_pat(pat)
-    }
-
-    /// It also includes the changes that binding mode makes in the type. For example in
-    /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
-    /// of this function is `&mut Option<T>`
-    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
-        self.imp.type_of_binding_in_pat(pat)
-    }
-
-    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
-        self.imp.type_of_self(param)
-    }
-
-    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
-        self.imp.pattern_adjustments(pat)
-    }
-
-    pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
-        self.imp.binding_mode_of_pat(pat)
-    }
-
     pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
         self.imp.resolve_method_call(call).map(Function::from)
     }
@@ -417,61 +216,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_try_expr(try_expr).map(Function::from)
     }
 
-    pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
-        self.imp.resolve_method_call_as_callable(call)
-    }
-
-    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
-        self.imp.resolve_field(field)
-    }
-
-    pub fn resolve_record_field(
-        &self,
-        field: &ast::RecordExprField,
-    ) -> Option<(Field, Option<Local>, Type)> {
-        self.imp.resolve_record_field(field)
-    }
-
-    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
-        self.imp.resolve_record_pat_field(field)
-    }
-
-    pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
-        self.imp.resolve_macro_call(macro_call)
-    }
-
-    pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
-        self.imp.is_unsafe_macro_call(macro_call)
-    }
-
-    pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
-        self.imp.resolve_attr_macro_call(item)
-    }
-
-    pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
-        self.imp.resolve_path(path)
-    }
-
     pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
         self.imp.resolve_variant(record_lit).map(VariantDef::from)
     }
 
-    pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
-        self.imp.resolve_bind_pat_to_const(pat)
-    }
-
-    pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
-        self.imp.record_literal_missing_fields(literal)
-    }
-
-    pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
-        self.imp.record_pattern_missing_fields(pattern)
-    }
-
-    pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
-        self.imp.to_def(src)
-    }
-
     pub fn to_module_def(&self, file: FileId) -> Option<Module> {
         self.imp.to_module_def(file).next()
     }
@@ -479,39 +227,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
     pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
         self.imp.to_module_def(file)
     }
-
-    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
-        self.imp.scope(node)
-    }
-
-    pub fn scope_at_offset(
-        &self,
-        node: &SyntaxNode,
-        offset: TextSize,
-    ) -> Option<SemanticsScope<'db>> {
-        self.imp.scope_at_offset(node, offset)
-    }
-
-    pub fn assert_contains_node(&self, node: &SyntaxNode) {
-        self.imp.assert_contains_node(node)
-    }
-
-    pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
-        self.imp.is_unsafe_method_call(method_call_expr)
-    }
-
-    pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
-        self.imp.is_unsafe_ref_expr(ref_expr)
-    }
-
-    pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
-        self.imp.is_unsafe_ident_pat(ident_pat)
-    }
-
-    /// Returns `true` if the `node` is inside an `unsafe` context.
-    pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
-        self.imp.is_inside_unsafe(expr)
-    }
 }
 
 impl<'db> SemanticsImpl<'db> {
@@ -525,32 +240,33 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
-    fn parse(&self, file_id: FileId) -> ast::SourceFile {
+    pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
         let tree = self.db.parse(file_id).tree();
         self.cache(tree.syntax().clone(), file_id.into());
         tree
     }
 
-    fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
+    pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
         let node = self.db.parse_or_expand(file_id);
         self.cache(node.clone(), file_id);
         node
     }
 
-    fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
+    pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
         let sa = self.analyze_no_infer(macro_call.syntax())?;
         let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
         let node = self.parse_or_expand(file_id);
         Some(node)
     }
 
-    fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
+    /// If `item` has an attribute macro attached to it, expands it.
+    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
         let src = self.wrap_node_infile(item.clone());
         let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
         Some(self.parse_or_expand(macro_call_id.as_file()))
     }
 
-    fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
+    pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
         let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
         let src = self.wrap_node_infile(attr.clone());
         let call_id = self.with_ctx(|ctx| {
@@ -559,7 +275,7 @@ impl<'db> SemanticsImpl<'db> {
         Some(self.parse_or_expand(call_id.as_file()))
     }
 
-    fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> {
+    pub fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> {
         let calls = self.derive_macro_calls(attr)?;
         self.with_ctx(|ctx| {
             Some(
@@ -573,7 +289,7 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
-    fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
+    pub fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
         let res: Vec<_> = self
             .derive_macro_calls(attr)?
             .into_iter()
@@ -598,19 +314,21 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
-    fn is_derive_annotated(&self, adt: &ast::Adt) -> bool {
+    pub fn is_derive_annotated(&self, adt: &ast::Adt) -> bool {
         let file_id = self.find_file(adt.syntax()).file_id;
         let adt = InFile::new(file_id, adt);
         self.with_ctx(|ctx| ctx.has_derives(adt))
     }
 
-    fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
+    pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
         let file_id = self.find_file(item.syntax()).file_id;
         let src = InFile::new(file_id, item.clone());
         self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some())
     }
 
-    fn speculative_expand(
+    /// Expand the macro call with a different token tree, mapping the `token_to_map` down into the
+    /// expansion. `token_to_map` should be a token from the `speculative args` node.
+    pub fn speculative_expand(
         &self,
         actual_macro_call: &ast::MacroCall,
         speculative_args: &ast::TokenTree,
@@ -633,7 +351,9 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
-    fn speculative_expand_attr(
+    /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the
+    /// expansion. `token_to_map` should be a token from the `speculative args` node.
+    pub fn speculative_expand_attr_macro(
         &self,
         actual_macro_call: &ast::Item,
         speculative_args: &ast::Item,
@@ -649,7 +369,7 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
-    fn speculative_expand_derive_as_pseudo_attr_macro(
+    pub fn speculative_expand_derive_as_pseudo_attr_macro(
         &self,
         actual_macro_call: &ast::Attr,
         speculative_args: &ast::Attr,
@@ -668,8 +388,9 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
-    // This might not be the correct way to do this, but it works for now
-    fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
+    /// Maps a node down by mapping its first and last token down.
+    pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
+        // This might not be the correct way to do this, but it works for now
         let mut res = smallvec![];
         let tokens = (|| {
             let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?;
@@ -723,7 +444,10 @@ impl<'db> SemanticsImpl<'db> {
         res
     }
 
-    fn descend_into_macros(
+    /// Descend the token into its macro call if it is part of one, returning the tokens in the
+    /// expansion that it is associated with. If `offset` points into the token's range, it will
+    /// be considered for the mapping in case of inline format args.
+    pub fn descend_into_macros(
         &self,
         token: SyntaxToken,
         offset: TextSize,
@@ -736,7 +460,10 @@ impl<'db> SemanticsImpl<'db> {
         res
     }
 
-    fn descend_into_macros_with_same_text(
+    /// Descend the token into macrocalls to all its mapped counterparts that have the same text as the input token.
+    ///
+    /// Returns the original non descended token if none of the mapped counterparts have the same text.
+    pub fn descend_into_macros_with_same_text(
         &self,
         token: SyntaxToken,
         offset: TextSize,
@@ -755,7 +482,7 @@ impl<'db> SemanticsImpl<'db> {
         res
     }
 
-    fn descend_into_macros_with_kind_preference(
+    pub fn descend_into_macros_with_kind_preference(
         &self,
         token: SyntaxToken,
         offset: TextSize,
@@ -785,7 +512,10 @@ impl<'db> SemanticsImpl<'db> {
         res.unwrap_or(token)
     }
 
-    fn descend_into_macros_single(&self, token: SyntaxToken, offset: TextSize) -> SyntaxToken {
+    /// Descend the token into its macro call if it is part of one, returning the token in the
+    /// expansion that it is associated with. If `offset` points into the token's range, it will
+    /// be considered for the mapping in case of inline format args.
+    pub fn descend_into_macros_single(&self, token: SyntaxToken, offset: TextSize) -> SyntaxToken {
         let mut res = token.clone();
         self.descend_into_macros_impl(token, offset, &mut |InFile { value, .. }| {
             res = value;
@@ -995,17 +725,23 @@ impl<'db> SemanticsImpl<'db> {
             })
     }
 
-    fn original_range(&self, node: &SyntaxNode) -> FileRange {
+    /// Attempts to map the node out of macro expanded files returning the original file range.
+    /// If upmapping is not possible, this will fall back to the range of the macro call of the
+    /// macro file the node resides in.
+    pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
         let node = self.find_file(node);
         node.original_file_range(self.db.upcast())
     }
 
-    fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
+    /// Attempts to map the node out of macro expanded files returning the original file range.
+    pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
         let node = self.find_file(node);
         node.original_file_range_opt(self.db.upcast())
     }
 
-    fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
+    /// Attempts to map the node out of macro expanded files.
+    /// This only work for attribute expansions, as other ones do not have nodes as input.
+    pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
         self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(
             |InFile { file_id, value }| {
                 self.cache(find_root(value.syntax()), file_id);
@@ -1014,7 +750,9 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
-    fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
+    /// Attempts to map the node out of macro expanded files.
+    /// This only work for attribute expansions, as other ones do not have nodes as input.
+    pub fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
         let InFile { file_id, .. } = self.find_file(node);
         InFile::new(file_id, node).original_syntax_node(self.db.upcast()).map(
             |InFile { file_id, value }| {
@@ -1024,7 +762,7 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
-    fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
+    pub fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
         let root = self.parse_or_expand(src.file_id);
         let node = src.map(|it| it.to_node(&root));
         node.as_ref().original_file_range(self.db.upcast())
@@ -1037,7 +775,8 @@ impl<'db> SemanticsImpl<'db> {
         token.parent().into_iter().flat_map(move |parent| self.ancestors_with_macros(parent))
     }
 
-    fn ancestors_with_macros(
+    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
+    pub fn ancestors_with_macros(
         &self,
         node: SyntaxNode,
     ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
@@ -1055,7 +794,7 @@ impl<'db> SemanticsImpl<'db> {
         .map(|it| it.value)
     }
 
-    fn ancestors_at_offset_with_macros(
+    pub fn ancestors_at_offset_with_macros(
         &self,
         node: &SyntaxNode,
         offset: TextSize,
@@ -1065,7 +804,7 @@ impl<'db> SemanticsImpl<'db> {
             .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
     }
 
-    fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
+    pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
         let text = lifetime.text();
         let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {
             let gpl = ast::AnyHasGenericParams::cast(syn)?.generic_param_list()?;
@@ -1076,7 +815,7 @@ impl<'db> SemanticsImpl<'db> {
         ToDef::to_def(self, src)
     }
 
-    fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
+    pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
         let text = lifetime.text();
         let label = lifetime.syntax().ancestors().find_map(|syn| {
             let label = match_ast! {
@@ -1098,7 +837,7 @@ impl<'db> SemanticsImpl<'db> {
         ToDef::to_def(self, src)
     }
 
-    fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
+    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
         let analyze = self.analyze(ty.syntax())?;
         let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id);
         let ty = hir_ty::TyLoweringContext::new(
@@ -1110,7 +849,7 @@ impl<'db> SemanticsImpl<'db> {
         Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
     }
 
-    fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
+    pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
         let analyze = self.analyze(path.syntax())?;
         let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
         let ctx = LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
@@ -1121,7 +860,7 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
-    fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
+    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment>> {
         let mutability = |m| match m {
             hir_ty::Mutability::Not => Mutability::Shared,
             hir_ty::Mutability::Mut => Mutability::Mut,
@@ -1165,33 +904,36 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
-    fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
+    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
         self.analyze(expr.syntax())?
             .type_of_expr(self.db, expr)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
     }
 
-    fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
+    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
         self.analyze(pat.syntax())?
             .type_of_pat(self.db, pat)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
     }
 
-    fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
+    /// It also includes the changes that binding mode makes in the type. For example in
+    /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
+    /// of this function is `&mut Option<T>`
+    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> {
         self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
     }
 
-    fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
+    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
         self.analyze(param.syntax())?.type_of_self(self.db, param)
     }
 
-    fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
         self.analyze(pat.syntax())
             .and_then(|it| it.pattern_adjustments(self.db, pat))
             .unwrap_or_default()
     }
 
-    fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
+    pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
         self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
     }
 
@@ -1226,32 +968,32 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
     }
 
-    fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
+    pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
     }
 
-    fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
+    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
         self.analyze(field.syntax())?.resolve_field(self.db, field)
     }
 
-    fn resolve_record_field(
+    pub fn resolve_record_field(
         &self,
         field: &ast::RecordExprField,
     ) -> Option<(Field, Option<Local>, Type)> {
         self.analyze(field.syntax())?.resolve_record_field(self.db, field)
     }
 
-    fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
+    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
         self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
     }
 
-    fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
+    pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
         let sa = self.analyze(macro_call.syntax())?;
         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
         sa.resolve_macro_call(self.db, macro_call)
     }
 
-    fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
+    pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
         let sa = match self.analyze(macro_call.syntax()) {
             Some(it) => it,
             None => return false,
@@ -1260,7 +1002,7 @@ impl<'db> SemanticsImpl<'db> {
         sa.is_unsafe_macro_call(self.db, macro_call)
     }
 
-    fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
+    pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
         let item_in_file = self.wrap_node_infile(item.clone());
         let id = self.with_ctx(|ctx| {
             let macro_call_id = ctx.item_to_macro_call(item_in_file)?;
@@ -1269,7 +1011,7 @@ impl<'db> SemanticsImpl<'db> {
         Some(Macro { id })
     }
 
-    fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
+    pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
         self.analyze(path.syntax())?.resolve_path(self.db, path)
     }
 
@@ -1277,17 +1019,17 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
     }
 
-    fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
+    pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
         self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
     }
 
-    fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
+    pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
         self.analyze(literal.syntax())
             .and_then(|it| it.record_literal_missing_fields(self.db, literal))
             .unwrap_or_default()
     }
 
-    fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
+    pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
         self.analyze(pattern.syntax())
             .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
             .unwrap_or_default()
@@ -1299,7 +1041,7 @@ impl<'db> SemanticsImpl<'db> {
         f(&mut ctx)
     }
 
-    fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
+    pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
         let src = self.find_file(src.syntax()).with_value(src).cloned();
         T::to_def(self, src)
     }
@@ -1308,7 +1050,7 @@ impl<'db> SemanticsImpl<'db> {
         self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
     }
 
-    fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
+    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
         self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope {
             db: self.db,
             file_id,
@@ -1316,7 +1058,11 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
-    fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> Option<SemanticsScope<'db>> {
+    pub fn scope_at_offset(
+        &self,
+        node: &SyntaxNode,
+        offset: TextSize,
+    ) -> Option<SemanticsScope<'db>> {
         self.analyze_with_offset_no_infer(node, offset).map(
             |SourceAnalyzer { file_id, resolver, .. }| SemanticsScope {
                 db: self.db,
@@ -1326,7 +1072,8 @@ impl<'db> SemanticsImpl<'db> {
         )
     }
 
-    fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
+    /// Search for a definition's source and cache its syntax tree
+    pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
     where
         Def::Ast: AstNode,
     {
@@ -1391,7 +1138,7 @@ impl<'db> SemanticsImpl<'db> {
         assert!(prev == None || prev == Some(file_id))
     }
 
-    fn assert_contains_node(&self, node: &SyntaxNode) {
+    pub fn assert_contains_node(&self, node: &SyntaxNode) {
         self.find_file(node);
     }
 
@@ -1427,7 +1174,7 @@ impl<'db> SemanticsImpl<'db> {
         InFile::new(file_id, node)
     }
 
-    fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
+    pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
         method_call_expr
             .receiver()
             .and_then(|expr| {
@@ -1450,7 +1197,7 @@ impl<'db> SemanticsImpl<'db> {
             .unwrap_or(false)
     }
 
-    fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
+    pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
         ref_expr
             .expr()
             .and_then(|expr| {
@@ -1469,7 +1216,7 @@ impl<'db> SemanticsImpl<'db> {
         // more than it should with the current implementation.
     }
 
-    fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
+    pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
         if ident_pat.ref_token().is_none() {
             return false;
         }
@@ -1512,7 +1259,8 @@ impl<'db> SemanticsImpl<'db> {
             .unwrap_or(false)
     }
 
-    fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
+    /// Returns `true` if the `node` is inside an `unsafe` context.
+    pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
         let Some(enclosing_item) =
             expr.syntax().ancestors().find_map(Either::<ast::Item, ast::Variant>::cast)
         else {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
new file mode 100644
index 00000000000..45c1f0ccae3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
@@ -0,0 +1,159 @@
+use crate::assist_context::{AssistContext, Assists};
+use ide_db::{
+    assists::{AssistId, AssistKind},
+    defs::Definition,
+    LineIndexDatabase,
+};
+use syntax::{
+    ast::{self, edit_in_place::Indent},
+    AstNode,
+};
+
+// Assist: bind_unused_param
+//
+// Binds unused function parameter to an underscore.
+//
+// ```
+// fn some_function(x: i32$0) {}
+// ```
+// ->
+// ```
+// fn some_function(x: i32) {
+//     let _ = x;
+// }
+// ```
+pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let param: ast::Param = ctx.find_node_at_offset()?;
+
+    let Some(ast::Pat::IdentPat(ident_pat)) = param.pat() else { return None };
+
+    let param_def = {
+        let local = ctx.sema.to_def(&ident_pat)?;
+        Definition::Local(local)
+    };
+    if param_def.usages(&ctx.sema).at_least_one() {
+        cov_mark::hit!(keep_used);
+        return None;
+    }
+
+    let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
+    let stmt_list = func.body()?.stmt_list()?;
+    let l_curly_range = stmt_list.l_curly_token()?.text_range();
+    let r_curly_range = stmt_list.r_curly_token()?.text_range();
+
+    acc.add(
+        AssistId("bind_unused_param", AssistKind::QuickFix),
+        &format!("Bind as `let _ = {};`", &ident_pat),
+        param.syntax().text_range(),
+        |builder| {
+            let line_index = ctx.db().line_index(ctx.file_id());
+
+            let indent = func.indent_level();
+            let text_indent = indent + 1;
+            let mut text = format!("\n{text_indent}let _ = {ident_pat};");
+
+            let left_line = line_index.line_col(l_curly_range.end()).line;
+            let right_line = line_index.line_col(r_curly_range.start()).line;
+
+            if left_line == right_line {
+                cov_mark::hit!(single_line);
+                text.push_str(&format!("\n{indent}"));
+            }
+
+            builder.insert(l_curly_range.end(), text);
+        },
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn bind_unused_empty_block() {
+        cov_mark::check!(single_line);
+        check_assist(
+            bind_unused_param,
+            r#"
+fn foo($0y: i32) {}
+"#,
+            r#"
+fn foo(y: i32) {
+    let _ = y;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn bind_unused_empty_block_with_newline() {
+        check_assist(
+            bind_unused_param,
+            r#"
+fn foo($0y: i32) {
+}
+"#,
+            r#"
+fn foo(y: i32) {
+    let _ = y;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn bind_unused_generic() {
+        check_assist(
+            bind_unused_param,
+            r#"
+fn foo<T>($0y: T)
+where T : Default {
+}
+"#,
+            r#"
+fn foo<T>(y: T)
+where T : Default {
+    let _ = y;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_impl() {
+        check_assist(
+            bind_unused_param,
+            r#"
+trait Trait {
+    fn foo(x: i32);
+}
+impl Trait for () {
+    fn foo($0x: i32) {}
+}
+"#,
+            r#"
+trait Trait {
+    fn foo(x: i32);
+}
+impl Trait for () {
+    fn foo(x: i32) {
+        let _ = x;
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn keep_used() {
+        cov_mark::check!(keep_used);
+        check_assist_not_applicable(
+            bind_unused_param,
+            r#"
+fn foo(x: i32, $0y: i32) { y; }
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index 1af52c59218..d231708c55b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -103,7 +103,6 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
                 cond,
                 ast::Expr::BinExpr(_)
                     | ast::Expr::BlockExpr(_)
-                    | ast::Expr::BoxExpr(_)
                     | ast::Expr::BreakExpr(_)
                     | ast::Expr::CastExpr(_)
                     | ast::Expr::ClosureExpr(_)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
index c3d925cb26c..31a1ff496e1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs
@@ -15,26 +15,13 @@ use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
 // Move an expression out of a format string.
 //
 // ```
-// macro_rules! format_args {
-//     ($lit:literal $(tt:tt)*) => { 0 },
-// }
-// macro_rules! print {
-//     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-// }
-//
+// # //- minicore: fmt
 // fn main() {
 //     print!("{var} {x + 1}$0");
 // }
 // ```
 // ->
 // ```
-// macro_rules! format_args {
-//     ($lit:literal $(tt:tt)*) => { 0 },
-// }
-// macro_rules! print {
-//     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-// }
-//
 // fn main() {
 //     print!("{var} {}"$0, x + 1);
 // }
@@ -158,37 +145,21 @@ mod tests {
     use super::*;
     use crate::tests::check_assist;
 
-    const MACRO_DECL: &'static str = r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
-macro_rules! print {
-    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-}
-"#;
-
-    fn add_macro_decl(s: &'static str) -> String {
-        MACRO_DECL.to_string() + s
-    }
-
     #[test]
     fn multiple_middle_arg() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     print!("{} {x + 1:b} {}$0", y + 2, 2);
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     print!("{} {:b} {}"$0, y + 2, x + 1, 2);
 }
 "#,
-            ),
         );
     }
 
@@ -196,20 +167,17 @@ fn main() {
     fn single_arg() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     print!("{obj.value:b}$0",);
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     print!("{:b}"$0, obj.value);
 }
 "#,
-            ),
         );
     }
 
@@ -217,20 +185,17 @@ fn main() {
     fn multiple_middle_placeholders_arg() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     print!("{} {x + 1:b} {} {}$0", y + 2, 2);
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
 }
 "#,
-            ),
         );
     }
 
@@ -238,20 +203,17 @@ fn main() {
     fn multiple_trailing_args() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1);
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2));
 }
 "#,
-            ),
         );
     }
 
@@ -259,20 +221,17 @@ fn main() {
     fn improper_commas() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     print!("{} {x + 1:b} {Struct(1, 2)}$0", 1,);
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
 }
 "#,
-            ),
         );
     }
 
@@ -280,20 +239,17 @@ fn main() {
     fn nested_tt() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     print!("My name is {} {x$0 + x}", stringify!(Paperino))
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     print!("My name is {} {}"$0, stringify!(Paperino), x + x)
 }
 "#,
-            ),
         );
     }
 
@@ -301,22 +257,19 @@ fn main() {
     fn extract_only_expressions() {
         check_assist(
             extract_expressions_from_format_string,
-            &add_macro_decl(
-                r#"
+            r#"
+//- minicore: fmt
 fn main() {
     let var = 1 + 1;
     print!("foobar {var} {var:?} {x$0 + x}")
 }
 "#,
-            ),
-            &add_macro_decl(
-                r#"
+            r#"
 fn main() {
     let var = 1 + 1;
     print!("foobar {var} {var:?} {}"$0, x + x)
 }
 "#,
-            ),
         );
     }
 }
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 ea7a21e77a4..de591cfde94 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
@@ -531,7 +531,7 @@ impl FunctionBody {
 
     fn extracted_from_trait_impl(&self) -> bool {
         match self.node().ancestors().find_map(ast::Impl::cast) {
-            Some(c) => return c.trait_().is_some(),
+            Some(c) => c.trait_().is_some(),
             None => false,
         }
     }
@@ -1048,23 +1048,17 @@ impl GenericParent {
 fn generic_parents(parent: &SyntaxNode) -> Vec<GenericParent> {
     let mut list = Vec::new();
     if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast) {
-        match parent_item {
-            ast::Item::Fn(ref fn_) => {
-                if let Some(parent_parent) = parent_item
-                    .syntax()
-                    .parent()
-                    .and_then(|it| it.parent())
-                    .and_then(ast::Item::cast)
-                {
-                    match parent_parent {
-                        ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)),
-                        ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)),
-                        _ => (),
-                    }
+        if let ast::Item::Fn(ref fn_) = parent_item {
+            if let Some(parent_parent) =
+                parent_item.syntax().parent().and_then(|it| it.parent()).and_then(ast::Item::cast)
+            {
+                match parent_parent {
+                    ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)),
+                    ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)),
+                    _ => (),
                 }
-                list.push(GenericParent::Fn(fn_.clone()));
             }
-            _ => (),
+            list.push(GenericParent::Fn(fn_.clone()));
         }
     }
     list
@@ -1728,7 +1722,7 @@ fn make_body(
     let block = match &fun.body {
         FunctionBody::Expr(expr) => {
             let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
-            let expr = ast::Expr::cast(expr).unwrap();
+            let expr = ast::Expr::cast(expr).expect("Body segment should be an expr");
             match expr {
                 ast::Expr::BlockExpr(block) => {
                     // If the extracted expression is itself a block, there is no need to wrap it inside another block.
@@ -1868,9 +1862,8 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr
 
     if let Some(stmt_list) = block.stmt_list() {
         stmt_list.syntax().children_with_tokens().for_each(|node_or_token| {
-            match &node_or_token {
-                syntax::NodeOrToken::Token(_) => elements.push(node_or_token),
-                _ => (),
+            if let syntax::NodeOrToken::Token(_) = &node_or_token {
+                elements.push(node_or_token)
             };
         });
     }
@@ -1934,12 +1927,18 @@ fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNo
                 Some(ast::Expr::RefExpr(node))
                     if param.kind() == ParamKind::MutRef && node.mut_token().is_some() =>
                 {
-                    ted::replace(node.syntax(), node.expr().unwrap().syntax());
+                    ted::replace(
+                        node.syntax(),
+                        node.expr().expect("RefExpr::expr() cannot be None").syntax(),
+                    );
                 }
                 Some(ast::Expr::RefExpr(node))
                     if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() =>
                 {
-                    ted::replace(node.syntax(), node.expr().unwrap().syntax());
+                    ted::replace(
+                        node.syntax(),
+                        node.expr().expect("RefExpr::expr() cannot be None").syntax(),
+                    );
                 }
                 Some(_) | None => {
                     let p = &make::expr_prefix(T![*], usage.clone()).clone_for_update();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
new file mode 100644
index 00000000000..663df266b6f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
@@ -0,0 +1,205 @@
+use hir::{AsAssocItem, HirDisplay};
+use ide_db::{
+    assists::{AssistId, AssistKind},
+    famous_defs::FamousDefs,
+};
+use syntax::{ast, AstNode};
+
+use crate::assist_context::{AssistContext, Assists};
+
+// Assist: into_to_qualified_from
+//
+// Convert an `into` method call to a fully qualified `from` call.
+//
+// ```
+// //- minicore: from
+// struct B;
+// impl From<i32> for B {
+//     fn from(a: i32) -> Self {
+//        B
+//     }
+// }
+//
+// fn main() -> () {
+//     let a = 3;
+//     let b: B = a.in$0to();
+// }
+// ```
+// ->
+// ```
+// struct B;
+// impl From<i32> for B {
+//     fn from(a: i32) -> Self {
+//        B
+//     }
+// }
+//
+// fn main() -> () {
+//     let a = 3;
+//     let b: B = B::from(a);
+// }
+// ```
+pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+    let nameref = method_call.name_ref()?;
+    let receiver = method_call.receiver()?;
+    let db = ctx.db();
+    let sema = &ctx.sema;
+    let fnc = sema.resolve_method_call(&method_call)?;
+    let scope = sema.scope(method_call.syntax())?;
+    // Check if the method call refers to Into trait.
+    if fnc.as_assoc_item(db)?.containing_trait_impl(db)?
+        == FamousDefs(sema, scope.krate()).core_convert_Into()?
+    {
+        let type_call = sema.type_of_expr(&method_call.clone().into())?;
+        let type_call_disp =
+            type_call.adjusted().display_source_code(db, scope.module().into(), true).ok()?;
+
+        acc.add(
+            AssistId("into_to_qualified_from", AssistKind::Generate),
+            "Convert `into` to fully qualified `from`",
+            nameref.syntax().text_range(),
+            |edit| {
+                edit.replace(
+                    method_call.syntax().text_range(),
+                    format!("{}::from({})", type_call_disp, receiver),
+                );
+            },
+        );
+    }
+
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_assist;
+
+    use super::into_to_qualified_from;
+
+    #[test]
+    fn two_types_in_same_mod() {
+        check_assist(
+            into_to_qualified_from,
+            r#"
+//- minicore: from
+struct A;
+struct B;
+impl From<A> for B {
+    fn from(a: A) -> Self {
+        B
+    }
+}
+
+fn main() -> () {
+    let a: A = A;
+    let b: B = a.in$0to();
+}"#,
+            r#"
+struct A;
+struct B;
+impl From<A> for B {
+    fn from(a: A) -> Self {
+        B
+    }
+}
+
+fn main() -> () {
+    let a: A = A;
+    let b: B = B::from(a);
+}"#,
+        )
+    }
+
+    #[test]
+    fn fromed_in_child_mod_imported() {
+        check_assist(
+            into_to_qualified_from,
+            r#"
+//- minicore: from
+use C::B;
+
+struct A;
+
+mod C {
+    use crate::A;
+
+    pub(super) struct B;
+    impl From<A> for B {
+        fn from(a: A) -> Self {
+            B
+        }
+    }
+}
+
+fn main() -> () {
+    let a: A = A;
+    let b: B = a.in$0to();
+}"#,
+            r#"
+use C::B;
+
+struct A;
+
+mod C {
+    use crate::A;
+
+    pub(super) struct B;
+    impl From<A> for B {
+        fn from(a: A) -> Self {
+            B
+        }
+    }
+}
+
+fn main() -> () {
+    let a: A = A;
+    let b: B = B::from(a);
+}"#,
+        )
+    }
+
+    #[test]
+    fn fromed_in_child_mod_not_imported() {
+        check_assist(
+            into_to_qualified_from,
+            r#"
+//- minicore: from
+struct A;
+
+mod C {
+    use crate::A;
+
+    pub(super) struct B;
+    impl From<A> for B {
+        fn from(a: A) -> Self {
+            B
+        }
+    }
+}
+
+fn main() -> () {
+    let a: A = A;
+    let b: C::B = a.in$0to();
+}"#,
+            r#"
+struct A;
+
+mod C {
+    use crate::A;
+
+    pub(super) struct B;
+    impl From<A> for B {
+        fn from(a: A) -> Self {
+            B
+        }
+    }
+}
+
+fn main() -> () {
+    let a: A = A;
+    let b: C::B = C::B::from(a);
+}"#,
+        )
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
index 5cc110cf12b..6ed9bd85fcc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs
@@ -76,12 +76,19 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>)
             let name = to_upper_snake_case(&name.to_string());
             let usages = Definition::Local(local).usages(&ctx.sema).all();
             if let Some(usages) = usages.references.get(&ctx.file_id()) {
-                let name = make::name_ref(&name);
+                let name_ref = make::name_ref(&name);
 
                 for usage in usages {
                     let Some(usage) = usage.name.as_name_ref().cloned() else { continue };
-                    let usage = edit.make_mut(usage);
-                    ted::replace(usage.syntax(), name.clone_for_update().syntax());
+                    if let Some(record_field) = ast::RecordExprField::for_name_ref(&usage) {
+                        let record_field = edit.make_mut(record_field);
+                        let name_expr =
+                            make::expr_path(make::path_from_text(&name)).clone_for_update();
+                        record_field.replace_expr(name_expr);
+                    } else {
+                        let usage = edit.make_mut(usage);
+                        ted::replace(usage.syntax(), name_ref.clone_for_update().syntax());
+                    }
                 }
             }
 
@@ -120,8 +127,7 @@ fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool {
                 is_const &=
                     sema.resolve_method_call(&call).map(|it| it.is_const(sema.db)).unwrap_or(true)
             }
-            ast::Expr::BoxExpr(_)
-            | ast::Expr::ForExpr(_)
+            ast::Expr::ForExpr(_)
             | ast::Expr::ReturnExpr(_)
             | ast::Expr::TryExpr(_)
             | ast::Expr::YieldExpr(_)
@@ -180,6 +186,33 @@ fn foo() {
     }
 
     #[test]
+    fn usage_in_field_shorthand() {
+        check_assist(
+            promote_local_to_const,
+            r"
+struct Foo {
+    bar: usize,
+}
+
+fn main() {
+    let $0bar = 0;
+    let foo = Foo { bar };
+}
+",
+            r"
+struct Foo {
+    bar: usize,
+}
+
+fn main() {
+    const $0BAR: usize = 0;
+    let foo = Foo { bar: BAR };
+}
+",
+        )
+    }
+
+    #[test]
     fn not_applicable_non_const_meth_call() {
         cov_mark::check!(promote_local_non_const);
         check_assist_not_applicable(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index e2b82223289..cffa3f55c90 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -113,10 +113,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
                 Some(parent) => match (expr, parent) {
                     (ast::Expr::CastExpr(_), ast::Expr::CastExpr(_)) => false,
                     (
-                        ast::Expr::BoxExpr(_)
-                        | ast::Expr::PrefixExpr(_)
-                        | ast::Expr::RefExpr(_)
-                        | ast::Expr::MacroExpr(_),
+                        ast::Expr::PrefixExpr(_) | ast::Expr::RefExpr(_) | ast::Expr::MacroExpr(_),
                         ast::Expr::AwaitExpr(_)
                         | ast::Expr::CallExpr(_)
                         | ast::Expr::CastExpr(_)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs
index 24c3387457a..61e9bcdcc51 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs
@@ -48,6 +48,11 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext<
         return None;
     }
 
+    let new_result_ty =
+        make::ext::ty_result(type_ref.clone(), make::ty_placeholder()).clone_for_update();
+    let generic_args = new_result_ty.syntax().descendants().find_map(ast::GenericArgList::cast)?;
+    let last_genarg = generic_args.generic_args().last()?;
+
     acc.add(
         AssistId("wrap_return_type_in_result", AssistKind::RefactorRewrite),
         "Wrap return type in Result",
@@ -75,19 +80,12 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext<
                 ted::replace(ret_expr_arg.syntax(), ok_wrapped.syntax());
             }
 
-            let new_result_ty =
-                make::ext::ty_result(type_ref.clone(), make::ty_placeholder()).clone_for_update();
             let old_result_ty = edit.make_mut(type_ref.clone());
 
             ted::replace(old_result_ty.syntax(), new_result_ty.syntax());
 
             if let Some(cap) = ctx.config.snippet_cap {
-                let generic_args = new_result_ty
-                    .syntax()
-                    .descendants()
-                    .find_map(ast::GenericArgList::cast)
-                    .unwrap();
-                edit.add_placeholder_snippet(cap, generic_args.generic_args().last().unwrap());
+                edit.add_placeholder_snippet(cap, last_genarg);
             }
         },
     )
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 2ebb5ef9b19..6f973ab53ee 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -114,6 +114,7 @@ mod handlers {
     mod add_turbo_fish;
     mod apply_demorgan;
     mod auto_import;
+    mod bind_unused_param;
     mod change_visibility;
     mod convert_bool_then;
     mod convert_comment_block;
@@ -211,6 +212,7 @@ mod handlers {
     mod unwrap_result_return_type;
     mod unqualify_method_call;
     mod wrap_return_type_in_result;
+    mod into_to_qualified_from;
 
     pub(crate) fn all() -> &'static [Handler] {
         &[
@@ -224,6 +226,7 @@ mod handlers {
             add_turbo_fish::add_turbo_fish,
             apply_demorgan::apply_demorgan,
             auto_import::auto_import,
+            bind_unused_param::bind_unused_param,
             change_visibility::change_visibility,
             convert_bool_then::convert_bool_then_to_if,
             convert_bool_then::convert_if_to_bool_then,
@@ -274,6 +277,7 @@ mod handlers {
             inline_local_variable::inline_local_variable,
             inline_type_alias::inline_type_alias,
             inline_type_alias::inline_type_alias_uses,
+            into_to_qualified_from::into_to_qualified_from,
             introduce_named_generic::introduce_named_generic,
             introduce_named_lifetime::introduce_named_lifetime,
             invert_if::invert_if,
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 6eadc3dbcbc..dfaa53449f4 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
@@ -266,6 +266,21 @@ pub mod std { pub mod collections { pub struct HashMap { } } }
 }
 
 #[test]
+fn doctest_bind_unused_param() {
+    check_doc_test(
+        "bind_unused_param",
+        r#####"
+fn some_function(x: i32$0) {}
+"#####,
+        r#####"
+fn some_function(x: i32) {
+    let _ = x;
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_change_visibility() {
     check_doc_test(
         "change_visibility",
@@ -694,25 +709,12 @@ fn doctest_extract_expressions_from_format_string() {
     check_doc_test(
         "extract_expressions_from_format_string",
         r#####"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
-macro_rules! print {
-    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-}
-
+//- minicore: fmt
 fn main() {
     print!("{var} {x + 1}$0");
 }
 "#####,
         r#####"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
-macro_rules! print {
-    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-}
-
 fn main() {
     print!("{var} {}"$0, x + 1);
 }
@@ -1755,6 +1757,40 @@ fn foo() {
 }
 
 #[test]
+fn doctest_into_to_qualified_from() {
+    check_doc_test(
+        "into_to_qualified_from",
+        r#####"
+//- minicore: from
+struct B;
+impl From<i32> for B {
+    fn from(a: i32) -> Self {
+       B
+    }
+}
+
+fn main() -> () {
+    let a = 3;
+    let b: B = a.in$0to();
+}
+"#####,
+        r#####"
+struct B;
+impl From<i32> for B {
+    fn from(a: i32) -> Self {
+       B
+    }
+}
+
+fn main() -> () {
+    let a = 3;
+    let b: B = B::from(a);
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_introduce_named_generic() {
     check_doc_test(
         "introduce_named_generic",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
index f74ebfae02c..16704d598ef 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
@@ -103,7 +103,6 @@ pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>)
 
         match expr {
             ast::Expr::RefExpr(inner) => next_expr = inner.expr(),
-            ast::Expr::BoxExpr(inner) => next_expr = inner.expr(),
             ast::Expr::AwaitExpr(inner) => next_expr = inner.expr(),
             // ast::Expr::BlockExpr(block) => expr = block.tail_expr(),
             ast::Expr::CastExpr(inner) => next_expr = inner.expr(),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
index 62bdb6ee688..87a286778e6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -1,10 +1,8 @@
 //! Completion for cfg
 
-use std::iter;
-
 use ide_db::SymbolKind;
 use itertools::Itertools;
-use syntax::SyntaxKind;
+use syntax::{algo, ast::Ident, AstToken, Direction, NodeOrToken, SyntaxKind};
 
 use crate::{completions::Completions, context::CompletionContext, CompletionItem};
 
@@ -15,31 +13,44 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
         acc.add(completion.build(ctx.db));
     };
 
-    let previous = iter::successors(ctx.original_token.prev_token(), |t| {
-        (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
-            .then(|| t.prev_token())
-            .flatten()
-    })
-    .find(|t| matches!(t.kind(), SyntaxKind::IDENT));
-
-    match previous.as_ref().map(|p| p.text()) {
-        Some("target_arch") => KNOWN_ARCH.iter().copied().for_each(add_completion),
-        Some("target_env") => KNOWN_ENV.iter().copied().for_each(add_completion),
-        Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion),
-        Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion),
-        Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
-        Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
-            let insert_text = format!(r#""{s}""#);
-            let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
-            item.insert_text(insert_text);
+    // FIXME: Move this into context/analysis.rs
+    let previous = ctx
+        .original_token
+        .prev_token()
+        .and_then(|it| {
+            if matches!(it.kind(), SyntaxKind::EQ) {
+                Some(it.into())
+            } else {
+                algo::non_trivia_sibling(it.into(), Direction::Prev)
+            }
+        })
+        .filter(|t| matches!(t.kind(), SyntaxKind::EQ))
+        .and_then(|it| algo::non_trivia_sibling(it.prev_sibling_or_token()?, Direction::Prev))
+        .map(|it| match it {
+            NodeOrToken::Node(_) => None,
+            NodeOrToken::Token(t) => Ident::cast(t),
+        });
+    match previous {
+        Some(None) => (),
+        Some(Some(p)) => match p.text() {
+            "target_arch" => KNOWN_ARCH.iter().copied().for_each(add_completion),
+            "target_env" => KNOWN_ENV.iter().copied().for_each(add_completion),
+            "target_os" => KNOWN_OS.iter().copied().for_each(add_completion),
+            "target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion),
+            "target_endian" => ["little", "big"].into_iter().for_each(add_completion),
+            name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
+                let insert_text = format!(r#""{s}""#);
+                let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
+                item.insert_text(insert_text);
 
-            acc.add(item.build(ctx.db));
-        }),
+                acc.add(item.build(ctx.db));
+            }),
+        },
         None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
             let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
             acc.add(item.build(ctx.db));
         }),
-    };
+    }
 }
 
 const KNOWN_ARCH: [&str; 20] = [
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
index 9447bc7db0a..90dac1902a4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
@@ -1,6 +1,6 @@
 //! Completion for derives
-use hir::{HasAttrs, ScopeDef};
-use ide_db::SymbolKind;
+use hir::ScopeDef;
+use ide_db::{documentation::HasDocs, SymbolKind};
 use itertools::Itertools;
 use syntax::SmolStr;
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs
index 6bc6f34ed41..f9dec538064 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs
@@ -1,5 +1,5 @@
 //! Completion for lints
-use ide_db::{generated::lints::Lint, SymbolKind};
+use ide_db::{documentation::Documentation, generated::lints::Lint, SymbolKind};
 use syntax::ast;
 
 use crate::{context::CompletionContext, item::CompletionItem, Completions};
@@ -55,7 +55,7 @@ pub(super) fn complete_lint(
             _ => name.to_owned(),
         };
         let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label);
-        item.documentation(hir::Documentation::new(description.to_owned()));
+        item.documentation(Documentation::new(description.to_owned()));
         item.add_to(acc, ctx.db)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
index 0d0e143f5f6..f9cde44667b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
@@ -1,7 +1,7 @@
 //! Completion for extern crates
 
-use hir::{HasAttrs, Name};
-use ide_db::SymbolKind;
+use hir::Name;
+use ide_db::{documentation::HasDocs, SymbolKind};
 
 use crate::{context::CompletionContext, CompletionItem, CompletionItemKind};
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
index 8e904fd605a..cecbe75391d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs
@@ -51,9 +51,7 @@ mod tests {
     fn works_when_wrapped() {
         check(
             r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
+//- minicore: fmt
 macro_rules! print {
     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
 }
@@ -70,9 +68,7 @@ fn main() {
     fn no_completion_without_brace() {
         check(
             r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
+//- minicore: fmt
 fn main() {
     let foobar = 1;
     format_args!("f$0");
@@ -87,18 +83,13 @@ fn main() {
         check_edit(
             "foobar",
             r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
+//- minicore: fmt
 fn main() {
     let foobar = 1;
     format_args!("{f$0");
 }
 "#,
             r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
 fn main() {
     let foobar = 1;
     format_args!("{foobar");
@@ -108,18 +99,13 @@ fn main() {
         check_edit(
             "foobar",
             r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
+//- minicore: fmt
 fn main() {
     let foobar = 1;
     format_args!("{$0");
 }
 "#,
             r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
 fn main() {
     let foobar = 1;
     format_args!("{foobar");
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 269e40e6ef5..42dfbfc7d9a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -33,8 +33,8 @@
 
 use hir::{self, HasAttrs};
 use ide_db::{
-    path_transform::PathTransform, syntax_helpers::insert_whitespace_into_node,
-    traits::get_missing_assoc_items, SymbolKind,
+    documentation::HasDocs, path_transform::PathTransform,
+    syntax_helpers::insert_whitespace_into_node, traits::get_missing_assoc_items, SymbolKind,
 };
 use syntax::{
     ast::{self, edit_in_place::AttrsOwnerEdit, HasTypeBounds},
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 2ffe1233744..fc21bba456b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -2,8 +2,12 @@
 
 mod format_like;
 
-use hir::{Documentation, HasAttrs};
-use ide_db::{imports::insert_use::ImportScope, ty_filter::TryEnum, SnippetCap};
+use ide_db::{
+    documentation::{Documentation, HasDocs},
+    imports::insert_use::ImportScope,
+    ty_filter::TryEnum,
+    SnippetCap,
+};
 use syntax::{
     ast::{self, make, AstNode, AstToken},
     SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
index e9831a5b2a1..3ff68b97882 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
@@ -1,7 +1,6 @@
 //! This file provides snippet completions, like `pd` => `eprintln!(...)`.
 
-use hir::Documentation;
-use ide_db::{imports::insert_use::ImportScope, SnippetCap};
+use ide_db::{documentation::Documentation, imports::insert_use::ImportScope, SnippetCap};
 
 use crate::{
     context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified},
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 0309952c29a..c45cc8d7b37 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -2,8 +2,11 @@
 
 use std::fmt;
 
-use hir::{Documentation, Mutability};
-use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind};
+use hir::Mutability;
+use ide_db::{
+    documentation::Documentation, imports::import_assets::LocatedImport, RootDatabase, SnippetCap,
+    SymbolKind,
+};
 use itertools::Itertools;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 1953eb47957..dfe8fe7e2f7 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -12,7 +12,10 @@ pub(crate) mod literal;
 
 use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
 use ide_db::{
-    helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind,
+    documentation::{Documentation, HasDocs},
+    helpers::item_name,
+    imports::import_assets::LocatedImport,
+    RootDatabase, SnippetCap, SymbolKind,
 };
 use syntax::{AstNode, SmolStr, SyntaxKind, TextRange};
 
@@ -114,7 +117,7 @@ impl<'a> RenderContext<'a> {
     }
 
     // FIXME: remove this
-    fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
+    fn docs(&self, def: impl HasDocs) -> Option<Documentation> {
         def.docs(self.db())
     }
 }
@@ -409,7 +412,7 @@ fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind {
     }
 }
 
-fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
+fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<Documentation> {
     use hir::ModuleDef::*;
     match resolution {
         ScopeDef::ModuleDef(Module(it)) => it.docs(db),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index 728d236dff4..b218502f7f0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -1,7 +1,10 @@
 //! Renderer for `enum` variants.
 
-use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
-use ide_db::SymbolKind;
+use hir::{db::HirDatabase, StructKind};
+use ide_db::{
+    documentation::{Documentation, HasDocs},
+    SymbolKind,
+};
 
 use crate::{
     context::{CompletionContext, PathCompletionCtx, PathKind},
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index ce7af1d3400..68d175c2bd5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -1,7 +1,7 @@
 //! Renderer for macro invocations.
 
-use hir::{Documentation, HirDisplay};
-use ide_db::SymbolKind;
+use hir::HirDisplay;
+use ide_db::{documentation::Documentation, SymbolKind};
 use syntax::SmolStr;
 
 use crate::{
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index d06abc5e91e..6f998119b7c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -1,7 +1,7 @@
 //! Renderer for patterns.
 
-use hir::{db::HirDatabase, HasAttrs, Name, StructKind};
-use ide_db::SnippetCap;
+use hir::{db::HirDatabase, Name, StructKind};
+use ide_db::{documentation::HasDocs, SnippetCap};
 use itertools::Itertools;
 use syntax::SmolStr;
 
@@ -103,7 +103,7 @@ fn build_completion(
     label: SmolStr,
     lookup: SmolStr,
     pat: String,
-    def: impl HasAttrs + Copy,
+    def: impl HasDocs + Copy,
     adt_ty: hir::Type,
     // Missing in context of match statement completions
     is_variant_missing: bool,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index 1aaf3958726..d8c134c533b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -67,11 +67,6 @@ struct Foo;
 }
 
 #[test]
-fn inside_nested_attr() {
-    check(r#"#[cfg($0)]"#, expect![[]])
-}
-
-#[test]
 fn with_existing_attr() {
     check(
         r#"#[no_mangle] #[$0] mcall!();"#,
@@ -636,6 +631,32 @@ mod cfg {
     use super::*;
 
     #[test]
+    fn inside_cfg() {
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg($0)]
+"#,
+            expect![[r#"
+                ba dbg
+                ba opt_level
+                ba test
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg(b$0)]
+"#,
+            expect![[r#"
+                ba dbg
+                ba opt_level
+                ba test
+            "#]],
+        );
+    }
+
+    #[test]
     fn cfg_target_endian() {
         check(
             r#"#[cfg(target_endian = $0"#,
@@ -644,6 +665,13 @@ mod cfg {
                 ba little
             "#]],
         );
+        check(
+            r#"#[cfg(target_endian = b$0"#,
+            expect![[r#"
+                ba big
+                ba little
+            "#]],
+        );
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
new file mode 100644
index 00000000000..26f3cd28a27
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -0,0 +1,281 @@
+//! Documentation attribute related utilties.
+use either::Either;
+use hir::{
+    db::{DefDatabase, HirDatabase},
+    resolve_doc_path_on, AttrId, AttrSourceMap, AttrsWithOwner, HasAttrs, InFile,
+};
+use itertools::Itertools;
+use syntax::{
+    ast::{self, IsString},
+    AstToken,
+};
+use text_edit::{TextRange, TextSize};
+
+/// Holds documentation
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Documentation(String);
+
+impl Documentation {
+    pub fn new(s: String) -> Self {
+        Documentation(s)
+    }
+
+    pub fn as_str(&self) -> &str {
+        &self.0
+    }
+}
+
+impl From<Documentation> for String {
+    fn from(Documentation(string): Documentation) -> Self {
+        string
+    }
+}
+
+pub trait HasDocs: HasAttrs {
+    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
+    fn resolve_doc_path(
+        self,
+        db: &dyn HirDatabase,
+        link: &str,
+        ns: Option<hir::Namespace>,
+    ) -> Option<hir::DocLinkDef>;
+}
+/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
+#[derive(Debug)]
+pub struct DocsRangeMap {
+    source_map: AttrSourceMap,
+    // (docstring-line-range, attr_index, attr-string-range)
+    // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
+    // the original (untrimmed) syntax doc line
+    mapping: Vec<(TextRange, AttrId, TextRange)>,
+}
+
+impl DocsRangeMap {
+    /// Maps a [`TextRange`] relative to the documentation string back to its AST range
+    pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
+        let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
+        let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
+        if !line_docs_range.contains_range(range) {
+            return None;
+        }
+
+        let relative_range = range - line_docs_range.start();
+
+        let InFile { file_id, value: source } = self.source_map.source_of_id(idx);
+        match source {
+            Either::Left(attr) => {
+                let string = get_doc_string_in_attr(attr)?;
+                let text_range = string.open_quote_text_range()?;
+                let range = TextRange::at(
+                    text_range.end() + original_line_src_range.start() + relative_range.start(),
+                    string.syntax().text_range().len().min(range.len()),
+                );
+                Some(InFile { file_id, value: range })
+            }
+            Either::Right(comment) => {
+                let text_range = comment.syntax().text_range();
+                let range = TextRange::at(
+                    text_range.start()
+                        + TextSize::try_from(comment.prefix().len()).ok()?
+                        + original_line_src_range.start()
+                        + relative_range.start(),
+                    text_range.len().min(range.len()),
+                );
+                Some(InFile { file_id, value: range })
+            }
+        }
+    }
+}
+
+pub fn docs_with_rangemap(
+    db: &dyn DefDatabase,
+    attrs: &AttrsWithOwner,
+) -> Option<(Documentation, DocsRangeMap)> {
+    let docs =
+        attrs.by_key("doc").attrs().filter_map(|attr| attr.string_value().map(|s| (s, attr.id)));
+    let indent = doc_indent(attrs);
+    let mut buf = String::new();
+    let mut mapping = Vec::new();
+    for (doc, idx) in docs {
+        if !doc.is_empty() {
+            let mut base_offset = 0;
+            for raw_line in doc.split('\n') {
+                let line = raw_line.trim_end();
+                let line_len = line.len();
+                let (offset, line) = match line.char_indices().nth(indent) {
+                    Some((offset, _)) => (offset, &line[offset..]),
+                    None => (0, line),
+                };
+                let buf_offset = buf.len();
+                buf.push_str(line);
+                mapping.push((
+                    TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
+                    idx,
+                    TextRange::at(
+                        (base_offset + offset).try_into().ok()?,
+                        line_len.try_into().ok()?,
+                    ),
+                ));
+                buf.push('\n');
+                base_offset += raw_line.len() + 1;
+            }
+        } else {
+            buf.push('\n');
+        }
+    }
+    buf.pop();
+    if buf.is_empty() {
+        None
+    } else {
+        Some((Documentation(buf), DocsRangeMap { mapping, source_map: attrs.source_map(db) }))
+    }
+}
+
+pub fn docs_from_attrs(attrs: &hir::Attrs) -> Option<String> {
+    let docs = attrs.by_key("doc").attrs().filter_map(|attr| attr.string_value());
+    let indent = doc_indent(attrs);
+    let mut buf = String::new();
+    for doc in docs {
+        // str::lines doesn't yield anything for the empty string
+        if !doc.is_empty() {
+            buf.extend(Itertools::intersperse(
+                doc.lines().map(|line| {
+                    line.char_indices()
+                        .nth(indent)
+                        .map_or(line, |(offset, _)| &line[offset..])
+                        .trim_end()
+                }),
+                "\n",
+            ));
+        }
+        buf.push('\n');
+    }
+    buf.pop();
+    if buf.is_empty() {
+        None
+    } else {
+        Some(buf)
+    }
+}
+
+macro_rules! impl_has_docs {
+    ($($def:ident,)*) => {$(
+        impl HasDocs for hir::$def {
+            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+                docs_from_attrs(&self.attrs(db)).map(Documentation)
+            }
+            fn resolve_doc_path(
+                self,
+                db: &dyn HirDatabase,
+                link: &str,
+                ns: Option<hir::Namespace>
+            ) -> Option<hir::DocLinkDef> {
+                resolve_doc_path_on(db, self, link, ns)
+            }
+        }
+    )*};
+}
+
+impl_has_docs![
+    Variant, Field, Static, Const, Trait, TraitAlias, TypeAlias, Macro, Function, Adt, Module,
+    Impl,
+];
+
+macro_rules! impl_has_docs_enum {
+    ($($variant:ident),* for $enum:ident) => {$(
+        impl HasDocs for hir::$variant {
+            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+                hir::$enum::$variant(self).docs(db)
+            }
+            fn resolve_doc_path(
+                self,
+                db: &dyn HirDatabase,
+                link: &str,
+                ns: Option<hir::Namespace>
+            ) -> Option<hir::DocLinkDef> {
+                hir::$enum::$variant(self).resolve_doc_path(db, link, ns)
+            }
+        }
+    )*};
+}
+
+impl_has_docs_enum![Struct, Union, Enum for Adt];
+
+impl HasDocs for hir::AssocItem {
+    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+        match self {
+            hir::AssocItem::Function(it) => it.docs(db),
+            hir::AssocItem::Const(it) => it.docs(db),
+            hir::AssocItem::TypeAlias(it) => it.docs(db),
+        }
+    }
+
+    fn resolve_doc_path(
+        self,
+        db: &dyn HirDatabase,
+        link: &str,
+        ns: Option<hir::Namespace>,
+    ) -> Option<hir::DocLinkDef> {
+        match self {
+            hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
+            hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
+            hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
+        }
+    }
+}
+
+impl HasDocs for hir::ExternCrateDecl {
+    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+        let crate_docs =
+            docs_from_attrs(&self.resolved_crate(db)?.root_module().attrs(db)).map(String::from);
+        let decl_docs = docs_from_attrs(&self.attrs(db)).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<hir::Namespace>,
+    ) -> Option<hir::DocLinkDef> {
+        resolve_doc_path_on(db, self, link, ns)
+    }
+}
+
+fn get_doc_string_in_attr(it: &ast::Attr) -> Option<ast::String> {
+    match it.expr() {
+        // #[doc = lit]
+        Some(ast::Expr::Literal(lit)) => match lit.kind() {
+            ast::LiteralKind::String(it) => Some(it),
+            _ => None,
+        },
+        // #[cfg_attr(..., doc = "", ...)]
+        None => {
+            // FIXME: See highlight injection for what to do here
+            None
+        }
+        _ => None,
+    }
+}
+
+fn doc_indent(attrs: &hir::Attrs) -> usize {
+    attrs
+        .by_key("doc")
+        .attrs()
+        .filter_map(|attr| attr.string_value())
+        .flat_map(|s| s.lines())
+        .filter(|line| !line.chars().all(|c| c.is_whitespace()))
+        .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
+        .min()
+        .unwrap_or(0)
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index ac3511ba47b..226def4d526 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -22,6 +22,7 @@ pub mod symbol_index;
 pub mod traits;
 pub mod ty_filter;
 pub mod use_trivial_constructor;
+pub mod documentation;
 
 pub mod imports {
     pub mod import_assets;
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 aa0bb7cce69..353a9749a37 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -71,12 +71,29 @@ impl Definition {
         sema: &Semantics<'_, RootDatabase>,
         new_name: &str,
     ) -> Result<SourceChange> {
+        // self.krate() returns None if
+        // self is a built-in attr, built-in type or tool module.
+        // it is not allowed for these defs to be renamed.
+        // cases where self.krate() is None is handled below.
+        if let Some(krate) = self.krate(sema.db) {
+            if !krate.origin(sema.db).is_local() {
+                bail!("Cannot rename a non-local definition.")
+            }
+        }
+
         match *self {
             Definition::Module(module) => rename_mod(sema, module, new_name),
+            Definition::ToolModule(_) => {
+                bail!("Cannot rename a tool module")
+            }
             Definition::BuiltinType(_) => {
                 bail!("Cannot rename builtin type")
             }
+            Definition::BuiltinAttr(_) => {
+                bail!("Cannot rename a builtin attr.")
+            }
             Definition::SelfType(_) => bail!("Cannot rename `Self`"),
+            Definition::Macro(mac) => rename_reference(sema, Definition::Macro(mac), new_name),
             def => rename_reference(sema, def, new_name),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs b/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs
index e27e23867a8..ab2a250289c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs
@@ -1,5 +1,7 @@
 //! Rustdoc specific doc comment handling
 
+use crate::documentation::Documentation;
+
 // stripped down version of https://github.com/rust-lang/rust/blob/392ba2ba1a7d6c542d2459fb8133bebf62a4a423/src/librustdoc/html/markdown.rs#L810-L933
 pub fn is_rust_fence(s: &str) -> bool {
     let mut seen_rust_tags = false;
@@ -32,3 +34,170 @@ pub fn is_rust_fence(s: &str) -> bool {
 
     !seen_other_tags || seen_rust_tags
 }
+
+const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+
+pub fn format_docs(src: &Documentation) -> String {
+    format_docs_(src.as_str())
+}
+
+fn format_docs_(src: &str) -> String {
+    let mut processed_lines = Vec::new();
+    let mut in_code_block = false;
+    let mut is_rust = false;
+
+    for mut line in src.lines() {
+        if in_code_block && is_rust && code_line_ignored_by_rustdoc(line) {
+            continue;
+        }
+
+        if let Some(header) = RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
+        {
+            in_code_block ^= true;
+
+            if in_code_block {
+                is_rust = is_rust_fence(header);
+
+                if is_rust {
+                    line = "```rust";
+                }
+            }
+        }
+
+        if in_code_block {
+            let trimmed = line.trim_start();
+            if is_rust && trimmed.starts_with("##") {
+                line = &trimmed[1..];
+            }
+        }
+
+        processed_lines.push(line);
+    }
+    processed_lines.join("\n")
+}
+
+fn code_line_ignored_by_rustdoc(line: &str) -> bool {
+    let trimmed = line.trim();
+    trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t")
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_format_docs_adds_rust() {
+        let comment = "```\nfn some_rust() {}\n```";
+        assert_eq!(format_docs_(comment), "```rust\nfn some_rust() {}\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_plain_text() {
+        let comment = "```text\nthis is plain text\n```";
+        assert_eq!(format_docs_(comment), "```text\nthis is plain text\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_non_rust() {
+        let comment = "```sh\nsupposedly shell code\n```";
+        assert_eq!(format_docs_(comment), "```sh\nsupposedly shell code\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_rust_alias() {
+        let comment = "```ignore\nlet z = 55;\n```";
+        assert_eq!(format_docs_(comment), "```rust\nlet z = 55;\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_complex_code_block_attrs() {
+        let comment = "```rust,no_run\nlet z = 55;\n```";
+        assert_eq!(format_docs_(comment), "```rust\nlet z = 55;\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_error_codes() {
+        let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```";
+        assert_eq!(format_docs_(comment), "```rust\nlet b = 0 as *const _;\n```");
+    }
+
+    #[test]
+    fn test_format_docs_skips_comments_in_rust_block() {
+        let comment =
+            "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n   #    \n #\tskip3\n\t#\t\n```";
+        assert_eq!(format_docs_(comment), "```rust\n#stay1\nstay2\n```");
+    }
+
+    #[test]
+    fn test_format_docs_does_not_skip_lines_if_plain_text() {
+        let comment =
+            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```";
+        assert_eq!(
+            format_docs_(comment),
+            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```",
+        );
+    }
+
+    #[test]
+    fn test_format_docs_keeps_comments_outside_of_rust_block() {
+        let comment = " # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t";
+        assert_eq!(format_docs_(comment), comment);
+    }
+
+    #[test]
+    fn test_format_docs_preserves_newlines() {
+        let comment = "this\nis\nmultiline";
+        assert_eq!(format_docs_(comment), comment);
+    }
+
+    #[test]
+    fn test_code_blocks_in_comments_marked_as_rust() {
+        let comment = r#"```rust
+fn main(){}
+```
+Some comment.
+```
+let a = 1;
+```"#;
+
+        assert_eq!(
+            format_docs_(comment),
+            "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
+        );
+    }
+
+    #[test]
+    fn test_code_blocks_in_comments_marked_as_text() {
+        let comment = r#"```text
+filler
+text
+```
+Some comment.
+```
+let a = 1;
+```"#;
+
+        assert_eq!(
+            format_docs_(comment),
+            "```text\nfiller\ntext\n```\nSome comment.\n```rust\nlet a = 1;\n```"
+        );
+    }
+
+    #[test]
+    fn test_format_docs_handles_escape_double_hashes() {
+        let comment = r#"```rust
+let s = "foo
+## bar # baz";
+```"#;
+
+        assert_eq!(format_docs_(comment), "```rust\nlet s = \"foo\n# bar # baz\";\n```");
+    }
+
+    #[test]
+    fn test_format_docs_handles_double_hashes_non_rust() {
+        let comment = r#"```markdown
+## A second-level heading
+```"#;
+        assert_eq!(format_docs_(comment), "```markdown\n## A second-level heading\n```");
+    }
+}
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 7e00d368652..9c4f0ac8c9f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -6,7 +6,7 @@
 
 use std::mem;
 
-use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
+use base_db::{salsa::Database, FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 use hir::{
     AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility,
 };
@@ -221,7 +221,6 @@ impl Definition {
         }
 
         // def is crate root
-        // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
         if let &Definition::Module(module) = self {
             if module.is_crate_root() {
                 return SearchScope::reverse_dependencies(db, module.krate());
@@ -393,7 +392,10 @@ impl<'a> FindUsages<'a> {
         let name = match self.def {
             // special case crate modules as these do not have a proper name
             Definition::Module(module) if module.is_crate_root() => {
-                // FIXME: This assumes the crate name is always equal to its display name when it really isn't
+                // FIXME: This assumes the crate name is always equal to its display name when it
+                // really isn't
+                // we should instead look at the dependency edge name and recursively search our way
+                // up the ancestors
                 module
                     .krate()
                     .display_name(self.sema.db)
@@ -468,6 +470,7 @@ impl<'a> FindUsages<'a> {
         };
 
         for (text, file_id, search_range) in scope_files(sema, &search_scope) {
+            self.sema.db.unwind_if_cancelled();
             let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 
             // Search for occurrences of the items name
@@ -504,6 +507,7 @@ impl<'a> FindUsages<'a> {
             let finder = &Finder::new("super");
 
             for (text, file_id, search_range) in scope_files(sema, &scope) {
+                self.sema.db.unwind_if_cancelled();
                 let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
 
                 for offset in match_indices(&text, finder, search_range) {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
index acf0a67de4a..8302b015dda 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
@@ -1,10 +1,10 @@
 //! Tools to work with format string literals for the `format_args!` family of macros.
-use crate::syntax_helpers::node_ext::macro_call_for_string_token;
 use syntax::{
     ast::{self, IsString},
-    TextRange, TextSize,
+    AstNode, AstToken, TextRange, TextSize,
 };
 
+// FIXME: This can probably be re-implemented via the HIR?
 pub fn is_format_string(string: &ast::String) -> bool {
     // Check if `string` is a format string argument of a macro invocation.
     // `string` is a string literal, mapped down into the innermost macro expansion.
@@ -15,19 +15,9 @@ pub fn is_format_string(string: &ast::String) -> bool {
     // This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
     // strings. It still fails for `concat!("{", "}")`, but that is rare.
     (|| {
-        let name = macro_call_for_string_token(string)?.path()?.segment()?.name_ref()?;
-
-        if !matches!(
-            name.text().as_str(),
-            "format_args" | "format_args_nl" | "const_format_args" | "panic_2015" | "panic_2021"
-        ) {
-            return None;
-        }
-
-        // NB: we match against `panic_2015`/`panic_2021` here because they have a special-cased arm for
-        // `"{}"`, which otherwise wouldn't get highlighted.
-
-        Some(())
+        let lit = string.syntax().parent().and_then(ast::Literal::cast)?;
+        let fa = lit.syntax().parent().and_then(ast::FormatArgsExpr::cast)?;
+        (fa.template()? == ast::Expr::Literal(lit)).then_some(|| ())
     })()
     .is_some()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index 22ced69d81e..e4e735cecd8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -312,7 +312,6 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         ast::Expr::ArrayExpr(_)
         | ast::Expr::AwaitExpr(_)
         | ast::Expr::BinExpr(_)
-        | ast::Expr::BoxExpr(_)
         | ast::Expr::BreakExpr(_)
         | ast::Expr::CallExpr(_)
         | ast::Expr::CastExpr(_)
@@ -335,7 +334,10 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         | ast::Expr::LetExpr(_)
         | ast::Expr::UnderscoreExpr(_)
         | ast::Expr::YieldExpr(_)
-        | ast::Expr::YeetExpr(_) => cb(expr),
+        | ast::Expr::YeetExpr(_)
+        | ast::Expr::OffsetOfExpr(_)
+        | ast::Expr::FormatArgsExpr(_)
+        | ast::Expr::AsmExpr(_) => cb(expr),
     }
 }
 
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 f54cdd63bbb..7ca0a0eab2b 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
@@ -157,6 +157,7 @@ struct S;
     fn macro_diag_builtin() {
         check_diagnostics(
             r#"
+//- minicore: fmt
 #[rustc_builtin_macro]
 macro_rules! env {}
 
@@ -166,9 +167,6 @@ macro_rules! include {}
 #[rustc_builtin_macro]
 macro_rules! compile_error {}
 
-#[rustc_builtin_macro]
-macro_rules! format_args { () => {} }
-
 fn main() {
     // Test a handful of built-in (eager) macros:
 
@@ -189,7 +187,7 @@ fn main() {
     // Lazy:
 
     format_args!();
-  //^^^^^^^^^^^ error: no rule matches input tokens
+  //^^^^^^^^^^^ error: Syntax Error in Expansion: expected expression
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 6238c7e09e9..8265e0b1c11 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -1,10 +1,37 @@
+use either::Either;
+use hir::InFile;
 use syntax::{
     ast::{self, HasArgList},
-    AstNode, TextRange,
+    AstNode, SyntaxNodePtr, TextRange,
 };
 
 use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
+// Diagnostic: mismatched-tuple-struct-pat-arg-count
+//
+// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
+pub(crate) fn mismatched_tuple_struct_pat_arg_count(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::MismatchedTupleStructPatArgCount,
+) -> Diagnostic {
+    let s = if d.found == 1 { "" } else { "s" };
+    let s2 = if d.expected == 1 { "" } else { "s" };
+    let message = format!(
+        "this pattern has {} field{s}, but the corresponding tuple struct has {} field{s2}",
+        d.found, d.expected
+    );
+    Diagnostic::new(
+        DiagnosticCode::RustcHardError("E0023"),
+        message,
+        invalid_args_range(
+            ctx,
+            d.expr_or_pat.clone().map(|it| it.either(Into::into, Into::into)),
+            d.expected,
+            d.found,
+        ),
+    )
+}
+
 // Diagnostic: mismatched-arg-count
 //
 // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
@@ -14,31 +41,63 @@ pub(crate) fn mismatched_arg_count(
 ) -> Diagnostic {
     let s = if d.expected == 1 { "" } else { "s" };
     let message = format!("expected {} argument{s}, found {}", d.expected, d.found);
-    Diagnostic::new(DiagnosticCode::RustcHardError("E0107"), message, invalid_args_range(ctx, d))
+    Diagnostic::new(
+        DiagnosticCode::RustcHardError("E0107"),
+        message,
+        invalid_args_range(ctx, d.call_expr.clone().map(Into::into), d.expected, d.found),
+    )
 }
 
-fn invalid_args_range(ctx: &DiagnosticsContext<'_>, d: &hir::MismatchedArgCount) -> TextRange {
-    adjusted_display_range::<ast::Expr>(ctx, d.call_expr.clone().map(|it| it.into()), &|expr| {
-        let arg_list = match expr {
-            ast::Expr::CallExpr(call) => call.arg_list()?,
-            ast::Expr::MethodCallExpr(call) => call.arg_list()?,
+fn invalid_args_range(
+    ctx: &DiagnosticsContext<'_>,
+    source: InFile<SyntaxNodePtr>,
+    expected: usize,
+    found: usize,
+) -> TextRange {
+    adjusted_display_range::<Either<ast::Expr, ast::TupleStructPat>>(ctx, source, &|expr| {
+        let (text_range, r_paren_token, expected_arg) = match expr {
+            Either::Left(ast::Expr::CallExpr(call)) => {
+                let arg_list = call.arg_list()?;
+                (
+                    arg_list.syntax().text_range(),
+                    arg_list.r_paren_token(),
+                    arg_list.args().nth(expected).map(|it| it.syntax().text_range()),
+                )
+            }
+            Either::Left(ast::Expr::MethodCallExpr(call)) => {
+                let arg_list = call.arg_list()?;
+                (
+                    arg_list.syntax().text_range(),
+                    arg_list.r_paren_token(),
+                    arg_list.args().nth(expected).map(|it| it.syntax().text_range()),
+                )
+            }
+            Either::Right(pat) => {
+                let r_paren = pat.r_paren_token()?;
+                let l_paren = pat.l_paren_token()?;
+                (
+                    l_paren.text_range().cover(r_paren.text_range()),
+                    Some(r_paren),
+                    pat.fields().nth(expected).map(|it| it.syntax().text_range()),
+                )
+            }
             _ => return None,
         };
-        if d.found < d.expected {
-            if d.found == 0 {
-                return Some(arg_list.syntax().text_range());
+        if found < expected {
+            if found == 0 {
+                return Some(text_range);
             }
-            if let Some(r_paren) = arg_list.r_paren_token() {
+            if let Some(r_paren) = r_paren_token {
                 return Some(r_paren.text_range());
             }
         }
-        if d.expected < d.found {
-            if d.expected == 0 {
-                return Some(arg_list.syntax().text_range());
+        if expected < found {
+            if expected == 0 {
+                return Some(text_range);
             }
-            let zip = arg_list.args().nth(d.expected).zip(arg_list.r_paren_token());
+            let zip = expected_arg.zip(r_paren_token);
             if let Some((arg, r_paren)) = zip {
-                return Some(arg.syntax().text_range().cover(r_paren.text_range()));
+                return Some(arg.cover(r_paren.text_range()));
             }
         }
 
@@ -331,4 +390,21 @@ fn g() {
             "#,
         )
     }
+
+    #[test]
+    fn tuple_struct_pat() {
+        check_diagnostics(
+            r#"
+struct S(u32, u32);
+fn f(
+    S(a, b, c): S,
+         // ^^ error: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
+    S(): S,
+  // ^^ error: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+    S(e, f, .., g, d): S
+  //        ^^^^^^^^^ error: this pattern has 4 fields, but the corresponding tuple struct has 2 fields
+) {}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 82a9a3bd559..06b03d3d198 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -319,6 +319,7 @@ fn main() {
     match Either::A {
         Either::A => (),
         Either::B() => (),
+              // ^^ error: this pattern has 0 fields, but the corresponding tuple struct has 1 field
     }
 }
 "#,
@@ -334,9 +335,11 @@ enum A { B(isize, isize), C }
 fn main() {
     match A::B(1, 2) {
         A::B(_, _, _) => (),
+                // ^^ error: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
     }
     match A::B(1, 2) {
         A::C(_) => (),
+         // ^^^ error: this pattern has 1 field, but the corresponding tuple struct has 0 fields
     }
 }
 "#,
@@ -846,6 +849,7 @@ fn main() {
 struct Foo { }
 fn main(f: Foo) {
     match f { Foo { bar } => () }
+                 // ^^^ error: no such field
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index e0c3bedce46..d056e5c85cc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -76,7 +76,7 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Di
         "variable does not need to be mutable",
         ast,
     )
-    .experimental() // Not supporting `#[allow(unused_mut)]` leads to false positive.
+    .experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
     .with_fixes(fixes)
 }
 
@@ -1173,4 +1173,27 @@ fn f() {
 "#,
         );
     }
+
+    #[test]
+    fn regression_15623() {
+        check_diagnostics(
+            r#"
+//- minicore: fn
+
+struct Foo;
+
+impl Foo {
+    fn needs_mut(&mut self) {}
+}
+
+fn foo(mut foo: Foo) {
+    let mut call_me = || {
+        let 0 = 1 else { return };
+        foo.needs_mut();
+    };
+    call_me();
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index a34a5824f29..290c16c9d24 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,3 +1,4 @@
+use either::Either;
 use hir::{db::ExpandDatabase, HasSource, HirDisplay, Semantics};
 use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase};
 use syntax::{
@@ -12,22 +13,39 @@ use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 //
 // This diagnostic is triggered if created structure does not have field provided in record.
 pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic {
-    Diagnostic::new_with_syntax_node_ptr(
-        ctx,
-        DiagnosticCode::RustcHardError("E0559"),
-        "no such field",
-        d.field.clone().map(|it| it.into()),
-    )
-    .with_fixes(fixes(ctx, d))
+    let node = d.field.clone().map(|it| it.either(Into::into, Into::into));
+    if d.private {
+        // FIXME: quickfix to add required visibility
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            DiagnosticCode::RustcHardError("E0451"),
+            "field is private",
+            node,
+        )
+    } else {
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            DiagnosticCode::RustcHardError("E0559"),
+            "no such field",
+            node,
+        )
+        .with_fixes(fixes(ctx, d))
+    }
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assist>> {
-    let root = ctx.sema.db.parse_or_expand(d.field.file_id);
-    missing_record_expr_field_fixes(
-        &ctx.sema,
-        d.field.file_id.original_file(ctx.sema.db),
-        &d.field.value.to_node(&root),
-    )
+    // FIXME: quickfix for pattern
+    match &d.field.value {
+        Either::Left(ptr) => {
+            let root = ctx.sema.db.parse_or_expand(d.field.file_id);
+            missing_record_expr_field_fixes(
+                &ctx.sema,
+                d.field.file_id.original_file(ctx.sema.db),
+                &ptr.to_node(&root),
+            )
+        }
+        _ => None,
+    }
 }
 
 fn missing_record_expr_field_fixes(
@@ -118,13 +136,34 @@ mod tests {
             r#"
 struct S { foo: i32, bar: () }
 impl S {
-    fn new() -> S {
+    fn new(
+        s@S {
+        //^ 💡 error: missing structure fields:
+        //|    - bar
+            foo,
+            baz: baz2,
+          //^^^^^^^^^ error: no such field
+            qux
+          //^^^ error: no such field
+        }: S
+    ) -> S {
+        S {
+      //^ 💡 error: missing structure fields:
+      //|    - bar
+            foo,
+            baz: baz2,
+          //^^^^^^^^^ error: no such field
+            qux
+          //^^^ error: no such field
+        } = s;
         S {
       //^ 💡 error: missing structure fields:
       //|    - bar
             foo: 92,
             baz: 62,
           //^^^^^^^ 💡 error: no such field
+            qux
+          //^^^ error: no such field
         }
     }
 }
@@ -295,4 +334,38 @@ fn main() {
 "#,
         )
     }
+
+    #[test]
+    fn test_struct_field_private() {
+        check_diagnostics(
+            r#"
+mod m {
+    pub struct Struct {
+        field: u32,
+        field2: u32,
+    }
+}
+fn f(s@m::Struct {
+    field: f,
+  //^^^^^^^^ error: field is private
+    field2
+  //^^^^^^ error: field is private
+}: m::Struct) {
+    // assignee expression
+    m::Struct {
+        field: 0,
+      //^^^^^^^^ error: field is private
+        field2
+      //^^^^^^ error: field is private
+    } = s;
+    m::Struct {
+        field: 0,
+      //^^^^^^^^ error: field is private
+        field2
+      //^^^^^^ error: field is private
+    };
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index 7de9a9a323e..495ea748776 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -35,6 +35,25 @@ fn foo() {
     }
 
     #[test]
+    fn while_let_loop_with_label_in_condition() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    let mut optional = Some(0);
+
+    'my_label: while let Some(a) = match optional {
+        None => break 'my_label,
+        Some(val) => Some(val),
+    } {
+        optional = None;
+        continue 'my_label;
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn for_loop() {
         check_diagnostics(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 0aa439f797a..c4ac59ec2a4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -1,3 +1,4 @@
+use hir::InFile;
 use ide_db::{base_db::FileId, source_change::SourceChange};
 use itertools::Itertools;
 use syntax::{ast, AstNode, SyntaxNode};
@@ -39,6 +40,7 @@ pub(crate) fn useless_braces(
                 "Unnecessary braces in use statement".to_string(),
                 use_range,
             )
+            .with_main_node(InFile::new(file_id.into(), node.clone()))
             .with_fixes(Some(vec![fix(
                 "remove_braces",
                 "Remove unnecessary braces",
@@ -156,4 +158,23 @@ use a::{c, d::e};
 "#,
         );
     }
+
+    #[test]
+    fn respect_lint_attributes_for_unused_braces() {
+        check_diagnostics(
+            r#"
+mod b {}
+#[allow(unused_braces)]
+use {b};
+"#,
+        );
+        check_diagnostics(
+            r#"
+mod b {}
+#[deny(unused_braces)]
+use {b};
+  //^^^ 💡 error: Unnecessary braces in use statement
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index b1b9b4b8ea5..ebe197a6790 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -369,6 +369,7 @@ pub fn diagnostics(
             AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
             AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
+            AnyDiagnostic::MismatchedTupleStructPatArgCount(d) => handlers::mismatched_arg_count::mismatched_tuple_struct_pat_arg_count(&ctx, &d),
         };
         res.push(d)
     }
@@ -432,7 +433,8 @@ fn handle_lint_attributes(
     diagnostics_of_range: &mut FxHashMap<InFile<SyntaxNode>, &mut Diagnostic>,
 ) {
     let file_id = sema.hir_file_for(root);
-    for ev in root.preorder() {
+    let mut preorder = root.preorder();
+    while let Some(ev) = preorder.next() {
         match ev {
             syntax::WalkEvent::Enter(node) => {
                 for attr in node.children().filter_map(ast::Attr::cast) {
@@ -515,7 +517,7 @@ fn parse_lint_attribute(
     let Some((tag, args_tt)) = attr.as_simple_call() else {
         return;
     };
-    let serevity = match tag.as_str() {
+    let severity = match tag.as_str() {
         "allow" => Severity::Allow,
         "warn" => Severity::Warning,
         "forbid" | "deny" => Severity::Error,
@@ -523,12 +525,12 @@ fn parse_lint_attribute(
     };
     for lint in parse_tt_as_comma_sep_paths(args_tt).into_iter().flatten() {
         if let Some(lint) = lint.as_single_name_ref() {
-            job(rustc_stack.entry(lint.to_string()).or_default(), serevity);
+            job(rustc_stack.entry(lint.to_string()).or_default(), severity);
         }
         if let Some(tool) = lint.qualifier().and_then(|x| x.as_single_name_ref()) {
             if let Some(name_ref) = &lint.segment().and_then(|x| x.name_ref()) {
                 if tool.to_string() == "clippy" {
-                    job(clippy_stack.entry(name_ref.to_string()).or_default(), serevity);
+                    job(clippy_stack.entry(name_ref.to_string()).or_default(), severity);
                 }
             }
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index f994c284c71..fb79b5dc211 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -94,10 +94,9 @@ pub(crate) fn annotations(
                         enum_
                             .variants(db)
                             .into_iter()
-                            .map(|variant| {
+                            .filter_map(|variant| {
                                 variant.source(db).and_then(|node| name_range(db, node, file_id))
                             })
-                            .flatten()
                             .for_each(|range| {
                                 let (annotation_range, target_position) = mk_ranges(range);
                                 annotations.push(Annotation {
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 901f7a2a79a..37a17762216 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -16,6 +16,7 @@ use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasA
 use ide_db::{
     base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase},
     defs::{Definition, NameClass, NameRefClass},
+    documentation::{docs_with_rangemap, Documentation, HasDocs},
     helpers::pick_best_token,
     RootDatabase,
 };
@@ -171,7 +172,7 @@ pub(crate) fn external_docs(
 /// Extracts all links from a given markdown text returning the definition text range, link-text
 /// and the namespace if known.
 pub(crate) fn extract_definitions_from_docs(
-    docs: &hir::Documentation,
+    docs: &Documentation,
 ) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
     Parser::new_with_broken_link_callback(
         docs.as_str(),
@@ -297,7 +298,7 @@ impl DocCommentToken {
             let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len;
 
             let (attributes, def) = doc_attributes(sema, &node)?;
-            let (docs, doc_mapping) = attributes.docs_with_rangemap(sema.db)?;
+            let (docs, doc_mapping) = docs_with_rangemap(sema.db, &attributes)?;
             let (in_expansion_range, link, ns) =
                 extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
                     let mapped = doc_mapping.map(range)?;
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 8036c77072b..9ae70ae66f5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -1,10 +1,11 @@
 use std::ffi::OsStr;
 
 use expect_test::{expect, Expect};
-use hir::{HasAttrs, Semantics};
+use hir::Semantics;
 use ide_db::{
     base_db::{FilePosition, FileRange},
     defs::Definition,
+    documentation::{Documentation, HasDocs},
     RootDatabase,
 };
 use itertools::Itertools;
@@ -78,7 +79,7 @@ fn check_doc_links(ra_fixture: &str) {
 fn def_under_cursor(
     sema: &Semantics<'_, RootDatabase>,
     position: &FilePosition,
-) -> (Definition, hir::Documentation) {
+) -> (Definition, Documentation) {
     let (docs, def) = sema
         .parse(position.file_id)
         .syntax()
@@ -96,7 +97,7 @@ fn def_under_cursor(
 fn node_to_def(
     sema: &Semantics<'_, RootDatabase>,
     node: &SyntaxNode,
-) -> Option<Option<(Option<hir::Documentation>, Definition)>> {
+) -> Option<Option<(Option<Documentation>, Definition)>> {
     Some(match_ast! {
         match node {
             ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(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 a33a6ee1816..f72ce37d1d9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -3,12 +3,13 @@ use std::fmt::Display;
 
 use either::Either;
 use hir::{
-    Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasSource, HirDisplay, Layout,
-    LayoutError, Semantics, TypeInfo,
+    Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasSource, HirDisplay, Layout, LayoutError,
+    Semantics, TypeInfo,
 };
 use ide_db::{
     base_db::SourceDatabase,
     defs::Definition,
+    documentation::{Documentation, HasDocs},
     famous_defs::FamousDefs,
     generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
     syntax_helpers::insert_whitespace_into_node,
@@ -470,7 +471,7 @@ pub(super) fn definition(
         Definition::SelfType(impl_def) => {
             impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
         }
-        Definition::GenericParam(it) => label_and_docs(db, it),
+        Definition::GenericParam(it) => (it.display(db).to_string(), None),
         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
@@ -616,9 +617,9 @@ fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option<Mark
     markup(Some(docs.replace('*', "\\*")), desc, None)
 }
 
-fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
+fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<Documentation>)
 where
-    D: HasAttrs + HirDisplay,
+    D: HasDocs + HirDisplay,
 {
     let label = def.display(db).to_string();
     let docs = def.docs(db);
@@ -631,9 +632,9 @@ fn label_and_layout_info_and_docs<D, E, E2>(
     config: &HoverConfig,
     layout_extractor: E,
     layout_offset_extractor: E2,
-) -> (String, Option<hir::Documentation>)
+) -> (String, Option<Documentation>)
 where
-    D: HasAttrs + HirDisplay,
+    D: HasDocs + HirDisplay,
     E: Fn(&D) -> Result<Layout, LayoutError>,
     E2: Fn(&Layout) -> Option<u64>,
 {
@@ -657,9 +658,9 @@ fn label_value_and_layout_info_and_docs<D, E, E2, E3, V>(
     value_extractor: E,
     layout_extractor: E2,
     layout_tag_extractor: E3,
-) -> (String, Option<hir::Documentation>)
+) -> (String, Option<Documentation>)
 where
-    D: HasAttrs + HirDisplay,
+    D: HasDocs + HirDisplay,
     E: Fn(&D) -> Option<V>,
     E2: Fn(&D) -> Result<Layout, LayoutError>,
     E3: Fn(&Layout) -> Option<usize>,
@@ -686,9 +687,9 @@ fn label_value_and_docs<D, E, V>(
     db: &RootDatabase,
     def: D,
     value_extractor: E,
-) -> (String, Option<hir::Documentation>)
+) -> (String, Option<Documentation>)
 where
-    D: HasAttrs + HirDisplay,
+    D: HasDocs + HirDisplay,
     E: Fn(&D) -> Option<V>,
     V: Display,
 {
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 d0f9f7b0e16..81d6db564ff 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -6574,3 +6574,23 @@ fn test() {
         "#]],
     );
 }
+
+#[test]
+fn format_args_arg() {
+    check(
+        r#"
+//- minicore: fmt
+fn test() {
+    let foo = 0;
+    format_args!("{}", foo$0);
+}
+"#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            let foo: i32 // size = 4, align = 4
+            ```
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 29259167419..a5d070fe767 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -52,6 +52,28 @@ pub struct InlayHintsConfig {
     pub closure_style: ClosureStyle,
     pub max_length: Option<usize>,
     pub closing_brace_hints_min_lines: Option<usize>,
+    pub fields_to_resolve: InlayFieldsToResolve,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct InlayFieldsToResolve {
+    pub resolve_text_edits: bool,
+    pub resolve_hint_tooltip: bool,
+    pub resolve_label_tooltip: bool,
+    pub resolve_label_location: bool,
+    pub resolve_label_command: bool,
+}
+
+impl InlayFieldsToResolve {
+    pub const fn empty() -> Self {
+        Self {
+            resolve_text_edits: false,
+            resolve_hint_tooltip: false,
+            resolve_label_tooltip: false,
+            resolve_label_location: false,
+            resolve_label_command: false,
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -123,11 +145,13 @@ pub struct InlayHint {
     pub label: InlayHintLabel,
     /// Text edit to apply when "accepting" this inlay hint.
     pub text_edit: Option<TextEdit>,
+    pub needs_resolve: bool,
 }
 
 impl InlayHint {
     fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint {
         InlayHint {
+            needs_resolve: false,
             range,
             kind,
             label: InlayHintLabel::from(")"),
@@ -139,6 +163,7 @@ impl InlayHint {
     }
     fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
         InlayHint {
+            needs_resolve: false,
             range,
             kind,
             label: InlayHintLabel::from("("),
@@ -196,6 +221,10 @@ impl InlayHintLabel {
             }),
         }
     }
+
+    pub fn needs_resolve(&self) -> bool {
+        self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some())
+    }
 }
 
 impl From<String> for InlayHintLabel {
@@ -529,6 +558,7 @@ fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
 
 #[cfg(test)]
 mod tests {
+
     use expect_test::Expect;
     use hir::ClosureStyle;
     use itertools::Itertools;
@@ -538,7 +568,7 @@ mod tests {
     use crate::DiscriminantHints;
     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 
-    use super::ClosureReturnTypeHints;
+    use super::{ClosureReturnTypeHints, InlayFieldsToResolve};
 
     pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
         discriminant_hints: DiscriminantHints::Never,
@@ -559,6 +589,7 @@ mod tests {
         param_names_for_lifetime_elision_hints: false,
         max_length: None,
         closing_brace_hints_min_lines: None,
+        fields_to_resolve: InlayFieldsToResolve::empty(),
     };
     pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
         type_hints: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 6d6bd315ebb..631807d99a7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -137,21 +137,23 @@ pub(super) fn hints(
             }
             _ => continue,
         };
+        let label = InlayHintLabel::simple(
+            if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
+            Some(InlayTooltip::Markdown(format!(
+                "`{}` → `{}` ({coercion} coercion)",
+                source.display(sema.db),
+                target.display(sema.db),
+            ))),
+            None,
+        );
         acc.push(InlayHint {
+            needs_resolve: label.needs_resolve(),
             range: expr.syntax().text_range(),
             pad_left: false,
             pad_right: false,
             position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
             kind: InlayKind::Adjustment,
-            label: InlayHintLabel::simple(
-                if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
-                Some(InlayTooltip::Markdown(format!(
-                    "`{}` → `{}` ({coercion} coercion)",
-                    source.display(sema.db),
-                    target.display(sema.db),
-                ))),
-                None,
-            ),
+            label,
             text_edit: None,
         });
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 07b9f9cc1ff..680035c721b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -99,6 +99,7 @@ pub(super) fn hints(
         None => pat.syntax().text_range(),
     };
     acc.push(InlayHint {
+        needs_resolve: label.needs_resolve() || text_edit.is_some(),
         range: match type_ascriptable {
             Some(Some(t)) => text_range.cover(t.text_range()),
             _ => text_range,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index 343cf17e50e..35504ffa785 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -50,9 +50,10 @@ pub(super) fn hints(
             _ => return,
         };
         acc.push(InlayHint {
+            needs_resolve: false,
             range,
             kind: InlayKind::BindingMode,
-            label: r.to_string().into(),
+            label: r.into(),
             text_edit: None,
             position: InlayHintPosition::Before,
             pad_left: false,
@@ -68,9 +69,10 @@ pub(super) fn hints(
                 hir::BindingMode::Ref(Mutability::Shared) => "ref",
             };
             acc.push(InlayHint {
+                needs_resolve: false,
                 range: pat.syntax().text_range(),
                 kind: InlayKind::BindingMode,
-                label: bm.to_string().into(),
+                label: bm.into(),
                 text_edit: None,
                 position: InlayHintPosition::Before,
                 pad_left: false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index b621a8dda7e..12e46c0f883 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -57,10 +57,12 @@ pub(super) fn hints(
                     }
                 }
             }
+            let label = label_of_ty(famous_defs, config, &ty)?;
             acc.push(InlayHint {
+                needs_resolve: label.needs_resolve(),
                 range: expr.syntax().text_range(),
                 kind: InlayKind::Chaining,
-                label: label_of_ty(famous_defs, config, &ty)?,
+                label,
                 text_edit: None,
                 position: InlayHintPosition::After,
                 pad_left: true,
@@ -128,6 +130,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 147..154,
@@ -152,6 +155,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                 ]
             "#]],
@@ -221,6 +225,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 143..179,
@@ -245,6 +250,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                 ]
             "#]],
@@ -298,6 +304,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 143..179,
@@ -322,6 +329,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                 ]
             "#]],
@@ -389,6 +397,7 @@ fn main() {
                             "<i32, bool>>",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 246..265,
@@ -426,6 +435,7 @@ fn main() {
                             "<i32, bool>>",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                 ]
             "#]],
@@ -474,7 +484,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9289..9297,
+                                        range: 10739..10747,
                                     },
                                 ),
                                 tooltip: "",
@@ -487,7 +497,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9321..9325,
+                                        range: 10771..10775,
                                     },
                                 ),
                                 tooltip: "",
@@ -495,6 +505,7 @@ fn main() {
                             " = ()>",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 174..224,
@@ -511,7 +522,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9289..9297,
+                                        range: 10739..10747,
                                     },
                                 ),
                                 tooltip: "",
@@ -524,7 +535,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9321..9325,
+                                        range: 10771..10775,
                                     },
                                 ),
                                 tooltip: "",
@@ -532,6 +543,7 @@ fn main() {
                             " = ()>",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 174..206,
@@ -548,7 +560,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9289..9297,
+                                        range: 10739..10747,
                                     },
                                 ),
                                 tooltip: "",
@@ -561,7 +573,7 @@ fn main() {
                                         file_id: FileId(
                                             1,
                                         ),
-                                        range: 9321..9325,
+                                        range: 10771..10775,
                                     },
                                 ),
                                 tooltip: "",
@@ -569,6 +581,7 @@ fn main() {
                             " = ()>",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 174..189,
@@ -593,6 +606,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                 ]
             "#]],
@@ -655,6 +669,7 @@ fn main() {
                                 ],
                             },
                         ),
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 145..185,
@@ -679,6 +694,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 145..168,
@@ -703,6 +719,7 @@ fn main() {
                             "",
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                     InlayHint {
                         range: 222..228,
@@ -725,6 +742,7 @@ fn main() {
                             },
                         ],
                         text_edit: None,
+                        needs_resolve: true,
                     },
                 ]
             "#]],
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 2cefd5acdc2..2b68538c198 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -109,6 +109,7 @@ pub(super) fn hints(
 
     let linked_location = name_range.map(|range| FileRange { file_id, range });
     acc.push(InlayHint {
+        needs_resolve: linked_location.is_some(),
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBrace,
         label: InlayHintLabel::simple(label, None, linked_location),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 9d5defcbb71..d691303c18b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -31,9 +31,10 @@ pub(super) fn hints(
             let range = closure.syntax().first_token()?.prev_token()?.text_range();
             let range = TextRange::new(range.end() - TextSize::from(1), range.end());
             acc.push(InlayHint {
+                needs_resolve: false,
                 range,
                 kind: InlayKind::ClosureCapture,
-                label: InlayHintLabel::simple("move", None, None),
+                label: InlayHintLabel::from("move"),
                 text_edit: None,
                 position: InlayHintPosition::After,
                 pad_left: false,
@@ -43,6 +44,7 @@ pub(super) fn hints(
         }
     };
     acc.push(InlayHint {
+        needs_resolve: false,
         range: move_kw_range,
         kind: InlayKind::ClosureCapture,
         label: InlayHintLabel::from("("),
@@ -59,23 +61,25 @@ pub(super) fn hints(
         // force cache the source file, otherwise sema lookup will potentially panic
         _ = sema.parse_or_expand(source.file());
 
+        let label = InlayHintLabel::simple(
+            format!(
+                "{}{}",
+                match capture.kind() {
+                    hir::CaptureKind::SharedRef => "&",
+                    hir::CaptureKind::UniqueSharedRef => "&unique ",
+                    hir::CaptureKind::MutableRef => "&mut ",
+                    hir::CaptureKind::Move => "",
+                },
+                capture.display_place(sema.db)
+            ),
+            None,
+            source.name().and_then(|name| name.syntax().original_file_range_opt(sema.db)),
+        );
         acc.push(InlayHint {
+            needs_resolve: label.needs_resolve(),
             range: move_kw_range,
             kind: InlayKind::ClosureCapture,
-            label: InlayHintLabel::simple(
-                format!(
-                    "{}{}",
-                    match capture.kind() {
-                        hir::CaptureKind::SharedRef => "&",
-                        hir::CaptureKind::UniqueSharedRef => "&unique ",
-                        hir::CaptureKind::MutableRef => "&mut ",
-                        hir::CaptureKind::Move => "",
-                    },
-                    capture.display_place(sema.db)
-                ),
-                None,
-                source.name().and_then(|name| name.syntax().original_file_range_opt(sema.db)),
-            ),
+            label,
             text_edit: None,
             position: InlayHintPosition::After,
             pad_left: false,
@@ -84,9 +88,10 @@ pub(super) fn hints(
 
         if idx != last {
             acc.push(InlayHint {
+                needs_resolve: false,
                 range: move_kw_range,
                 kind: InlayKind::ClosureCapture,
-                label: InlayHintLabel::simple(", ", None, None),
+                label: InlayHintLabel::from(", "),
                 text_edit: None,
                 position: InlayHintPosition::After,
                 pad_left: false,
@@ -95,6 +100,7 @@ pub(super) fn hints(
         }
     }
     acc.push(InlayHint {
+        needs_resolve: false,
         range: move_kw_range,
         kind: InlayKind::ClosureCapture,
         label: InlayHintLabel::from(")"),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
index 3b41db0f13d..204967cd7ca 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
@@ -64,6 +64,7 @@ pub(super) fn hints(
     };
 
     acc.push(InlayHint {
+        needs_resolve: label.needs_resolve() || text_edit.is_some(),
         range: param_list.syntax().text_range(),
         kind: InlayKind::Type,
         label,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index c4d2ac75cfa..26dc6fa8b9c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -79,6 +79,7 @@ fn variant_hints(
         None,
     );
     acc.push(InlayHint {
+        needs_resolve: label.needs_resolve(),
         range: match eq_token {
             Some(t) => range.cover(t.text_range()),
             _ => range,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
index 5fce11b785a..7b05e32ad86 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
@@ -22,6 +22,7 @@ pub(super) fn hints(
     }
 
     let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
+        needs_resolve: false,
         range: t.text_range(),
         kind: InlayKind::Lifetime,
         label: label.into(),
@@ -185,6 +186,7 @@ pub(super) fn hints(
             let angle_tok = gpl.l_angle_token()?;
             let is_empty = gpl.generic_params().next().is_none();
             acc.push(InlayHint {
+                needs_resolve: false,
                 range: angle_tok.text_range(),
                 kind: InlayKind::Lifetime,
                 label: format!(
@@ -200,6 +202,7 @@ pub(super) fn hints(
             });
         }
         (None, allocated_lifetimes) => acc.push(InlayHint {
+            needs_resolve: false,
             range: func.name()?.syntax().text_range(),
             kind: InlayKind::GenericParamList,
             label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index fc297a8d824..f18e6421cbc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -31,9 +31,10 @@ pub(super) fn hints(
         if ty.lifetime().is_none() {
             let t = ty.amp_token()?;
             acc.push(InlayHint {
+                needs_resolve: false,
                 range: t.text_range(),
                 kind: InlayKind::Lifetime,
-                label: "'static".to_owned().into(),
+                label: "'static".into(),
                 text_edit: None,
                 position: InlayHintPosition::After,
                 pad_left: false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index c4f43f41175..b4260d82506 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -57,6 +57,7 @@ pub(super) fn hints(
             let label =
                 InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location);
             InlayHint {
+                needs_resolve: label.needs_resolve(),
                 range,
                 kind: InlayKind::Parameter,
                 label,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index c9cdbff7d7d..aee03d218ad 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -91,9 +91,9 @@ pub use crate::{
         MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
     },
     inlay_hints::{
-        AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
-        InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
-        InlayTooltip, LifetimeElisionHints,
+        AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
+        InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
+        InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -111,7 +111,7 @@ pub use crate::{
         HighlightConfig, HlRange,
     },
 };
-pub use hir::{Documentation, Semantics};
+pub use hir::Semantics;
 pub use ide_assists::{
     Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
 };
@@ -124,6 +124,7 @@ pub use ide_db::{
         Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
         SourceRoot, SourceRootId,
     },
+    documentation::Documentation,
     label::Label,
     line_index::{LineCol, LineIndex},
     search::{ReferenceCategory, SearchScope},
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 0740bfbc7b1..32f211c6b28 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -4,14 +4,15 @@ use std::fmt;
 
 use either::Either;
 use hir::{
-    symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasContainer, HasSource,
-    HirDisplay, HirFileId, InFile, LocalSource, ModuleSource,
+    symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource, HirDisplay, HirFileId,
+    InFile, LocalSource, ModuleSource,
 };
 use ide_db::{
     base_db::{FileId, FileRange},
-    SymbolKind,
+    defs::Definition,
+    documentation::{Documentation, HasDocs},
+    RootDatabase, SymbolKind,
 };
-use ide_db::{defs::Definition, RootDatabase};
 use stdx::never;
 use syntax::{
     ast::{self, HasName},
@@ -327,7 +328,7 @@ impl ToNavFromAst for hir::TraitAlias {
 
 impl<D> TryToNav for D
 where
-    D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay,
+    D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay,
     D::Ast: ast::HasName,
 {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index dae8e71e8a0..ac9df5ed6d1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -2634,4 +2634,33 @@ use qux as frob;
         // ",
         //         );
     }
+
+    #[test]
+    fn disallow_renaming_for_non_local_definition() {
+        check(
+            "Baz",
+            r#"
+//- /lib.rs crate:lib new_source_root:library
+pub struct S;
+//- /main.rs crate:main deps:lib new_source_root:local
+use lib::S$0;
+"#,
+            "error: Cannot rename a non-local definition.",
+        );
+    }
+
+    #[test]
+    fn disallow_renaming_for_builtin_macros() {
+        check(
+            "Baz",
+            r#"
+//- minicore: derive, hash
+//- /main.rs crate:main
+use core::hash::Hash;
+#[derive(H$0ash)]
+struct A;
+            "#,
+            "error: Cannot rename a non-local definition.",
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 5f87a78551d..2d528c64255 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -7,6 +7,7 @@ use ide_assists::utils::test_related_attribute;
 use ide_db::{
     base_db::{FilePosition, FileRange},
     defs::Definition,
+    documentation::docs_from_attrs,
     helpers::visit_file_defs,
     search::SearchScope,
     FxHashMap, FxHashSet, RootDatabase, SymbolKind,
@@ -496,7 +497,7 @@ const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
     &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
 
 fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
-    attrs.docs().map_or(false, |doc| {
+    docs_from_attrs(attrs).map_or(false, |doc| {
         let mut in_code_block = false;
 
         for line in String::from(doc).lines() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 847ab3d21ad..e020b52e171 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -4,12 +4,11 @@
 use std::collections::BTreeSet;
 
 use either::Either;
-use hir::{
-    AssocItem, GenericParam, HasAttrs, HirDisplay, ModuleDef, PathResolution, Semantics, Trait,
-};
+use hir::{AssocItem, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait};
 use ide_db::{
     active_parameter::{callable_for_node, generic_def_for_node},
     base_db::FilePosition,
+    documentation::{Documentation, HasDocs},
     FxIndexMap,
 };
 use stdx::format_to;
@@ -28,7 +27,7 @@ use crate::RootDatabase;
 /// edited.
 #[derive(Debug)]
 pub struct SignatureHelp {
-    pub doc: Option<String>,
+    pub doc: Option<Documentation>,
     pub signature: String,
     pub active_parameter: Option<usize>,
     parameters: Vec<TextRange>,
@@ -179,7 +178,7 @@ fn signature_help_for_call(
     let mut fn_params = None;
     match callable.kind() {
         hir::CallableKind::Function(func) => {
-            res.doc = func.docs(db).map(|it| it.into());
+            res.doc = func.docs(db);
             format_to!(res.signature, "fn {}", func.name(db).display(db));
             fn_params = Some(match callable.receiver_param(db) {
                 Some(_self) => func.params_without_self(db),
@@ -187,11 +186,11 @@ fn signature_help_for_call(
             });
         }
         hir::CallableKind::TupleStruct(strukt) => {
-            res.doc = strukt.docs(db).map(|it| it.into());
+            res.doc = strukt.docs(db);
             format_to!(res.signature, "struct {}", strukt.name(db).display(db));
         }
         hir::CallableKind::TupleEnumVariant(variant) => {
-            res.doc = variant.docs(db).map(|it| it.into());
+            res.doc = variant.docs(db);
             format_to!(
                 res.signature,
                 "enum {}::{}",
@@ -265,38 +264,38 @@ fn signature_help_for_generics(
     let db = sema.db;
     match generics_def {
         hir::GenericDef::Function(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "fn {}", it.name(db).display(db));
         }
         hir::GenericDef::Adt(hir::Adt::Enum(it)) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "enum {}", it.name(db).display(db));
         }
         hir::GenericDef::Adt(hir::Adt::Struct(it)) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "struct {}", it.name(db).display(db));
         }
         hir::GenericDef::Adt(hir::Adt::Union(it)) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "union {}", it.name(db).display(db));
         }
         hir::GenericDef::Trait(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "trait {}", it.name(db).display(db));
         }
         hir::GenericDef::TraitAlias(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "trait {}", it.name(db).display(db));
         }
         hir::GenericDef::TypeAlias(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             format_to!(res.signature, "type {}", it.name(db).display(db));
         }
         hir::GenericDef::Variant(it) => {
             // In paths, generics of an enum can be specified *after* one of its variants.
             // eg. `None::<u8>`
             // We'll use the signature of the enum, but include the docs of the variant.
-            res.doc = it.docs(db).map(|it| it.into());
+            res.doc = it.docs(db);
             let enum_ = it.parent_enum(db);
             format_to!(res.signature, "enum {}", enum_.name(db).display(db));
             generics_def = enum_.into();
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 d8696198d3b..aabd26da289 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -12,6 +12,7 @@ use ide_db::{
 };
 use syntax::{AstNode, SyntaxKind::*, TextRange, T};
 
+use crate::inlay_hints::InlayFieldsToResolve;
 use crate::{
     hover::hover_for_definition,
     inlay_hints::AdjustmentHintsMode,
@@ -125,6 +126,7 @@ impl StaticIndex<'_> {
                     max_length: Some(25),
                     closure_capture_hints: false,
                     closing_brace_hints_min_lines: Some(25),
+                    fields_to_resolve: InlayFieldsToResolve::empty(),
                 },
                 file_id,
                 None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index d2c77e2dc79..c9ee460a1c2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -66,6 +66,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
                 None => format!("{}", krate.into_raw()),
             };
             format_to!(buf, "Crate: {}\n", display_crate(krate));
+            format_to!(buf, "Enabled cfgs: {:?}\n", crate_graph[krate].cfg_options);
             let deps = crate_graph[krate]
                 .dependencies
                 .iter()
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
index 2ed57e20130..2ef1315945a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
@@ -17,6 +17,7 @@ pub(super) fn highlight_format_string(
         return;
     }
 
+    // FIXME: Replace this with the HIR info we have now.
     lex_format_specifiers(string, &mut |piece_range, kind| {
         if let Some(highlight) = highlight_format_specifier(kind) {
             stack.add(HlRange {
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 8e96bfa01ad..7d00282fc14 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
@@ -617,6 +617,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
         CONST => SymbolKind::Const,
         STATIC => SymbolKind::Static,
         IDENT_PAT => SymbolKind::Local,
+        FORMAT_ARGS_ARG => SymbolKind::Local,
         _ => return default.into(),
     };
 
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 2657a641482..71f4d07245d 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
@@ -5,8 +5,8 @@ use std::mem;
 use either::Either;
 use hir::{InFile, Semantics};
 use ide_db::{
-    active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence,
-    SymbolKind,
+    active_parameter::ActiveParameter, base_db::FileId, defs::Definition,
+    documentation::docs_with_rangemap, rust_doc::is_rust_fence, SymbolKind,
 };
 use syntax::{
     ast::{self, AstNode, IsString, QuoteOffsets},
@@ -118,7 +118,7 @@ pub(super) fn doc_comment(
     let src_file_id = src_file_id.into();
 
     // Extract intra-doc links and emit highlights for them.
-    if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
+    if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) {
         extract_definitions_from_docs(&docs)
             .into_iter()
             .filter_map(|(range, link, ns)| {
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 3ac8aa9cc9d..64e614cecd2 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
@@ -45,17 +45,11 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 </style>
 <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="brace">{</span>
-        <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
     <span class="brace">}</span><span class="parenthesis">)</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="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</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="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="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">const_format_args</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="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
 <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span>
@@ -75,7 +69,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
             <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_display<span class="parenthesis">(</span><span class="punctuation">&</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span>
         <span class="parenthesis">)</span><span class="comma">,</span>
         <span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span>
-            <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_fmt<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>const_format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+            <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_fmt<span class="parenthesis">(</span>const_format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
         <span class="parenthesis">)</span><span class="comma">,</span>
     <span class="brace">}</span>
 <span class="brace">}</span>
@@ -92,7 +86,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
@@ -114,18 +108,18 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro">println</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="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "Hello, world!"</span>
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </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">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "The number is 1"</span>
     <span class="macro">println</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="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "(3, 4)"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>      <span class="comment">// =&gt; "4"</span>
+    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>      <span class="comment">// =&gt; "4"</span>
     <span class="macro">println</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="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>           <span class="comment">// =&gt; "1 2"</span>
     <span class="macro">println</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="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>             <span class="comment">// =&gt; "0042" with leading zerosV</span>
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</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="numeric_literal">0</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="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "2 1 1 2"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "test"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</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="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="none macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "2 1"</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="none macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="none macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>  <span class="comment">// =&gt; "a 3 b"</span>
+    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>   <span class="comment">// =&gt; "test"</span>
+    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</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="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>          <span class="comment">// =&gt; "2 1"</span>
+    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>  <span class="comment">// =&gt; "a 3 b"</span>
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>                       <span class="comment">// =&gt; "{2}"</span>
     <span class="macro">println</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="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</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">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</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="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="none macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</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="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
@@ -140,10 +134,10 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro">println</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="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>    <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</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"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>   <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</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"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="none macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="none macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</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="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</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="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</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="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</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"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</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="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</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="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</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="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{}"</span>
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{{}}"</span><span class="semicolon">;</span>
@@ -167,16 +161,24 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
     <span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
 
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
     <span class="macro">println</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="variable">x</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="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">panic</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="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </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">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma 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">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <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="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="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</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="semicolon">;</span>
+    <span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more {}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{} asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</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="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</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 {0}, {1}"</span><span class="comma macro">,</span>
+        <span class="string_literal macro">"add {0}, 5"</span><span class="comma macro">,</span>
+        <span class="none macro">out</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">o</span><span class="comma macro">,</span>
+        <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">i</span><span class="comma macro">,</span>
+    <span class="parenthesis macro">)</span><span class="semicolon">;</span>
+
+    <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</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 default_library library">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="macro default_library library macro">format_args</span><span class="macro_bang 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="macro macro">toho</span><span class="macro_bang 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 8749d355c85..542d8992531 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
@@ -401,19 +401,14 @@ fn test_string_highlighting() {
     // thus, we have to copy the macro definition from `std`
     check_highlighting(
         r#"
+//- minicore: fmt
 macro_rules! println {
     ($($arg:tt)*) => ({
-        $crate::io::_print($crate::format_args_nl!($($arg)*));
+        $crate::io::_print(format_args_nl!($($arg)*));
     })
 }
 #[rustc_builtin_macro]
 #[macro_export]
-macro_rules! format_args {}
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! const_format_args {}
-#[rustc_builtin_macro]
-#[macro_export]
 macro_rules! format_args_nl {}
 
 mod panic {
@@ -433,7 +428,7 @@ mod panic {
             $crate::panicking::panic_display(&$arg)
         ),
         ($fmt:expr, $($arg:tt)+) => (
-            $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
+            $crate::panicking::panic_fmt(const_format_args!($fmt, $($arg)+))
         ),
     }
 }
@@ -450,7 +445,7 @@ macro_rules! concat {}
 
 macro_rules! toho {
     () => ($crate::panic!("not yet implemented"));
-    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
+    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
 }
 
 fn main() {
@@ -534,7 +529,15 @@ fn main() {
     assert!(true, "{}", 1);
     assert!(true, "{} asdasd", 1);
     toho!("{}fmt", 0);
-    asm!("mov eax, {0}");
+    let i: u64 = 3;
+    let o: u64;
+    asm!(
+        "mov {0}, {1}",
+        "add {0}, 5",
+        out(reg) o,
+        in(reg) i,
+    );
+
     format_args!(concat!("{}"), "{}");
     format_args!("{} {} {} {} {} {}", backslash, format_args!("{}", 0), foo, "bar", toho!(), backslash);
 }"#,
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index c7e403f6b1a..b40509715ba 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -32,7 +32,7 @@ use crate::SourceChange;
 pub(crate) use on_enter::on_enter;
 
 // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
-pub(crate) const TRIGGER_CHARS: &str = ".=<>{";
+pub(crate) const TRIGGER_CHARS: &str = ".=<>{(";
 
 struct ExtendedTextEdit {
     edit: TextEdit,
@@ -86,45 +86,57 @@ fn on_char_typed_inner(
     if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
         return None;
     }
-    return match char_typed {
+    let conv = |text_edit: Option<TextEdit>| {
+        Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false })
+    };
+    match char_typed {
         '.' => conv(on_dot_typed(&file.tree(), offset)),
         '=' => conv(on_eq_typed(&file.tree(), offset)),
         '<' => on_left_angle_typed(&file.tree(), offset),
         '>' => conv(on_right_angle_typed(&file.tree(), offset)),
-        '{' => conv(on_opening_brace_typed(file, offset)),
-        _ => return None,
-    };
-
-    fn conv(text_edit: Option<TextEdit>) -> Option<ExtendedTextEdit> {
-        Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false })
+        '{' => conv(on_opening_bracket_typed(file, offset, '{')),
+        '(' => conv(on_opening_bracket_typed(file, offset, '(')),
+        _ => None,
     }
 }
 
-/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
-/// block, or a part of a `use` item.
-fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
-    if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
+/// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a
+/// block, or a part of a `use` item (for `{`).
+fn on_opening_bracket_typed(
+    file: &Parse<SourceFile>,
+    offset: TextSize,
+    opening_bracket: char,
+) -> Option<TextEdit> {
+    let (closing_bracket, expected_ast_bracket) = match opening_bracket {
+        '{' => ('}', SyntaxKind::L_CURLY),
+        '(' => (')', SyntaxKind::L_PAREN),
+        _ => return None,
+    };
+
+    if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some(opening_bracket)) {
         return None;
     }
 
     let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
-    if brace_token.kind() != SyntaxKind::L_CURLY {
+    if brace_token.kind() != expected_ast_bracket {
         return None;
     }
 
-    // Remove the `{` to get a better parse tree, and reparse.
+    // Remove the opening bracket to get a better parse tree, and reparse.
     let range = brace_token.text_range();
-    if !stdx::always!(range.len() == TextSize::of('{')) {
+    if !stdx::always!(range.len() == TextSize::of(opening_bracket)) {
         return None;
     }
     let file = file.reparse(&Indel::delete(range));
 
-    if let Some(edit) = brace_expr(&file.tree(), offset) {
+    if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) {
         return Some(edit);
     }
 
-    if let Some(edit) = brace_use_path(&file.tree(), offset) {
-        return Some(edit);
+    if closing_bracket == '}' {
+        if let Some(edit) = brace_use_path(&file.tree(), offset) {
+            return Some(edit);
+        }
     }
 
     return None;
@@ -143,7 +155,12 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
         ))
     }
 
-    fn brace_expr(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
+    fn bracket_expr(
+        file: &SourceFile,
+        offset: TextSize,
+        opening_bracket: char,
+        closing_bracket: char,
+    ) -> Option<TextEdit> {
         let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?;
         if expr.syntax().text_range().start() != offset {
             return None;
@@ -166,10 +183,10 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
             return None;
         }
 
-        // Insert `}` right after the expression.
+        // Insert the closing bracket right after the expression.
         Some(TextEdit::insert(
-            expr.syntax().text_range().end() + TextSize::of("{"),
-            "}".to_string(),
+            expr.syntax().text_range().end() + TextSize::of(opening_bracket),
+            closing_bracket.to_string(),
         ))
     }
 }
@@ -938,6 +955,193 @@ use some::pa$0th::to::Item;
     }
 
     #[test]
+    fn adds_closing_parenthesis_for_expr() {
+        type_char(
+            '(',
+            r#"
+fn f() { match () { _ => $0() } }
+            "#,
+            r#"
+fn f() { match () { _ => (()) } }
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+fn f() { $0() }
+            "#,
+            r#"
+fn f() { (()) }
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+fn f() { let x = $0(); }
+            "#,
+            r#"
+fn f() { let x = (()); }
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+fn f() { let x = $0a.b(); }
+            "#,
+            r#"
+fn f() { let x = (a.b()); }
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+const S: () = $0();
+fn f() {}
+            "#,
+            r#"
+const S: () = (());
+fn f() {}
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+const S: () = $0a.b();
+fn f() {}
+            "#,
+            r#"
+const S: () = (a.b());
+fn f() {}
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+fn f() {
+    match x {
+        0 => $0(),
+        1 => (),
+    }
+}
+            "#,
+            r#"
+fn f() {
+    match x {
+        0 => (()),
+        1 => (),
+    }
+}
+            "#,
+        );
+        type_char(
+            '(',
+            r#"
+        fn f() {
+            let z = Some($03);
+        }
+                    "#,
+            r#"
+        fn f() {
+            let z = Some((3));
+        }
+                    "#,
+        );
+    }
+
+    #[test]
+    fn parenthesis_noop_in_string_literal() {
+        // Regression test for #9351
+        type_char_noop(
+            '(',
+            r##"
+fn check_with(ra_fixture: &str, expect: Expect) {
+    let base = r#"
+enum E { T(), R$0, C }
+use self::E::X;
+const Z: E = E::C;
+mod m {}
+asdasdasdasdasdasda
+sdasdasdasdasdasda
+sdasdasdasdasd
+"#;
+    let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
+    expect.assert_eq(&actual)
+}
+            "##,
+        );
+    }
+
+    #[test]
+    fn parenthesis_noop_in_item_position_with_macro() {
+        type_char_noop('(', r#"$0println!();"#);
+        type_char_noop(
+            '(',
+            r#"
+fn main() $0println!("hello");
+}"#,
+        );
+    }
+
+    #[test]
+    fn parenthesis_noop_in_use_tree() {
+        type_char_noop(
+            '(',
+            r#"
+use some::$0Path;
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use some::{Path, $0Other};
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use some::{$0Path, Other};
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use some::path::$0to::Item;
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use some::$0path::to::Item;
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use $0some::path::to::Item;
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use some::path::$0to::{Item};
+            "#,
+        );
+        type_char_noop(
+            '(',
+            r#"
+use $0Thing as _;
+            "#,
+        );
+
+        type_char_noop(
+            '(',
+            r#"
+use some::pa$0th::to::Item;
+            "#,
+        );
+    }
+
+    #[test]
     fn adds_closing_angle_bracket_for_generic_args() {
         type_char(
             '<',
diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml
index 4d56c771960..89b302c796b 100644
--- a/src/tools/rust-analyzer/crates/intern/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml
@@ -16,6 +16,5 @@ doctest = false
 # We need to freeze the version of the crate, as the raw-api feature is considered unstable
 dashmap = { version = "=5.4.0", features = ["raw-api"] }
 hashbrown.workspace = true
-once_cell = "1.17.0"
 rustc-hash = "1.1.0"
 triomphe.workspace = true
diff --git a/src/tools/rust-analyzer/crates/intern/src/lib.rs b/src/tools/rust-analyzer/crates/intern/src/lib.rs
index dabbf3a38b5..2934d26674d 100644
--- a/src/tools/rust-analyzer/crates/intern/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/lib.rs
@@ -6,11 +6,11 @@ use std::{
     fmt::{self, Debug, Display},
     hash::{BuildHasherDefault, Hash, Hasher},
     ops::Deref,
+    sync::OnceLock,
 };
 
 use dashmap::{DashMap, SharedValue};
 use hashbrown::{hash_map::RawEntryMut, HashMap};
-use once_cell::sync::OnceCell;
 use rustc_hash::FxHasher;
 use triomphe::Arc;
 
@@ -177,12 +177,12 @@ impl<T: Display + Internable + ?Sized> Display for Interned<T> {
 }
 
 pub struct InternStorage<T: ?Sized> {
-    map: OnceCell<InternMap<T>>,
+    map: OnceLock<InternMap<T>>,
 }
 
 impl<T: ?Sized> InternStorage<T> {
     pub const fn new() -> Self {
-        Self { map: OnceCell::new() }
+        Self { map: OnceLock::new() }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index d8553d3f953..4197f248e0a 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -1,3 +1,5 @@
+use crate::grammar::types::type_;
+
 use super::*;
 
 // test expr_literals
@@ -73,6 +75,9 @@ pub(super) fn atom_expr(
     if let Some(m) = literal(p) {
         return Some((m, BlockLike::NotBlock));
     }
+    if p.at_contextual_kw(T![builtin]) && p.nth_at(1, T![#]) {
+        return Some((builtin_expr(p)?, BlockLike::NotBlock));
+    }
     if paths::is_path_start(p) {
         return Some(path_expr(p, r));
     }
@@ -93,7 +98,6 @@ pub(super) fn atom_expr(
             m.complete(p, UNDERSCORE_EXPR)
         }
         T![loop] => loop_expr(p, None),
-        T![box] => box_expr(p, None),
         T![while] => while_expr(p, None),
         T![try] => try_block_expr(p, None),
         T![match] => match_expr(p),
@@ -212,6 +216,72 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
     m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
 }
 
+// test builtin_expr
+// fn foo() {
+//     builtin#asm(0);
+//     builtin#format_args("", 0, 1, a = 2 + 3, a + b);
+//     builtin#offset_of(Foo, bar.baz.0);
+// }
+fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
+    let m = p.start();
+    p.bump_remap(T![builtin]);
+    p.bump(T![#]);
+    if p.at_contextual_kw(T![offset_of]) {
+        p.bump_remap(T![offset_of]);
+        p.expect(T!['(']);
+        type_(p);
+        p.expect(T![,]);
+        while !p.at(EOF) && !p.at(T![')']) {
+            if p.at(IDENT) || p.at(INT_NUMBER) {
+                name_ref_or_index(p);
+            // } else if p.at(FLOAT_NUMBER) {
+            // FIXME: needs float hack
+            } else {
+                p.err_and_bump("expected field name or number");
+            }
+            if !p.at(T![')']) {
+                p.expect(T![.]);
+            }
+        }
+        p.expect(T![')']);
+        Some(m.complete(p, OFFSET_OF_EXPR))
+    } else if p.at_contextual_kw(T![format_args]) {
+        p.bump_remap(T![format_args]);
+        p.expect(T!['(']);
+        expr(p);
+        if p.eat(T![,]) {
+            while !p.at(EOF) && !p.at(T![')']) {
+                let m = p.start();
+                if p.at(IDENT) && p.nth_at(1, T![=]) {
+                    name(p);
+                    p.bump(T![=]);
+                }
+                if expr(p).is_none() {
+                    m.abandon(p);
+                    break;
+                }
+                m.complete(p, FORMAT_ARGS_ARG);
+
+                if !p.at(T![')']) {
+                    p.expect(T![,]);
+                }
+            }
+        }
+        p.expect(T![')']);
+        Some(m.complete(p, FORMAT_ARGS_EXPR))
+    } else if p.at_contextual_kw(T![asm]) {
+        p.bump_remap(T![asm]);
+        p.expect(T!['(']);
+        // FIXME: We just put expression here so highlighting kind of keeps working
+        expr(p);
+        p.expect(T![')']);
+        Some(m.complete(p, ASM_EXPR))
+    } else {
+        m.abandon(p);
+        None
+    }
+}
+
 // test array_expr
 // fn foo() {
 //     [];
@@ -662,19 +732,3 @@ fn try_block_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
     }
     m.complete(p, BLOCK_EXPR)
 }
-
-// test box_expr
-// fn foo() {
-//     let x = box 1i32;
-//     let y = (box 1i32, box 2i32);
-//     let z = Foo(box 1i32, box 2i32);
-// }
-fn box_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
-    assert!(p.at(T![box]));
-    let m = m.unwrap_or_else(|| p.start());
-    p.bump(T![box]);
-    if p.at_ts(EXPR_FIRST) {
-        expr(p);
-    }
-    m.complete(p, BOX_EXPR)
-}
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index e4dce21f32a..36c52953a02 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -221,6 +221,7 @@ impl<'a> Converter<'a> {
                 rustc_lexer::TokenKind::Caret => T![^],
                 rustc_lexer::TokenKind::Percent => T![%],
                 rustc_lexer::TokenKind::Unknown => ERROR,
+                rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT,
                 rustc_lexer::TokenKind::UnknownPrefix => {
                     err = "unknown literal prefix";
                     IDENT
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 48f407623d8..db5278f89d5 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
@@ -105,12 +105,16 @@ pub enum SyntaxKind {
     WHILE_KW,
     YIELD_KW,
     AUTO_KW,
+    BUILTIN_KW,
     DEFAULT_KW,
     EXISTENTIAL_KW,
     UNION_KW,
     RAW_KW,
     MACRO_RULES_KW,
     YEET_KW,
+    OFFSET_OF_KW,
+    ASM_KW,
+    FORMAT_ARGS_KW,
     INT_NUMBER,
     FLOAT_NUMBER,
     CHAR,
@@ -203,7 +207,10 @@ pub enum SyntaxKind {
     RECORD_EXPR,
     RECORD_EXPR_FIELD_LIST,
     RECORD_EXPR_FIELD,
-    BOX_EXPR,
+    OFFSET_OF_EXPR,
+    ASM_EXPR,
+    FORMAT_ARGS_EXPR,
+    FORMAT_ARGS_ARG,
     CALL_EXPR,
     INDEX_EXPR,
     METHOD_CALL_EXPR,
@@ -315,12 +322,16 @@ impl SyntaxKind {
                 | WHILE_KW
                 | YIELD_KW
                 | AUTO_KW
+                | BUILTIN_KW
                 | DEFAULT_KW
                 | EXISTENTIAL_KW
                 | UNION_KW
                 | RAW_KW
                 | MACRO_RULES_KW
                 | YEET_KW
+                | OFFSET_OF_KW
+                | ASM_KW
+                | FORMAT_ARGS_KW
         )
     }
     pub fn is_punct(self) -> bool {
@@ -435,12 +446,16 @@ impl SyntaxKind {
     pub fn from_contextual_keyword(ident: &str) -> Option<SyntaxKind> {
         let kw = match ident {
             "auto" => AUTO_KW,
+            "builtin" => BUILTIN_KW,
             "default" => DEFAULT_KW,
             "existential" => EXISTENTIAL_KW,
             "union" => UNION_KW,
             "raw" => RAW_KW,
             "macro_rules" => MACRO_RULES_KW,
             "yeet" => YEET_KW,
+            "offset_of" => OFFSET_OF_KW,
+            "asm" => ASM_KW,
+            "format_args" => FORMAT_ARGS_KW,
             _ => return None,
         };
         Some(kw)
@@ -481,5 +496,5 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
 pub use T;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast
deleted file mode 100644
index b21f37cd85a..00000000000
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast
+++ /dev/null
@@ -1,90 +0,0 @@
-SOURCE_FILE
-  FN
-    FN_KW "fn"
-    WHITESPACE " "
-    NAME
-      IDENT "foo"
-    PARAM_LIST
-      L_PAREN "("
-      R_PAREN ")"
-    WHITESPACE " "
-    BLOCK_EXPR
-      STMT_LIST
-        L_CURLY "{"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          IDENT_PAT
-            NAME
-              IDENT "x"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          BOX_EXPR
-            BOX_KW "box"
-            WHITESPACE " "
-            LITERAL
-              INT_NUMBER "1i32"
-          SEMICOLON ";"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          IDENT_PAT
-            NAME
-              IDENT "y"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          TUPLE_EXPR
-            L_PAREN "("
-            BOX_EXPR
-              BOX_KW "box"
-              WHITESPACE " "
-              LITERAL
-                INT_NUMBER "1i32"
-            COMMA ","
-            WHITESPACE " "
-            BOX_EXPR
-              BOX_KW "box"
-              WHITESPACE " "
-              LITERAL
-                INT_NUMBER "2i32"
-            R_PAREN ")"
-          SEMICOLON ";"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          IDENT_PAT
-            NAME
-              IDENT "z"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          CALL_EXPR
-            PATH_EXPR
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "Foo"
-            ARG_LIST
-              L_PAREN "("
-              BOX_EXPR
-                BOX_KW "box"
-                WHITESPACE " "
-                LITERAL
-                  INT_NUMBER "1i32"
-              COMMA ","
-              WHITESPACE " "
-              BOX_EXPR
-                BOX_KW "box"
-                WHITESPACE " "
-                LITERAL
-                  INT_NUMBER "2i32"
-              R_PAREN ")"
-          SEMICOLON ";"
-        WHITESPACE "\n"
-        R_CURLY "}"
-  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs
deleted file mode 100644
index fc9923b7137..00000000000
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn foo() {
-    let x = box 1i32;
-    let y = (box 1i32, box 2i32);
-    let z = Foo(box 1i32, box 2i32);
-}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast
new file mode 100644
index 00000000000..361900b6d3e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rast
@@ -0,0 +1,105 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          ASM_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            ASM_KW "asm"
+            L_PAREN "("
+            LITERAL
+              INT_NUMBER "0"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          FORMAT_ARGS_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            FORMAT_ARGS_KW "format_args"
+            L_PAREN "("
+            LITERAL
+              STRING "\"\""
+            COMMA ","
+            WHITESPACE " "
+            FORMAT_ARGS_ARG
+              LITERAL
+                INT_NUMBER "0"
+            COMMA ","
+            WHITESPACE " "
+            FORMAT_ARGS_ARG
+              LITERAL
+                INT_NUMBER "1"
+            COMMA ","
+            WHITESPACE " "
+            FORMAT_ARGS_ARG
+              NAME
+                IDENT "a"
+              WHITESPACE " "
+              EQ "="
+              WHITESPACE " "
+              BIN_EXPR
+                LITERAL
+                  INT_NUMBER "2"
+                WHITESPACE " "
+                PLUS "+"
+                WHITESPACE " "
+                LITERAL
+                  INT_NUMBER "3"
+            COMMA ","
+            WHITESPACE " "
+            FORMAT_ARGS_ARG
+              BIN_EXPR
+                PATH_EXPR
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "a"
+                WHITESPACE " "
+                PLUS "+"
+                WHITESPACE " "
+                PATH_EXPR
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "b"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          OFFSET_OF_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            OFFSET_OF_KW "offset_of"
+            L_PAREN "("
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Foo"
+            COMMA ","
+            WHITESPACE " "
+            NAME_REF
+              IDENT "bar"
+            DOT "."
+            NAME_REF
+              IDENT "baz"
+            DOT "."
+            NAME_REF
+              INT_NUMBER "0"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs
new file mode 100644
index 00000000000..14431b0210e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0207_builtin_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+    builtin#asm(0);
+    builtin#format_args("", 0, 1, a = 2 + 3, a + b);
+    builtin#offset_of(Foo, bar.baz.0);
+}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-test/build.rs
index 19a5caa4ccd..7827157865a 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-test/build.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-test/build.rs
@@ -71,6 +71,10 @@ fn main() {
         .arg("--target-dir")
         .arg(&target_dir);
 
+    if let Ok(target) = std::env::var("TARGET") {
+        cmd.args(["--target", &target]);
+    }
+
     println!("Running {cmd:?}");
 
     let output = cmd.output().unwrap();
diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
index 8392718b227..c5d55f7d217 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
@@ -2,14 +2,29 @@
 
 use std::process::Command;
 
+use anyhow::Context;
 use rustc_hash::FxHashMap;
 
-use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};
+use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath, Sysroot};
+
+/// Determines how `rustc --print cfg` is discovered and invoked.
+///
+/// There options are supported:
+/// - [`RustcCfgConfig::Cargo`], which relies on `cargo rustc --print cfg`
+///   and `RUSTC_BOOTSTRAP`.
+/// - [`RustcCfgConfig::Explicit`], which uses an explicit path to the `rustc`
+///   binary in the sysroot.
+/// - [`RustcCfgConfig::Discover`], which uses [`toolchain::rustc`].
+pub(crate) enum RustcCfgConfig<'a> {
+    Cargo(&'a ManifestPath),
+    Explicit(&'a Sysroot),
+    Discover,
+}
 
 pub(crate) fn get(
-    cargo_toml: Option<&ManifestPath>,
     target: Option<&str>,
     extra_env: &FxHashMap<String, String>,
+    config: RustcCfgConfig<'_>,
 ) -> Vec<CfgFlag> {
     let _p = profile::span("rustc_cfg::get");
     let mut res = Vec::with_capacity(6 * 2 + 1);
@@ -25,49 +40,67 @@ pub(crate) fn get(
     // Add miri cfg, which is useful for mir eval in stdlib
     res.push(CfgFlag::Atom("miri".into()));
 
-    match get_rust_cfgs(cargo_toml, target, extra_env) {
+    let rustc_cfgs = get_rust_cfgs(target, extra_env, config);
+
+    let rustc_cfgs = match rustc_cfgs {
+        Ok(cfgs) => cfgs,
+        Err(e) => {
+            tracing::error!(?e, "failed to get rustc cfgs");
+            return res;
+        }
+    };
+
+    let rustc_cfgs =
+        rustc_cfgs.lines().map(|it| it.parse::<CfgFlag>()).collect::<Result<Vec<_>, _>>();
+
+    match rustc_cfgs {
         Ok(rustc_cfgs) => {
-            tracing::debug!(
-                "rustc cfgs found: {:?}",
-                rustc_cfgs
-                    .lines()
-                    .map(|it| it.parse::<CfgFlag>().map(|it| it.to_string()))
-                    .collect::<Vec<_>>()
-            );
-            res.extend(rustc_cfgs.lines().filter_map(|it| it.parse().ok()));
+            tracing::debug!(?rustc_cfgs, "rustc cfgs found");
+            res.extend(rustc_cfgs);
+        }
+        Err(e) => {
+            tracing::error!(?e, "failed to get rustc cfgs")
         }
-        Err(e) => tracing::error!("failed to get rustc cfgs: {e:?}"),
     }
 
     res
 }
 
 fn get_rust_cfgs(
-    cargo_toml: Option<&ManifestPath>,
     target: Option<&str>,
     extra_env: &FxHashMap<String, String>,
+    config: RustcCfgConfig<'_>,
 ) -> anyhow::Result<String> {
-    if let Some(cargo_toml) = cargo_toml {
-        let mut cargo_config = Command::new(toolchain::cargo());
-        cargo_config.envs(extra_env);
-        cargo_config
-            .current_dir(cargo_toml.parent())
-            .args(["rustc", "-Z", "unstable-options", "--print", "cfg"])
-            .env("RUSTC_BOOTSTRAP", "1");
-        if let Some(target) = target {
-            cargo_config.args(["--target", target]);
+    let mut cmd = match config {
+        RustcCfgConfig::Cargo(cargo_toml) => {
+            let mut cmd = Command::new(toolchain::cargo());
+            cmd.envs(extra_env);
+            cmd.current_dir(cargo_toml.parent())
+                .args(["rustc", "-Z", "unstable-options", "--print", "cfg"])
+                .env("RUSTC_BOOTSTRAP", "1");
+            if let Some(target) = target {
+                cmd.args(["--target", target]);
+            }
+
+            return utf8_stdout(cmd).context("Unable to run `cargo rustc`");
         }
-        match utf8_stdout(cargo_config) {
-            Ok(it) => return Ok(it),
-            Err(e) => tracing::debug!("{e:?}: falling back to querying rustc for cfgs"),
+        RustcCfgConfig::Explicit(sysroot) => {
+            let rustc: std::path::PathBuf = sysroot.discover_rustc()?.into();
+            tracing::debug!(?rustc, "using explicit rustc from sysroot");
+            Command::new(rustc)
         }
-    }
-    // using unstable cargo features failed, fall back to using plain rustc
-    let mut cmd = Command::new(toolchain::rustc());
+        RustcCfgConfig::Discover => {
+            let rustc = toolchain::rustc();
+            tracing::debug!(?rustc, "using rustc from env");
+            Command::new(rustc)
+        }
+    };
+
     cmd.envs(extra_env);
     cmd.args(["--print", "cfg", "-O"]);
     if let Some(target) = target {
         cmd.args(["--target", target]);
     }
-    utf8_stdout(cmd)
+
+    utf8_stdout(cmd).context("Unable to run `rustc`")
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index da862c9e87f..fe046dd1463 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -115,10 +115,19 @@ impl Sysroot {
         Ok(Sysroot::load(sysroot_dir, src))
     }
 
-    pub fn discover_rustc(&self) -> Option<ManifestPath> {
+    pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
         get_rustc_src(&self.root)
     }
 
+    pub fn discover_rustc(&self) -> Result<AbsPathBuf, std::io::Error> {
+        let rustc = self.root.join("bin/rustc");
+        tracing::debug!(?rustc, "checking for rustc binary at location");
+        match fs::metadata(&rustc) {
+            Ok(_) => Ok(rustc),
+            Err(e) => Err(e),
+        }
+    }
+
     pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result<Sysroot> {
         let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
             format_err!("can't load standard library from sysroot path {sysroot_dir}")
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 13463e9f72e..e0209ca15a5 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -2,7 +2,7 @@
 //! metadata` or `rust-project.json`) into representation stored in the salsa
 //! database -- `CrateGraph`.
 
-use std::{collections::VecDeque, fmt, fs, process::Command, sync};
+use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, sync};
 
 use anyhow::{format_err, Context};
 use base_db::{
@@ -21,7 +21,7 @@ use crate::{
     cargo_workspace::{DepKind, PackageData, RustLibSource},
     cfg_flag::CfgFlag,
     project_json::Crate,
-    rustc_cfg,
+    rustc_cfg::{self, RustcCfgConfig},
     sysroot::SysrootCrate,
     target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
     Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
@@ -240,9 +240,9 @@ impl ProjectWorkspace {
                     Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
                         .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
                     Some(RustLibSource::Discover) => {
-                        sysroot.as_ref().ok().and_then(Sysroot::discover_rustc).ok_or_else(|| {
-                            Some(format!("Failed to discover rustc source for sysroot."))
-                        })
+                        sysroot.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else(
+                            || Some(format!("Failed to discover rustc source for sysroot.")),
+                        )
                     }
                     None => Err(None),
                 };
@@ -279,8 +279,11 @@ impl ProjectWorkspace {
                     }
                 });
 
-                let rustc_cfg =
-                    rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
+                let rustc_cfg = rustc_cfg::get(
+                    config.target.as_deref(),
+                    &config.extra_env,
+                    RustcCfgConfig::Cargo(cargo_toml),
+                );
 
                 let cfg_overrides = config.cfg_overrides.clone();
                 let data_layout = target_data_layout::get(
@@ -331,11 +334,18 @@ impl ProjectWorkspace {
             }
             (None, None) => Err(None),
         };
-        if let Ok(sysroot) = &sysroot {
-            tracing::info!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
-        }
+        let config = match &sysroot {
+            Ok(sysroot) => {
+                tracing::debug!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
+                RustcCfgConfig::Explicit(sysroot)
+            }
+            Err(_) => {
+                tracing::debug!("discovering sysroot");
+                RustcCfgConfig::Discover
+            }
+        };
 
-        let rustc_cfg = rustc_cfg::get(None, target, extra_env);
+        let rustc_cfg = rustc_cfg::get(target, extra_env, config);
         ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg, toolchain }
     }
 
@@ -357,10 +367,18 @@ impl ProjectWorkspace {
             }
             None => Err(None),
         };
-        if let Ok(sysroot) = &sysroot {
-            tracing::info!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
-        }
-        let rustc_cfg = rustc_cfg::get(None, None, &Default::default());
+        let rustc_config = match &sysroot {
+            Ok(sysroot) => {
+                tracing::info!(src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
+                RustcCfgConfig::Explicit(sysroot)
+            }
+            Err(_) => {
+                tracing::info!("discovering sysroot");
+                RustcCfgConfig::Discover
+            }
+        };
+
+        let rustc_cfg = rustc_cfg::get(None, &FxHashMap::default(), rustc_config);
         Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
     }
 
@@ -730,6 +748,7 @@ fn project_json_to_crate_graph(
         )
     });
 
+    let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned());
     let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
     let crates: FxHashMap<CrateId, CrateId> = project
         .crates()
@@ -754,9 +773,14 @@ fn project_json_to_crate_graph(
                 let env = env.clone().into_iter().collect();
 
                 let target_cfgs = match target.as_deref() {
-                    Some(target) => cfg_cache
-                        .entry(target)
-                        .or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)),
+                    Some(target) => cfg_cache.entry(target).or_insert_with(|| {
+                        let rustc_cfg = match sysroot {
+                            Some(sysroot) => RustcCfgConfig::Explicit(sysroot),
+                            None => RustcCfgConfig::Discover,
+                        };
+
+                        rustc_cfg::get(Some(target), extra_env, rustc_cfg)
+                    }),
                     None => &rustc_cfg,
                 };
 
@@ -765,7 +789,12 @@ fn project_json_to_crate_graph(
                     *edition,
                     display_name.clone(),
                     version.clone(),
-                    target_cfgs.iter().chain(cfg.iter()).cloned().collect(),
+                    target_cfgs
+                        .iter()
+                        .chain(cfg.iter())
+                        .chain(iter::once(&r_a_cfg_flag))
+                        .cloned()
+                        .collect(),
                     None,
                     env,
                     *is_proc_macro,
@@ -820,7 +849,7 @@ fn cargo_to_crate_graph(
     sysroot: Option<&Sysroot>,
     rustc_cfg: Vec<CfgFlag>,
     override_cfg: &CfgOverrides,
-    // Don't compute cfg and use this if present
+    // Don't compute cfg and use this if present, only used for the sysroot experiment hack
     forced_cfg: Option<CfgOptions>,
     build_scripts: &WorkspaceBuildScripts,
     target_layout: TargetLayoutLoadResult,
@@ -842,12 +871,7 @@ fn cargo_to_crate_graph(
         None => (SysrootPublicDeps::default(), None),
     };
 
-    let cfg_options = {
-        let mut cfg_options = CfgOptions::default();
-        cfg_options.extend(rustc_cfg);
-        cfg_options.insert_atom("debug_assertions".into());
-        cfg_options
-    };
+    let cfg_options = create_cfg_options(rustc_cfg);
 
     // Mapping of a package to its library target
     let mut pkg_to_lib_crate = FxHashMap::default();
@@ -866,6 +890,9 @@ fn cargo_to_crate_graph(
             if cargo[pkg].is_local {
                 cfg_options.insert_atom("test".into());
             }
+            if cargo[pkg].is_member {
+                cfg_options.insert_atom("rust_analyzer".into());
+            }
 
             if !override_cfg.global.is_empty() {
                 cfg_options.apply_diff(override_cfg.global.clone());
@@ -1029,8 +1056,8 @@ fn detached_files_to_crate_graph(
         None => (SysrootPublicDeps::default(), None),
     };
 
-    let mut cfg_options = CfgOptions::default();
-    cfg_options.extend(rustc_cfg);
+    let mut cfg_options = create_cfg_options(rustc_cfg);
+    cfg_options.insert_atom("rust_analyzer".into());
 
     for detached_file in detached_files {
         let file_id = match load(detached_file) {
@@ -1228,6 +1255,10 @@ fn add_target_crate_root(
 
     let mut env = Env::default();
     inject_cargo_env(pkg, &mut env);
+    if let Ok(cname) = String::from_str(cargo_name) {
+        // CARGO_CRATE_NAME is the name of the Cargo target with - converted to _, such as the name of the library, binary, example, integration test, or benchmark.
+        env.set("CARGO_CRATE_NAME", cname.replace("-", "_"));
+    }
 
     if let Some(envs) = build_data.map(|it| &it.envs) {
         for (k, v) in envs {
@@ -1291,8 +1322,7 @@ fn sysroot_to_crate_graph(
     channel: Option<ReleaseChannel>,
 ) -> (SysrootPublicDeps, Option<CrateId>) {
     let _p = profile::span("sysroot_to_crate_graph");
-    let mut cfg_options = CfgOptions::default();
-    cfg_options.extend(rustc_cfg.clone());
+    let cfg_options = create_cfg_options(rustc_cfg.clone());
     let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = match &sysroot.hack_cargo_workspace {
         Some(cargo) => handle_hack_cargo_workspace(
             load,
@@ -1471,3 +1501,10 @@ fn inject_cargo_env(package: &PackageData, env: &mut Env) {
 
     env.set("CARGO_PKG_LICENSE_FILE", String::new());
 }
+
+fn create_cfg_options(rustc_cfg: Vec<CfgFlag>) -> CfgOptions {
+    let mut cfg_options = CfgOptions::default();
+    cfg_options.extend(rustc_cfg);
+    cfg_options.insert_atom("debug_assertions".into());
+    cfg_options
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index e595cd82729..727d39a3077 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -18,6 +18,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -81,6 +82,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -151,6 +153,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -162,7 +165,7 @@
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
                 "CARGO_PKG_VERSION": "0.1.0",
                 "CARGO_PKG_AUTHORS": "",
-                "CARGO_CRATE_NAME": "hello_world",
+                "CARGO_CRATE_NAME": "an_example",
                 "CARGO_PKG_LICENSE_FILE": "",
                 "CARGO_PKG_HOMEPAGE": "",
                 "CARGO_PKG_DESCRIPTION": "",
@@ -221,6 +224,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -232,7 +236,7 @@
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
                 "CARGO_PKG_VERSION": "0.1.0",
                 "CARGO_PKG_AUTHORS": "",
-                "CARGO_CRATE_NAME": "hello_world",
+                "CARGO_CRATE_NAME": "it",
                 "CARGO_PKG_LICENSE_FILE": "",
                 "CARGO_PKG_HOMEPAGE": "",
                 "CARGO_PKG_DESCRIPTION": "",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index e595cd82729..727d39a3077 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -18,6 +18,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -81,6 +82,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -151,6 +153,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -162,7 +165,7 @@
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
                 "CARGO_PKG_VERSION": "0.1.0",
                 "CARGO_PKG_AUTHORS": "",
-                "CARGO_CRATE_NAME": "hello_world",
+                "CARGO_CRATE_NAME": "an_example",
                 "CARGO_PKG_LICENSE_FILE": "",
                 "CARGO_PKG_HOMEPAGE": "",
                 "CARGO_PKG_DESCRIPTION": "",
@@ -221,6 +224,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
                 "test",
             ],
         ),
@@ -232,7 +236,7 @@
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
                 "CARGO_PKG_VERSION": "0.1.0",
                 "CARGO_PKG_AUTHORS": "",
-                "CARGO_CRATE_NAME": "hello_world",
+                "CARGO_CRATE_NAME": "it",
                 "CARGO_PKG_LICENSE_FILE": "",
                 "CARGO_PKG_HOMEPAGE": "",
                 "CARGO_PKG_DESCRIPTION": "",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index f10c55d0462..89728babd82 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -18,6 +18,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
             ],
         ),
         potential_cfg_options: None,
@@ -80,6 +81,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
             ],
         ),
         potential_cfg_options: None,
@@ -149,6 +151,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
             ],
         ),
         potential_cfg_options: None,
@@ -159,7 +162,7 @@
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
                 "CARGO_PKG_VERSION": "0.1.0",
                 "CARGO_PKG_AUTHORS": "",
-                "CARGO_CRATE_NAME": "hello_world",
+                "CARGO_CRATE_NAME": "an_example",
                 "CARGO_PKG_LICENSE_FILE": "",
                 "CARGO_PKG_HOMEPAGE": "",
                 "CARGO_PKG_DESCRIPTION": "",
@@ -218,6 +221,7 @@
         cfg_options: CfgOptions(
             [
                 "debug_assertions",
+                "rust_analyzer",
             ],
         ),
         potential_cfg_options: None,
@@ -228,7 +232,7 @@
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
                 "CARGO_PKG_VERSION": "0.1.0",
                 "CARGO_PKG_AUTHORS": "",
-                "CARGO_CRATE_NAME": "hello_world",
+                "CARGO_CRATE_NAME": "it",
                 "CARGO_PKG_LICENSE_FILE": "",
                 "CARGO_PKG_HOMEPAGE": "",
                 "CARGO_PKG_DESCRIPTION": "",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index fb3f5933b17..b7bf6cb2774 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -14,7 +14,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -53,7 +55,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -84,7 +88,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -115,7 +121,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -146,7 +154,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -192,7 +202,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -223,7 +235,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -311,7 +325,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -342,7 +358,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -373,7 +391,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "debug_assertions",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
@@ -404,7 +424,9 @@
             },
         ),
         cfg_options: CfgOptions(
-            [],
+            [
+                "rust_analyzer",
+            ],
         ),
         potential_cfg_options: None,
         env: Env {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 1f9d6db9314..7410f0a3a66 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -50,7 +50,6 @@ always-assert = "0.1.2"
 # These 3 deps are not used by r-a directly, but we list them here to lock in their versions
 # in our transitive deps to prevent them from pulling in windows-sys 0.45.0
 mio = "=0.8.5"
-filetime = "=0.2.19"
 parking_lot_core = "=0.9.6"
 
 cfg.workspace = true
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
index ab06b96814a..8c9261ab05e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
@@ -16,10 +16,12 @@ use lsp_types::{
 };
 use serde_json::json;
 
-use crate::config::{Config, RustfmtConfig};
-use crate::line_index::PositionEncoding;
-use crate::lsp_ext::negotiated_encoding;
-use crate::semantic_tokens;
+use crate::{
+    config::{Config, RustfmtConfig},
+    line_index::PositionEncoding,
+    lsp::semantic_tokens,
+    lsp_ext::negotiated_encoding,
+};
 
 pub fn server_capabilities(config: &Config) -> ServerCapabilities {
     ServerCapabilities {
@@ -218,7 +220,7 @@ fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProvi
 }
 
 fn more_trigger_character(config: &Config) -> Vec<String> {
-    let mut res = vec![".".to_string(), ">".to_string(), "{".to_string()];
+    let mut res = vec![".".to_string(), ">".to_string(), "{".to_string(), "(".to_string()];
     if config.snippet_cap() {
         res.push("<".to_string());
     }
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 4a03be1893c..dcb3ca6581c 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
@@ -15,7 +15,10 @@ use hir_def::{
     hir::{ExprId, PatId},
 };
 use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
-use ide::{Analysis, AnnotationConfig, DiagnosticsConfig, InlayHintsConfig, LineCol, RootDatabase};
+use ide::{
+    Analysis, AnnotationConfig, DiagnosticsConfig, InlayFieldsToResolve, InlayHintsConfig, LineCol,
+    RootDatabase,
+};
 use ide_db::{
     base_db::{
         salsa::{self, debug::DebugQueryTable, ParallelDatabase},
@@ -317,9 +320,13 @@ impl flags::AnalysisStats {
 
     fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) {
         let mut sw = self.stop_watch();
-        let all = bodies.len() as u64;
+        let mut all = 0;
         let mut fail = 0;
         for &body in bodies {
+            if matches!(body, DefWithBody::Variant(_)) {
+                continue;
+            }
+            all += 1;
             let Err(e) = db.mir_body(body.into()) else {
                 continue;
             };
@@ -782,6 +789,7 @@ impl flags::AnalysisStats {
                     closure_style: hir::ClosureStyle::ImplFn,
                     max_length: Some(25),
                     closing_brace_hints_min_lines: Some(20),
+                    fields_to_resolve: InlayFieldsToResolve::empty(),
                 },
                 file_id,
                 None,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index 42d180114e5..d6a45ce06f2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -21,7 +21,7 @@ use vfs::{AbsPathBuf, Vfs};
 use crate::{
     cli::flags,
     line_index::{LineEndings, LineIndex, PositionEncoding},
-    to_proto,
+    lsp::to_proto,
     version::version,
 };
 
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 44337f955e5..8c056fff000 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
@@ -51,7 +51,7 @@ impl flags::Scip {
             version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
             tool_info: Some(scip_types::ToolInfo {
                 name: "rust-analyzer".to_owned(),
-                version: "0.1".to_owned(),
+                version: format!("{}", crate::version::version()),
                 arguments: vec![],
                 special_fields: Default::default(),
             })
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 40c50f6d176..ea3a21241cb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -13,8 +13,9 @@ use cfg::{CfgAtom, CfgDiff};
 use flycheck::FlycheckConfig;
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
-    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
-    JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
+    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
+    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+    Snippet, SnippetScope,
 };
 use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
@@ -1335,6 +1336,18 @@ impl Config {
     }
 
     pub fn inlay_hints(&self) -> InlayHintsConfig {
+        let client_capability_fields = self
+            .caps
+            .text_document
+            .as_ref()
+            .and_then(|text| text.inlay_hint.as_ref())
+            .and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref())
+            .map(|inlay_resolve| inlay_resolve.properties.iter())
+            .into_iter()
+            .flatten()
+            .cloned()
+            .collect::<FxHashSet<_>>();
+
         InlayHintsConfig {
             render_colons: self.data.inlayHints_renderColons,
             type_hints: self.data.inlayHints_typeHints_enable,
@@ -1395,6 +1408,13 @@ impl Config {
             } else {
                 None
             },
+            fields_to_resolve: InlayFieldsToResolve {
+                resolve_text_edits: client_capability_fields.contains("textEdits"),
+                resolve_hint_tooltip: client_capability_fields.contains("tooltip"),
+                resolve_label_tooltip: client_capability_fields.contains("label.tooltip"),
+                resolve_label_location: client_capability_fields.contains("label.location"),
+                resolve_label_command: client_capability_fields.contains("label.command"),
+            },
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
index b65f38a0c71..71701ef1617 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -9,7 +9,7 @@ use nohash_hasher::{IntMap, IntSet};
 use rustc_hash::FxHashSet;
 use triomphe::Arc;
 
-use crate::lsp_ext;
+use crate::{global_state::GlobalStateSnapshot, lsp, lsp_ext};
 
 pub(crate) type CheckFixes = Arc<IntMap<usize, IntMap<FileId, Vec<Fix>>>>;
 
@@ -122,3 +122,41 @@ fn are_diagnostics_equal(left: &lsp_types::Diagnostic, right: &lsp_types::Diagno
         && left.range == right.range
         && left.message == right.message
 }
+
+pub(crate) fn fetch_native_diagnostics(
+    snapshot: GlobalStateSnapshot,
+    subscriptions: Vec<FileId>,
+) -> Vec<(FileId, Vec<lsp_types::Diagnostic>)> {
+    let _p = profile::span("fetch_native_diagnostics");
+    let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned());
+    subscriptions
+        .into_iter()
+        .filter_map(|file_id| {
+            let line_index = snapshot.file_line_index(file_id).ok()?;
+            let diagnostics = snapshot
+                .analysis
+                .diagnostics(
+                    &snapshot.config.diagnostics(),
+                    ide::AssistResolveStrategy::None,
+                    file_id,
+                )
+                .ok()?
+                .into_iter()
+                .map(move |d| lsp_types::Diagnostic {
+                    range: lsp::to_proto::range(&line_index, d.range),
+                    severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
+                    code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_string())),
+                    code_description: Some(lsp_types::CodeDescription {
+                        href: lsp_types::Url::parse(&d.code.url()).unwrap(),
+                    }),
+                    source: Some("rust-analyzer".to_string()),
+                    message: d.message,
+                    related_information: None,
+                    tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
+                    data: None,
+                })
+                .collect::<Vec<_>>();
+            Some((file_id, diagnostics))
+        })
+        .collect()
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 06564578d80..731580557c2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -8,8 +8,8 @@ use stdx::format_to;
 use vfs::{AbsPath, AbsPathBuf};
 
 use crate::{
-    global_state::GlobalStateSnapshot, line_index::PositionEncoding, lsp_ext,
-    to_proto::url_from_abs_path,
+    global_state::GlobalStateSnapshot, line_index::PositionEncoding,
+    lsp::to_proto::url_from_abs_path, lsp_ext,
 };
 
 use super::{DiagnosticsMapConfig, Fix};
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
index 5e5cd9a0269..7da43118881 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -8,9 +8,9 @@ use stdx::thread::ThreadIntent;
 
 use crate::{
     global_state::{GlobalState, GlobalStateSnapshot},
+    lsp::LspError,
     main_loop::Task,
     version::version,
-    LspError,
 };
 
 /// A visitor for routing a raw JSON request to an appropriate handler function.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index ea8a6975195..c09f57252ce 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -12,25 +12,27 @@ use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
 use nohash_hasher::IntMap;
-use parking_lot::{Mutex, RwLock};
+use parking_lot::{
+    MappedRwLockReadGuard, Mutex, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard,
+    RwLockWriteGuard,
+};
 use proc_macro_api::ProcMacroServer;
 use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
 use rustc_hash::{FxHashMap, FxHashSet};
 use triomphe::Arc;
-use vfs::AnchoredPathBuf;
+use vfs::{AnchoredPathBuf, Vfs};
 
 use crate::{
     config::{Config, ConfigError},
     diagnostics::{CheckFixes, DiagnosticCollection},
-    from_proto,
     line_index::{LineEndings, LineIndex},
+    lsp::{from_proto, to_proto::url_from_abs_path},
     lsp_ext,
     main_loop::Task,
     mem_docs::MemDocs,
     op_queue::OpQueue,
     reload,
     task_pool::TaskPool,
-    to_proto::url_from_abs_path,
 };
 
 // Enforces drop order
@@ -40,7 +42,7 @@ pub(crate) struct Handle<H, C> {
 }
 
 pub(crate) type ReqHandler = fn(&mut GlobalState, lsp_server::Response);
-pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
+type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
 
 /// `GlobalState` is the primary mutable state of the language server
 ///
@@ -49,6 +51,7 @@ pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
 /// incremental salsa database.
 ///
 /// Note that this struct has more than one impl in various modules!
+#[doc(alias = "GlobalMess")]
 pub(crate) struct GlobalState {
     sender: Sender<lsp_server::Message>,
     req_queue: ReqQueue,
@@ -66,6 +69,7 @@ pub(crate) struct GlobalState {
 
     // status
     pub(crate) shutdown_requested: bool,
+    pub(crate) send_hint_refresh_query: bool,
     pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
 
     // proc macros
@@ -177,6 +181,7 @@ impl GlobalState {
             mem_docs: MemDocs::default(),
             semantic_tokens_cache: Arc::new(Default::default()),
             shutdown_requested: false,
+            send_hint_refresh_query: false,
             last_reported_status: None,
             source_root_config: SourceRootConfig::default(),
             config_errors: Default::default(),
@@ -216,12 +221,15 @@ impl GlobalState {
         let mut file_changes = FxHashMap::default();
         let (change, changed_files, workspace_structure_change) = {
             let mut change = Change::new();
-            let (vfs, line_endings_map) = &mut *self.vfs.write();
-            let changed_files = vfs.take_changes();
+            let mut guard = self.vfs.write();
+            let changed_files = guard.0.take_changes();
             if changed_files.is_empty() {
                 return false;
             }
 
+            // downgrade to read lock to allow more readers while we are normalizing text
+            let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
+            let vfs: &Vfs = &guard.0;
             // We need to fix up the changed events a bit. If we have a create or modify for a file
             // id that is followed by a delete we actually skip observing the file text from the
             // earlier event, to avoid problems later on.
@@ -272,6 +280,7 @@ impl GlobalState {
             let mut workspace_structure_change = None;
             // A file was added or deleted
             let mut has_structure_changes = false;
+            let mut bytes = vec![];
             for file in &changed_files {
                 let vfs_path = &vfs.file_path(file.file_id);
                 if let Some(path) = vfs_path.as_path() {
@@ -293,16 +302,28 @@ impl GlobalState {
 
                 let text = if file.exists() {
                     let bytes = vfs.file_contents(file.file_id).to_vec();
+
                     String::from_utf8(bytes).ok().and_then(|text| {
+                        // FIXME: Consider doing normalization in the `vfs` instead? That allows
+                        // getting rid of some locking
                         let (text, line_endings) = LineEndings::normalize(text);
-                        line_endings_map.insert(file.file_id, line_endings);
-                        Some(Arc::from(text))
+                        Some((Arc::from(text), line_endings))
                     })
                 } else {
                     None
                 };
-                change.change_file(file.file_id, text);
+                // delay `line_endings_map` changes until we are done normalizing the text
+                // this allows delaying the re-acquisition of the write lock
+                bytes.push((file.file_id, text));
             }
+            let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
+            bytes.into_iter().for_each(|(file_id, text)| match text {
+                None => change.change_file(file_id, None),
+                Some((text, line_endings)) => {
+                    line_endings_map.insert(file_id, line_endings);
+                    change.change_file(file_id, Some(text));
+                }
+            });
             if has_structure_changes {
                 let roots = self.source_root_config.partition(vfs);
                 change.set_roots(roots);
@@ -422,12 +443,16 @@ impl Drop for GlobalState {
 }
 
 impl GlobalStateSnapshot {
+    fn vfs_read(&self) -> MappedRwLockReadGuard<'_, vfs::Vfs> {
+        RwLockReadGuard::map(self.vfs.read(), |(it, _)| it)
+    }
+
     pub(crate) fn url_to_file_id(&self, url: &Url) -> anyhow::Result<FileId> {
-        url_to_file_id(&self.vfs.read().0, url)
+        url_to_file_id(&self.vfs_read(), url)
     }
 
     pub(crate) fn file_id_to_url(&self, id: FileId) -> Url {
-        file_id_to_url(&self.vfs.read().0, id)
+        file_id_to_url(&self.vfs_read(), id)
     }
 
     pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
@@ -443,7 +468,7 @@ impl GlobalStateSnapshot {
     }
 
     pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Url {
-        let mut base = self.vfs.read().0.file_path(path.anchor);
+        let mut base = self.vfs_read().file_path(path.anchor);
         base.pop();
         let path = base.join(&path.path).unwrap();
         let path = path.as_path().unwrap();
@@ -451,7 +476,7 @@ impl GlobalStateSnapshot {
     }
 
     pub(crate) fn file_id_to_file_path(&self, file_id: FileId) -> vfs::VfsPath {
-        self.vfs.read().0.file_path(file_id)
+        self.vfs_read().file_path(file_id)
     }
 
     pub(crate) fn cargo_target_for_crate_root(
@@ -459,7 +484,7 @@ impl GlobalStateSnapshot {
         crate_id: CrateId,
     ) -> Option<(&CargoWorkspace, Target)> {
         let file_id = self.analysis.crate_root(crate_id).ok()?;
-        let path = self.vfs.read().0.file_path(file_id);
+        let path = self.vfs_read().file_path(file_id);
         let path = path.as_path()?;
         self.workspaces.iter().find_map(|ws| match ws {
             ProjectWorkspace::Cargo { cargo, .. } => {
@@ -471,7 +496,11 @@ impl GlobalStateSnapshot {
     }
 
     pub(crate) fn vfs_memory_usage(&self) -> usize {
-        self.vfs.read().0.memory_usage()
+        self.vfs_read().memory_usage()
+    }
+
+    pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
+        self.vfs.read().0.exists(file_id)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index e830e5e9a64..f9070d27353 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -13,8 +13,12 @@ use triomphe::Arc;
 use vfs::{AbsPathBuf, ChangeKind, VfsPath};
 
 use crate::{
-    config::Config, from_proto, global_state::GlobalState, lsp_ext::RunFlycheckParams,
-    lsp_utils::apply_document_changes, mem_docs::DocumentData, reload,
+    config::Config,
+    global_state::GlobalState,
+    lsp::{from_proto, utils::apply_document_changes},
+    lsp_ext::RunFlycheckParams,
+    mem_docs::DocumentData,
+    reload,
 };
 
 pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> anyhow::Result<()> {
@@ -84,15 +88,16 @@ pub(crate) fn handle_did_change_text_document(
             }
         };
 
-        let vfs = &mut state.vfs.write().0;
-        let file_id = vfs.file_id(&path).unwrap();
         let text = apply_document_changes(
             state.config.position_encoding(),
-            || std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(),
+            || {
+                let vfs = &state.vfs.read().0;
+                let file_id = vfs.file_id(&path).unwrap();
+                std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into()
+            },
             params.content_changes,
         );
-
-        vfs.set_file_contents(path, Some(text.into_bytes()));
+        state.vfs.write().0.set_file_contents(path, Some(text.into_bytes()));
     }
     Ok(())
 }
@@ -108,6 +113,10 @@ pub(crate) fn handle_did_close_text_document(
             tracing::error!("orphan DidCloseTextDocument: {}", path);
         }
 
+        if let Some(file_id) = state.vfs.read().0.file_id(&path) {
+            state.diagnostics.clear_native_for(file_id);
+        }
+
         state.semantic_tokens_cache.lock().remove(&params.text_document.uri);
 
         if let Some(path) = path.as_path() {
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 5f1f731cffb..b8a1a39be19 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
@@ -11,8 +11,8 @@ use anyhow::Context;
 
 use ide::{
     AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
-    HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
-    SingleResolve, SourceChange, TextEdit,
+    HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory,
+    Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
 };
 use ide_db::SymbolKind;
 use lsp_server::ErrorCode;
@@ -30,21 +30,23 @@ use serde_json::json;
 use stdx::{format_to, never};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
 use triomphe::Arc;
-use vfs::{AbsPath, AbsPathBuf, VfsPath};
+use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
     cargo_target_spec::CargoTargetSpec,
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
     diff::diff,
-    from_proto,
     global_state::{GlobalState, GlobalStateSnapshot},
     line_index::LineEndings,
+    lsp::{
+        from_proto, to_proto,
+        utils::{all_edits_are_disjoint, invalid_params_error},
+        LspError,
+    },
     lsp_ext::{
         self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
         FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
     },
-    lsp_utils::{all_edits_are_disjoint, invalid_params_error},
-    to_proto, LspError,
 };
 
 pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
@@ -354,7 +356,7 @@ pub(crate) fn handle_on_type_formatting(
 
     // This should be a single-file edit
     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");
+    stdx::always!(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))
@@ -972,7 +974,7 @@ pub(crate) fn handle_hover(
         PositionOrRange::Range(range) => range,
     };
 
-    let file_range = from_proto::file_range(&snap, params.text_document, range)?;
+    let file_range = from_proto::file_range(&snap, &params.text_document, range)?;
     let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
         None => return Ok(None),
         Some(info) => info,
@@ -1128,7 +1130,7 @@ pub(crate) fn handle_code_action(
 
     let line_index =
         snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
-    let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?;
+    let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
 
     let mut assists_config = snap.config.assist();
     assists_config.allowed = params
@@ -1381,7 +1383,7 @@ pub(crate) fn handle_ssr(
     let selections = params
         .selections
         .iter()
-        .map(|range| from_proto::file_range(&snap, params.position.text_document.clone(), *range))
+        .map(|range| from_proto::file_range(&snap, &params.position.text_document, *range))
         .collect::<Result<Vec<_>, _>>()?;
     let position = from_proto::file_position(&snap, params.position)?;
     let source_change = snap.analysis.structural_search_replace(
@@ -1401,7 +1403,7 @@ pub(crate) fn handle_inlay_hints(
     let document_uri = &params.text_document.uri;
     let FileRange { file_id, range } = from_proto::file_range(
         &snap,
-        TextDocumentIdentifier::new(document_uri.to_owned()),
+        &TextDocumentIdentifier::new(document_uri.to_owned()),
         params.range,
     )?;
     let line_index = snap.file_line_index(file_id)?;
@@ -1410,17 +1412,73 @@ pub(crate) fn handle_inlay_hints(
         snap.analysis
             .inlay_hints(&inlay_hints_config, file_id, Some(range))?
             .into_iter()
-            .map(|it| to_proto::inlay_hint(&snap, &line_index, it))
+            .map(|it| {
+                to_proto::inlay_hint(
+                    &snap,
+                    &inlay_hints_config.fields_to_resolve,
+                    &line_index,
+                    file_id,
+                    it,
+                )
+            })
             .collect::<Cancellable<Vec<_>>>()?,
     ))
 }
 
 pub(crate) fn handle_inlay_hints_resolve(
-    _snap: GlobalStateSnapshot,
-    hint: InlayHint,
+    snap: GlobalStateSnapshot,
+    mut original_hint: InlayHint,
 ) -> anyhow::Result<InlayHint> {
     let _p = profile::span("handle_inlay_hints_resolve");
-    Ok(hint)
+
+    let data = match original_hint.data.take() {
+        Some(it) => it,
+        None => return Ok(original_hint),
+    };
+
+    let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
+    let file_id = FileId(resolve_data.file_id);
+    anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data");
+
+    let line_index = snap.file_line_index(file_id)?;
+    let range = from_proto::text_range(
+        &line_index,
+        lsp_types::Range { start: original_hint.position, end: original_hint.position },
+    )?;
+    let range_start = range.start();
+    let range_end = range.end();
+    let large_range = TextRange::new(
+        range_start.checked_sub(1.into()).unwrap_or(range_start),
+        range_end.checked_add(1.into()).unwrap_or(range_end),
+    );
+    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
+    forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
+    let resolve_hints = snap.analysis.inlay_hints(
+        &forced_resolve_inlay_hints_config,
+        file_id,
+        Some(large_range),
+    )?;
+
+    let mut resolved_hints = resolve_hints
+        .into_iter()
+        .filter_map(|it| {
+            to_proto::inlay_hint(
+                &snap,
+                &forced_resolve_inlay_hints_config.fields_to_resolve,
+                &line_index,
+                file_id,
+                it,
+            )
+            .ok()
+        })
+        .filter(|hint| hint.position == original_hint.position)
+        .filter(|hint| hint.kind == original_hint.kind);
+    if let Some(resolved_hint) = resolved_hints.next() {
+        if resolved_hints.next().is_none() {
+            return Ok(resolved_hint);
+        }
+    }
+    Ok(original_hint)
 }
 
 pub(crate) fn handle_call_hierarchy_prepare(
@@ -1453,7 +1511,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
     let item = params.item;
 
     let doc = TextDocumentIdentifier::new(item.uri);
-    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
+    let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
     let call_items = match snap.analysis.incoming_calls(fpos)? {
@@ -1488,7 +1546,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     let item = params.item;
 
     let doc = TextDocumentIdentifier::new(item.uri);
-    let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
+    let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
     let call_items = match snap.analysis.outgoing_calls(fpos)? {
@@ -1569,18 +1627,21 @@ pub(crate) fn handle_semantic_tokens_full_delta(
         snap.config.highlighting_non_standard_tokens(),
     );
 
-    let mut cache = snap.semantic_tokens_cache.lock();
-    let cached_tokens = cache.entry(params.text_document.uri).or_default();
+    let cached_tokens = snap.semantic_tokens_cache.lock().remove(&params.text_document.uri);
 
-    if let Some(prev_id) = &cached_tokens.result_id {
+    if let Some(cached_tokens @ lsp_types::SemanticTokens { result_id: Some(prev_id), .. }) =
+        &cached_tokens
+    {
         if *prev_id == params.previous_result_id {
             let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens);
-            *cached_tokens = semantic_tokens;
+            snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens);
             return Ok(Some(delta.into()));
         }
     }
 
-    *cached_tokens = semantic_tokens.clone();
+    // Clone first to keep the lock short
+    let semantic_tokens_clone = semantic_tokens.clone();
+    snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens_clone);
 
     Ok(Some(semantic_tokens.into()))
 }
@@ -1591,7 +1652,7 @@ pub(crate) fn handle_semantic_tokens_range(
 ) -> anyhow::Result<Option<SemanticTokensRangeResult>> {
     let _p = profile::span("handle_semantic_tokens_range");
 
-    let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
+    let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
     let text = snap.analysis.file_text(frange.file_id)?;
     let line_index = snap.file_line_index(frange.file_id)?;
 
@@ -1674,7 +1735,7 @@ pub(crate) fn handle_move_item(
 ) -> anyhow::Result<Vec<lsp_ext::SnippetTextEdit>> {
     let _p = profile::span("handle_move_item");
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let range = from_proto::file_range(&snap, params.text_document, params.range)?;
+    let range = from_proto::file_range(&snap, &params.text_document, params.range)?;
 
     let direction = match params.direction {
         lsp_ext::MoveItemDirection::Up => ide::Direction::Up,
@@ -1879,12 +1940,15 @@ fn run_rustfmt(
 
     // Determine the edition of the crate the file belongs to (if there's multiple, we pick the
     // highest edition).
-    let editions = snap
+    let Ok(editions) = snap
         .analysis
         .relevant_crates_for(file_id)?
         .into_iter()
         .map(|crate_id| snap.analysis.crate_edition(crate_id))
-        .collect::<Result<Vec<_>, _>>()?;
+        .collect::<Result<Vec<_>, _>>()
+    else {
+        return Ok(None);
+    };
     let edition = editions.iter().copied().max();
 
     let line_index = snap.file_line_index(file_id)?;
@@ -1894,23 +1958,7 @@ fn run_rustfmt(
             let mut cmd = process::Command::new(toolchain::rustfmt());
             cmd.envs(snap.config.extra_env());
             cmd.args(extra_args);
-            // try to chdir to the file so we can respect `rustfmt.toml`
-            // FIXME: use `rustfmt --config-path` once
-            // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
-            match text_document.uri.to_file_path() {
-                Ok(mut path) => {
-                    // pop off file name
-                    if path.pop() && path.is_dir() {
-                        cmd.current_dir(path);
-                    }
-                }
-                Err(_) => {
-                    tracing::error!(
-                        "Unable to get file path for {}, rustfmt.toml might be ignored",
-                        text_document.uri
-                    );
-                }
-            }
+
             if let Some(edition) = edition {
                 cmd.arg("--edition");
                 cmd.arg(edition.to_string());
@@ -1929,7 +1977,7 @@ fn run_rustfmt(
                     .into());
                 }
 
-                let frange = from_proto::file_range(snap, text_document, range)?;
+                let frange = from_proto::file_range(snap, &text_document, range)?;
                 let start_line = line_index.index.line_col(frange.range.start()).line;
                 let end_line = line_index.index.line_col(frange.range.end()).line;
 
@@ -1948,12 +1996,31 @@ fn run_rustfmt(
         }
         RustfmtConfig::CustomCommand { command, args } => {
             let mut cmd = process::Command::new(command);
+
             cmd.envs(snap.config.extra_env());
             cmd.args(args);
             cmd
         }
     };
 
+    // try to chdir to the file so we can respect `rustfmt.toml`
+    // FIXME: use `rustfmt --config-path` once
+    // https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
+    match text_document.uri.to_file_path() {
+        Ok(mut path) => {
+            // pop off file name
+            if path.pop() && path.is_dir() {
+                command.current_dir(path);
+            }
+        }
+        Err(_) => {
+            tracing::error!(
+                text_document = ?text_document.uri,
+                "Unable to get path, rustfmt.toml might be ignored"
+            );
+        }
+    }
+
     let mut rustfmt = command
         .stdin(Stdio::piped())
         .stdout(Stdio::piped())
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 57e26c241bb..6c62577f696 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -23,18 +23,13 @@ mod cargo_target_spec;
 mod diagnostics;
 mod diff;
 mod dispatch;
-mod from_proto;
 mod global_state;
 mod line_index;
-mod lsp_utils;
 mod main_loop;
-mod markdown;
 mod mem_docs;
 mod op_queue;
 mod reload;
-mod semantic_tokens;
 mod task_pool;
-mod to_proto;
 mod version;
 
 mod handlers {
@@ -43,13 +38,12 @@ mod handlers {
 }
 
 pub mod config;
-pub mod lsp_ext;
+pub mod lsp;
+use self::lsp::ext as lsp_ext;
 
 #[cfg(test)]
 mod integrated_benchmarks;
 
-use std::fmt;
-
 use serde::de::DeserializeOwned;
 
 pub use crate::{caps::server_capabilities, main_loop::main_loop, version::version};
@@ -61,23 +55,3 @@ pub fn from_json<T: DeserializeOwned>(
     serde_json::from_value(json.clone())
         .map_err(|e| anyhow::format_err!("Failed to deserialize {what}: {e}; {json}"))
 }
-
-#[derive(Debug)]
-struct LspError {
-    code: i32,
-    message: String,
-}
-
-impl LspError {
-    fn new(code: i32, message: String) -> LspError {
-        LspError { code, message }
-    }
-}
-
-impl fmt::Display for LspError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "Language Server request failed with {}. ({})", self.code, self.message)
-    }
-}
-
-impl std::error::Error for LspError {}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs
new file mode 100644
index 00000000000..ac7e1a95e62
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp.rs
@@ -0,0 +1,29 @@
+//! Custom LSP definitions and protocol conversions.
+
+use core::fmt;
+
+pub(crate) mod utils;
+pub(crate) mod semantic_tokens;
+pub mod ext;
+pub(crate) mod from_proto;
+pub(crate) mod to_proto;
+
+#[derive(Debug)]
+pub(crate) struct LspError {
+    pub(crate) code: i32,
+    pub(crate) message: String,
+}
+
+impl LspError {
+    pub(crate) fn new(code: i32, message: String) -> LspError {
+        LspError { code, message }
+    }
+}
+
+impl fmt::Display for LspError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Language Server request failed with {}. ({})", self.code, self.message)
+    }
+}
+
+impl std::error::Error for LspError {}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index d0989b3230d..ad56899163d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -682,7 +682,9 @@ pub struct CompletionResolveData {
 }
 
 #[derive(Debug, Serialize, Deserialize)]
-pub struct InlayHintResolveData {}
+pub struct InlayHintResolveData {
+    pub file_id: u32,
+}
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct CompletionImport {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
index c247e1bb229..69d6aba94c3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
@@ -12,8 +12,8 @@ use crate::{
     from_json,
     global_state::GlobalStateSnapshot,
     line_index::{LineIndex, PositionEncoding},
+    lsp::utils::invalid_params_error,
     lsp_ext,
-    lsp_utils::invalid_params_error,
 };
 
 pub(crate) fn abs_path(url: &lsp_types::Url) -> anyhow::Result<AbsPathBuf> {
@@ -72,7 +72,7 @@ pub(crate) fn file_position(
 
 pub(crate) fn file_range(
     snap: &GlobalStateSnapshot,
-    text_document_identifier: lsp_types::TextDocumentIdentifier,
+    text_document_identifier: &lsp_types::TextDocumentIdentifier,
     range: lsp_types::Range,
 ) -> anyhow::Result<FileRange> {
     file_range_uri(snap, &text_document_identifier.uri, range)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
index 1fe02fc7ead..1fe02fc7ead 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 7b32180e3eb..23074493aee 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -8,11 +8,12 @@ use std::{
 use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
     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, SnippetEdit, SourceChange, StructureNodeKind,
-    SymbolKind, TextEdit, TextRange, TextSize,
+    Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
+    InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
+    NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
+    SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
+use ide_db::rust_doc::format_docs;
 use itertools::Itertools;
 use serde_json::to_value;
 use vfs::AbsPath;
@@ -22,9 +23,12 @@ use crate::{
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
+    lsp::{
+        semantic_tokens::{self, standard_fallback_type},
+        utils::invalid_params_error,
+        LspError,
+    },
     lsp_ext::{self, SnippetTextEdit},
-    lsp_utils::invalid_params_error,
-    semantic_tokens::{self, standard_fallback_type},
 };
 
 pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
@@ -102,7 +106,7 @@ pub(crate) fn diagnostic_severity(severity: Severity) -> lsp_types::DiagnosticSe
 }
 
 pub(crate) fn documentation(documentation: Documentation) -> lsp_types::Documentation {
-    let value = crate::markdown::format_docs(documentation.as_str());
+    let value = format_docs(&documentation);
     let markup_content = lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value };
     lsp_types::Documentation::MarkupContent(markup_content)
 }
@@ -413,7 +417,7 @@ pub(crate) fn signature_help(
     let documentation = call_info.doc.filter(|_| config.docs).map(|doc| {
         lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent {
             kind: lsp_types::MarkupKind::Markdown,
-            value: crate::markdown::format_docs(&doc),
+            value: format_docs(&doc),
         })
     });
 
@@ -434,10 +438,25 @@ pub(crate) fn signature_help(
 
 pub(crate) fn inlay_hint(
     snap: &GlobalStateSnapshot,
+    fields_to_resolve: &InlayFieldsToResolve,
     line_index: &LineIndex,
+    file_id: FileId,
     inlay_hint: InlayHint,
 ) -> Cancellable<lsp_types::InlayHint> {
-    let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?;
+    let needs_resolve = inlay_hint.needs_resolve;
+    let (label, tooltip, mut something_to_resolve) =
+        inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?;
+    let text_edits = if needs_resolve && fields_to_resolve.resolve_text_edits {
+        something_to_resolve |= inlay_hint.text_edit.is_some();
+        None
+    } else {
+        inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it))
+    };
+    let data = if needs_resolve && something_to_resolve {
+        Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.0 }).unwrap())
+    } else {
+        None
+    };
 
     Ok(lsp_types::InlayHint {
         position: match inlay_hint.position {
@@ -451,8 +470,8 @@ pub(crate) fn inlay_hint(
             InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE),
             _ => None,
         },
-        text_edits: inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)),
-        data: None,
+        text_edits,
+        data,
         tooltip,
         label,
     })
@@ -460,13 +479,18 @@ pub(crate) fn inlay_hint(
 
 fn inlay_hint_label(
     snap: &GlobalStateSnapshot,
+    fields_to_resolve: &InlayFieldsToResolve,
+    needs_resolve: bool,
     mut label: InlayHintLabel,
-) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>)> {
-    let res = match &*label.parts {
+) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>, bool)> {
+    let mut something_to_resolve = false;
+    let (label, tooltip) = match &*label.parts {
         [InlayHintLabelPart { linked_location: None, .. }] => {
             let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
-            (
-                lsp_types::InlayHintLabel::String(text),
+            let hint_tooltip = if needs_resolve && fields_to_resolve.resolve_hint_tooltip {
+                something_to_resolve |= tooltip.is_some();
+                None
+            } else {
                 match tooltip {
                     Some(ide::InlayTooltip::String(s)) => {
                         Some(lsp_types::InlayHintTooltip::String(s))
@@ -478,41 +502,52 @@ fn inlay_hint_label(
                         }))
                     }
                     None => None,
-                },
-            )
+                }
+            };
+            (lsp_types::InlayHintLabel::String(text), hint_tooltip)
         }
         _ => {
             let parts = label
                 .parts
                 .into_iter()
                 .map(|part| {
-                    part.linked_location.map(|range| location(snap, range)).transpose().map(
-                        |location| lsp_types::InlayHintLabelPart {
-                            value: part.text,
-                            tooltip: match part.tooltip {
-                                Some(ide::InlayTooltip::String(s)) => {
-                                    Some(lsp_types::InlayHintLabelPartTooltip::String(s))
-                                }
-                                Some(ide::InlayTooltip::Markdown(s)) => {
-                                    Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
-                                        lsp_types::MarkupContent {
-                                            kind: lsp_types::MarkupKind::Markdown,
-                                            value: s,
-                                        },
-                                    ))
-                                }
-                                None => None,
-                            },
-                            location,
-                            command: None,
-                        },
-                    )
+                    let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
+                        something_to_resolve |= part.tooltip.is_some();
+                        None
+                    } else {
+                        match part.tooltip {
+                            Some(ide::InlayTooltip::String(s)) => {
+                                Some(lsp_types::InlayHintLabelPartTooltip::String(s))
+                            }
+                            Some(ide::InlayTooltip::Markdown(s)) => {
+                                Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
+                                    lsp_types::MarkupContent {
+                                        kind: lsp_types::MarkupKind::Markdown,
+                                        value: s,
+                                    },
+                                ))
+                            }
+                            None => None,
+                        }
+                    };
+                    let location = if needs_resolve && fields_to_resolve.resolve_label_location {
+                        something_to_resolve |= part.linked_location.is_some();
+                        None
+                    } else {
+                        part.linked_location.map(|range| location(snap, range)).transpose()?
+                    };
+                    Ok(lsp_types::InlayHintLabelPart {
+                        value: part.text,
+                        tooltip,
+                        location,
+                        command: None,
+                    })
                 })
                 .collect::<Cancellable<_>>()?;
             (lsp_types::InlayHintLabel::LabelParts(parts), None)
         }
     };
-    Ok(res)
+    Ok((label, tooltip, something_to_resolve))
 }
 
 static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
@@ -1323,17 +1358,18 @@ pub(crate) fn code_lens(
                 })
             }
         }
-        AnnotationKind::HasImpls { pos: file_range, data } => {
+        AnnotationKind::HasImpls { pos, data } => {
             if !client_commands_config.show_reference {
                 return Ok(());
             }
-            let line_index = snap.file_line_index(file_range.file_id)?;
+            let line_index = snap.file_line_index(pos.file_id)?;
             let annotation_range = range(&line_index, annotation.range);
-            let url = url(snap, file_range.file_id);
+            let url = url(snap, pos.file_id);
+            let pos = position(&line_index, pos.offset);
 
             let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
 
-            let doc_pos = lsp_types::TextDocumentPositionParams::new(id, annotation_range.start);
+            let doc_pos = lsp_types::TextDocumentPositionParams::new(id, pos);
 
             let goto_params = lsp_types::request::GotoImplementationParams {
                 text_document_position_params: doc_pos,
@@ -1356,7 +1392,7 @@ pub(crate) fn code_lens(
                 command::show_references(
                     implementation_title(locations.len()),
                     &url,
-                    annotation_range.start,
+                    pos,
                     locations,
                 )
             });
@@ -1376,28 +1412,24 @@ pub(crate) fn code_lens(
                 })(),
             })
         }
-        AnnotationKind::HasReferences { pos: file_range, data } => {
+        AnnotationKind::HasReferences { pos, data } => {
             if !client_commands_config.show_reference {
                 return Ok(());
             }
-            let line_index = snap.file_line_index(file_range.file_id)?;
+            let line_index = snap.file_line_index(pos.file_id)?;
             let annotation_range = range(&line_index, annotation.range);
-            let url = url(snap, file_range.file_id);
+            let url = url(snap, pos.file_id);
+            let pos = position(&line_index, pos.offset);
 
             let id = lsp_types::TextDocumentIdentifier { uri: url.clone() };
 
-            let doc_pos = lsp_types::TextDocumentPositionParams::new(id, annotation_range.start);
+            let doc_pos = lsp_types::TextDocumentPositionParams::new(id, pos);
 
             let command = data.map(|ranges| {
                 let locations: Vec<lsp_types::Location> =
                     ranges.into_iter().filter_map(|range| location(snap, range).ok()).collect();
 
-                command::show_references(
-                    reference_title(locations.len()),
-                    &url,
-                    annotation_range.start,
-                    locations,
-                )
+                command::show_references(reference_title(locations.len()), &url, pos, locations)
             });
 
             acc.push(lsp_types::CodeLens {
@@ -1425,8 +1457,8 @@ pub(crate) mod command {
 
     use crate::{
         global_state::GlobalStateSnapshot,
+        lsp::to_proto::{location, location_link},
         lsp_ext,
-        to_proto::{location, location_link},
     };
 
     pub(crate) fn show_references(
@@ -1528,11 +1560,11 @@ pub(crate) fn markup_content(
         ide::HoverDocFormat::Markdown => lsp_types::MarkupKind::Markdown,
         ide::HoverDocFormat::PlainText => lsp_types::MarkupKind::PlainText,
     };
-    let value = crate::markdown::format_docs(markup.as_str());
+    let value = format_docs(&Documentation::new(markup.into()));
     lsp_types::MarkupContent { kind, value }
 }
 
-pub(crate) fn rename_error(err: RenameError) -> crate::LspError {
+pub(crate) fn rename_error(err: RenameError) -> LspError {
     // This is wrong, but we don't have a better alternative I suppose?
     // https://github.com/microsoft/language-server-protocol/issues/1341
     invalid_params_error(err.to_string())
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
index 74e79e8e605..b388b317599 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
@@ -6,10 +6,10 @@ use lsp_types::request::Request;
 use triomphe::Arc;
 
 use crate::{
-    from_proto,
     global_state::GlobalState,
     line_index::{LineEndings, LineIndex, PositionEncoding},
-    lsp_ext, LspError,
+    lsp::{from_proto, LspError},
+    lsp_ext,
 };
 
 pub(crate) fn invalid_params_error(message: String) -> LspError {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 74036710fa3..cdf41c955d2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -17,11 +17,14 @@ use vfs::FileId;
 
 use crate::{
     config::Config,
+    diagnostics::fetch_native_diagnostics,
     dispatch::{NotificationDispatcher, RequestDispatcher},
-    from_proto,
     global_state::{file_id_to_url, url_to_file_id, GlobalState},
+    lsp::{
+        from_proto,
+        utils::{notification_is, Progress},
+    },
     lsp_ext,
-    lsp_utils::{notification_is, Progress},
     reload::{BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress},
 };
 
@@ -317,8 +320,11 @@ impl GlobalState {
                 }
 
                 // Refresh inlay hints if the client supports it.
-                if self.config.inlay_hints_refresh() {
+                if (self.send_hint_refresh_query || self.proc_macro_changed)
+                    && self.config.inlay_hints_refresh()
+                {
                     self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
+                    self.send_hint_refresh_query = false;
                 }
             }
 
@@ -420,6 +426,32 @@ impl GlobalState {
         });
     }
 
+    fn update_diagnostics(&mut self) {
+        let db = self.analysis_host.raw_database();
+        let subscriptions = self
+            .mem_docs
+            .iter()
+            .map(|path| self.vfs.read().0.file_id(path).unwrap())
+            .filter(|&file_id| {
+                let source_root = db.file_source_root(file_id);
+                // Only publish diagnostics for files in the workspace, not from crates.io deps
+                // or the sysroot.
+                // While theoretically these should never have errors, we have quite a few false
+                // positives particularly in the stdlib, and those diagnostics would stay around
+                // forever if we emitted them here.
+                !db.source_root(source_root).is_library
+            })
+            .collect::<Vec<_>>();
+        tracing::trace!("updating notifications for {:?}", subscriptions);
+
+        // Diagnostics are triggered by the user typing
+        // so we run them on a latency sensitive thread.
+        self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, {
+            let snapshot = self.snapshot();
+            move || Task::Diagnostics(fetch_native_diagnostics(snapshot, subscriptions))
+        });
+    }
+
     fn update_status_or_notify(&mut self) {
         let status = self.current_status();
         if self.last_reported_status.as_ref() != Some(&status) {
@@ -509,6 +541,7 @@ impl GlobalState {
                         }
 
                         self.switch_workspaces("fetched build data".to_string());
+                        self.send_hint_refresh_query = true;
 
                         (Some(Progress::End), None)
                     }
@@ -525,7 +558,7 @@ impl GlobalState {
                     ProcMacroProgress::End(proc_macro_load_result) => {
                         self.fetch_proc_macros_queue.op_completed(true);
                         self.set_proc_macros(proc_macro_load_result);
-
+                        self.send_hint_refresh_query = true;
                         (Some(Progress::End), None)
                     }
                 };
@@ -670,6 +703,7 @@ impl GlobalState {
         }
 
         use crate::handlers::request as handlers;
+        use lsp_types::request as lsp_request;
 
         dispatcher
             // Request handlers that must run on the main thread
@@ -682,30 +716,30 @@ impl GlobalState {
             // are run on the main thread to reduce latency:
             .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
             .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
-            .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)
+            .on_sync::<lsp_request::SelectionRangeRequest>(handlers::handle_selection_range)
             .on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
             .on_sync::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
             // Formatting should be done immediately as the editor might wait on it, but we can't
             // put it on the main thread as we do not want the main thread to block on rustfmt.
             // So we have an extra thread just for formatting requests to make sure it gets handled
             // as fast as possible.
-            .on_fmt_thread::<lsp_types::request::Formatting>(handlers::handle_formatting)
-            .on_fmt_thread::<lsp_types::request::RangeFormatting>(handlers::handle_range_formatting)
+            .on_fmt_thread::<lsp_request::Formatting>(handlers::handle_formatting)
+            .on_fmt_thread::<lsp_request::RangeFormatting>(handlers::handle_range_formatting)
             // We can’t run latency-sensitive request handlers which do semantic
             // analysis on the main thread because that would block other
             // requests. Instead, we run these request handlers on higher priority
             // threads in the threadpool.
-            .on_latency_sensitive::<lsp_types::request::Completion>(handlers::handle_completion)
-            .on_latency_sensitive::<lsp_types::request::ResolveCompletionItem>(
+            .on_latency_sensitive::<lsp_request::Completion>(handlers::handle_completion)
+            .on_latency_sensitive::<lsp_request::ResolveCompletionItem>(
                 handlers::handle_completion_resolve,
             )
-            .on_latency_sensitive::<lsp_types::request::SemanticTokensFullRequest>(
+            .on_latency_sensitive::<lsp_request::SemanticTokensFullRequest>(
                 handlers::handle_semantic_tokens_full,
             )
-            .on_latency_sensitive::<lsp_types::request::SemanticTokensFullDeltaRequest>(
+            .on_latency_sensitive::<lsp_request::SemanticTokensFullDeltaRequest>(
                 handlers::handle_semantic_tokens_full_delta,
             )
-            .on_latency_sensitive::<lsp_types::request::SemanticTokensRangeRequest>(
+            .on_latency_sensitive::<lsp_request::SemanticTokensRangeRequest>(
                 handlers::handle_semantic_tokens_range,
             )
             // All other request handlers
@@ -729,29 +763,25 @@ impl GlobalState {
             .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
             .on::<lsp_ext::MoveItem>(handlers::handle_move_item)
             .on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
-            .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
-            .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
-            .on::<lsp_types::request::GotoDeclaration>(handlers::handle_goto_declaration)
-            .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
-            .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
-            .on_no_retry::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints)
-            .on::<lsp_types::request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
-            .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
-            .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
-            .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
-            .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)
-            .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)
-            .on::<lsp_types::request::Rename>(handlers::handle_rename)
-            .on::<lsp_types::request::References>(handlers::handle_references)
-            .on::<lsp_types::request::DocumentHighlightRequest>(handlers::handle_document_highlight)
-            .on::<lsp_types::request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
-            .on::<lsp_types::request::CallHierarchyIncomingCalls>(
-                handlers::handle_call_hierarchy_incoming,
-            )
-            .on::<lsp_types::request::CallHierarchyOutgoingCalls>(
-                handlers::handle_call_hierarchy_outgoing,
-            )
-            .on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files)
+            .on::<lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
+            .on::<lsp_request::GotoDefinition>(handlers::handle_goto_definition)
+            .on::<lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
+            .on::<lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
+            .on::<lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
+            .on_no_retry::<lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
+            .on::<lsp_request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
+            .on::<lsp_request::CodeLensRequest>(handlers::handle_code_lens)
+            .on::<lsp_request::CodeLensResolve>(handlers::handle_code_lens_resolve)
+            .on::<lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
+            .on::<lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
+            .on::<lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
+            .on::<lsp_request::Rename>(handlers::handle_rename)
+            .on::<lsp_request::References>(handlers::handle_references)
+            .on::<lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
+            .on::<lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
+            .on::<lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
+            .on::<lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
+            .on::<lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
             .on::<lsp_ext::Ssr>(handlers::handle_ssr)
             .on::<lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
             .finish();
@@ -788,77 +818,4 @@ impl GlobalState {
             .finish();
         Ok(())
     }
-
-    fn update_diagnostics(&mut self) {
-        let db = self.analysis_host.raw_database();
-        let subscriptions = self
-            .mem_docs
-            .iter()
-            .map(|path| self.vfs.read().0.file_id(path).unwrap())
-            .filter(|&file_id| {
-                let source_root = db.file_source_root(file_id);
-                // Only publish diagnostics for files in the workspace, not from crates.io deps
-                // or the sysroot.
-                // While theoretically these should never have errors, we have quite a few false
-                // positives particularly in the stdlib, and those diagnostics would stay around
-                // forever if we emitted them here.
-                !db.source_root(source_root).is_library
-            })
-            .collect::<Vec<_>>();
-
-        tracing::trace!("updating notifications for {:?}", subscriptions);
-
-        let snapshot = self.snapshot();
-
-        // Diagnostics are triggered by the user typing
-        // so we run them on a latency sensitive thread.
-        self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, move || {
-            let _p = profile::span("publish_diagnostics");
-            let _ctx = stdx::panic_context::enter("publish_diagnostics".to_owned());
-            let diagnostics = subscriptions
-                .into_iter()
-                .filter_map(|file_id| {
-                    let line_index = snapshot.file_line_index(file_id).ok()?;
-                    Some((
-                        file_id,
-                        line_index,
-                        snapshot
-                            .analysis
-                            .diagnostics(
-                                &snapshot.config.diagnostics(),
-                                ide::AssistResolveStrategy::None,
-                                file_id,
-                            )
-                            .ok()?,
-                    ))
-                })
-                .map(|(file_id, line_index, it)| {
-                    (
-                        file_id,
-                        it.into_iter()
-                            .map(move |d| lsp_types::Diagnostic {
-                                range: crate::to_proto::range(&line_index, d.range),
-                                severity: Some(crate::to_proto::diagnostic_severity(d.severity)),
-                                code: Some(lsp_types::NumberOrString::String(
-                                    d.code.as_str().to_string(),
-                                )),
-                                code_description: Some(lsp_types::CodeDescription {
-                                    href: lsp_types::Url::parse(&d.code.url()).unwrap(),
-                                }),
-                                source: Some("rust-analyzer".to_string()),
-                                message: d.message,
-                                related_information: None,
-                                tags: if d.unused {
-                                    Some(vec![lsp_types::DiagnosticTag::UNNECESSARY])
-                                } else {
-                                    None
-                                },
-                                data: None,
-                            })
-                            .collect::<Vec<_>>(),
-                    )
-                });
-            Task::Diagnostics(diagnostics.collect())
-        });
-    }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs
deleted file mode 100644
index 58426c66a85..00000000000
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/markdown.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-//! Transforms markdown
-use ide_db::rust_doc::is_rust_fence;
-
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
-
-pub(crate) fn format_docs(src: &str) -> String {
-    let mut processed_lines = Vec::new();
-    let mut in_code_block = false;
-    let mut is_rust = false;
-
-    for mut line in src.lines() {
-        if in_code_block && is_rust && code_line_ignored_by_rustdoc(line) {
-            continue;
-        }
-
-        if let Some(header) = RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
-        {
-            in_code_block ^= true;
-
-            if in_code_block {
-                is_rust = is_rust_fence(header);
-
-                if is_rust {
-                    line = "```rust";
-                }
-            }
-        }
-
-        if in_code_block {
-            let trimmed = line.trim_start();
-            if is_rust && trimmed.starts_with("##") {
-                line = &trimmed[1..];
-            }
-        }
-
-        processed_lines.push(line);
-    }
-    processed_lines.join("\n")
-}
-
-fn code_line_ignored_by_rustdoc(line: &str) -> bool {
-    let trimmed = line.trim();
-    trimmed == "#" || trimmed.starts_with("# ") || trimmed.starts_with("#\t")
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_format_docs_adds_rust() {
-        let comment = "```\nfn some_rust() {}\n```";
-        assert_eq!(format_docs(comment), "```rust\nfn some_rust() {}\n```");
-    }
-
-    #[test]
-    fn test_format_docs_handles_plain_text() {
-        let comment = "```text\nthis is plain text\n```";
-        assert_eq!(format_docs(comment), "```text\nthis is plain text\n```");
-    }
-
-    #[test]
-    fn test_format_docs_handles_non_rust() {
-        let comment = "```sh\nsupposedly shell code\n```";
-        assert_eq!(format_docs(comment), "```sh\nsupposedly shell code\n```");
-    }
-
-    #[test]
-    fn test_format_docs_handles_rust_alias() {
-        let comment = "```ignore\nlet z = 55;\n```";
-        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
-    }
-
-    #[test]
-    fn test_format_docs_handles_complex_code_block_attrs() {
-        let comment = "```rust,no_run\nlet z = 55;\n```";
-        assert_eq!(format_docs(comment), "```rust\nlet z = 55;\n```");
-    }
-
-    #[test]
-    fn test_format_docs_handles_error_codes() {
-        let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```";
-        assert_eq!(format_docs(comment), "```rust\nlet b = 0 as *const _;\n```");
-    }
-
-    #[test]
-    fn test_format_docs_skips_comments_in_rust_block() {
-        let comment =
-            "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n   #    \n #\tskip3\n\t#\t\n```";
-        assert_eq!(format_docs(comment), "```rust\n#stay1\nstay2\n```");
-    }
-
-    #[test]
-    fn test_format_docs_does_not_skip_lines_if_plain_text() {
-        let comment =
-            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```";
-        assert_eq!(
-            format_docs(comment),
-            "```text\n # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t\n```",
-        );
-    }
-
-    #[test]
-    fn test_format_docs_keeps_comments_outside_of_rust_block() {
-        let comment = " # stay1\n# stay2\n#stay3\nstay4\n#\n #\n   #    \n #\tstay5\n\t#\t";
-        assert_eq!(format_docs(comment), comment);
-    }
-
-    #[test]
-    fn test_format_docs_preserves_newlines() {
-        let comment = "this\nis\nmultiline";
-        assert_eq!(format_docs(comment), comment);
-    }
-
-    #[test]
-    fn test_code_blocks_in_comments_marked_as_rust() {
-        let comment = r#"```rust
-fn main(){}
-```
-Some comment.
-```
-let a = 1;
-```"#;
-
-        assert_eq!(
-            format_docs(comment),
-            "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```"
-        );
-    }
-
-    #[test]
-    fn test_code_blocks_in_comments_marked_as_text() {
-        let comment = r#"```text
-filler
-text
-```
-Some comment.
-```
-let a = 1;
-```"#;
-
-        assert_eq!(
-            format_docs(comment),
-            "```text\nfiller\ntext\n```\nSome comment.\n```rust\nlet a = 1;\n```"
-        );
-    }
-
-    #[test]
-    fn test_format_docs_handles_escape_double_hashes() {
-        let comment = r#"```rust
-let s = "foo
-## bar # baz";
-```"#;
-
-        assert_eq!(format_docs(comment), "```rust\nlet s = \"foo\n# bar # baz\";\n```");
-    }
-
-    #[test]
-    fn test_format_docs_handles_double_hashes_non_rust() {
-        let comment = r#"```markdown
-## A second-level heading
-```"#;
-        assert_eq!(format_docs(comment), "```markdown\n## A second-level heading\n```");
-    }
-}
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 0a2bb822475..3fae08b82e2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -12,6 +12,7 @@
 //! correct. Instead, we try to provide a best-effort service. Even if the
 //! project is currently loading and we don't have a full project model, we
 //! still want to respond to various  requests.
+// FIXME: This is a mess that needs some untangling work
 use std::{iter, mem};
 
 use flycheck::{FlycheckConfig, FlycheckHandle};
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 0bb29e7080f..d5991429899 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -29,7 +29,7 @@ use lsp_types::{
     PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem,
     TextDocumentPositionParams, WorkDoneProgressParams,
 };
-use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams};
+use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams};
 use serde_json::json;
 use test_utils::skip_slow_tests;
 
@@ -861,6 +861,7 @@ edition = "2021"
 bar = {path = "../bar"}
 
 //- /foo/src/main.rs
+#![allow(internal_features)]
 #![feature(rustc_attrs, decl_macro)]
 use bar::Bar;
 
@@ -938,7 +939,7 @@ pub fn foo(_input: TokenStream) -> TokenStream {
     let res = server.send_request::<HoverRequest>(HoverParams {
         text_document_position_params: TextDocumentPositionParams::new(
             server.doc_id("foo/src/main.rs"),
-            Position::new(11, 9),
+            Position::new(12, 9),
         ),
         work_done_progress_params: Default::default(),
     });
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 3c52ef5ef7f..e49b5768fa4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -9,7 +9,7 @@ use std::{
 use crossbeam_channel::{after, select, Receiver};
 use lsp_server::{Connection, Message, Notification, Request};
 use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
-use rust_analyzer::{config::Config, lsp_ext, main_loop};
+use rust_analyzer::{config::Config, lsp, main_loop};
 use serde::Serialize;
 use serde_json::{json, to_string_pretty, Value};
 use test_utils::FixtureWithProjectMeta;
@@ -260,9 +260,9 @@ impl Server {
             Message::Notification(n) if n.method == "experimental/serverStatus" => {
                 let status = n
                     .clone()
-                    .extract::<lsp_ext::ServerStatusParams>("experimental/serverStatus")
+                    .extract::<lsp::ext::ServerStatusParams>("experimental/serverStatus")
                     .unwrap();
-                if status.health != lsp_ext::Health::Ok {
+                if status.health != lsp::ext::Health::Ok {
                     panic!("server errored/warned while loading workspace: {:?}", status.message);
                 }
                 status.quiescent
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index f230cba2bf8..8b5c92c6602 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -35,7 +35,7 @@ fn check_lsp_extensions_docs() {
 
     let expected_hash = {
         let lsp_ext_rs = sh
-            .read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs"))
+            .read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp/ext.rs"))
             .unwrap();
         stable_hash(lsp_ext_rs.as_str())
     };
@@ -45,7 +45,7 @@ fn check_lsp_extensions_docs() {
             sh.read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap();
         let text = lsp_extensions_md
             .lines()
-            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
+            .find_map(|line| line.strip_prefix("lsp/ext.rs hash:"))
             .unwrap()
             .trim();
         u64::from_str_radix(text, 16).unwrap()
@@ -54,7 +54,7 @@ fn check_lsp_extensions_docs() {
     if actual_hash != expected_hash {
         panic!(
             "
-lsp_ext.rs was changed without touching lsp-extensions.md.
+lsp/ext.rs was changed without touching lsp-extensions.md.
 
 Expected hash: {expected_hash:x}
 Actual hash:   {actual_hash:x}
@@ -158,7 +158,7 @@ Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
 Apache-2.0/MIT
 BSD-3-Clause
 BlueOak-1.0.0 OR MIT OR Apache-2.0
-CC0-1.0 OR Artistic-2.0
+CC0-1.0
 ISC
 MIT
 MIT / Apache-2.0
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index ea7ebd85b33..3603560d35c 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -340,10 +340,10 @@ ExprStmt =
 
 Expr =
   ArrayExpr
+| AsmExpr
 | AwaitExpr
 | BinExpr
 | BlockExpr
-| BoxExpr
 | BreakExpr
 | CallExpr
 | CastExpr
@@ -351,6 +351,7 @@ Expr =
 | ContinueExpr
 | FieldExpr
 | ForExpr
+| FormatArgsExpr
 | IfExpr
 | IndexExpr
 | Literal
@@ -358,6 +359,7 @@ Expr =
 | MacroExpr
 | MatchExpr
 | MethodCallExpr
+| OffsetOfExpr
 | ParenExpr
 | PathExpr
 | PrefixExpr
@@ -373,6 +375,21 @@ Expr =
 | LetExpr
 | UnderscoreExpr
 
+OffsetOfExpr =
+  Attr* 'builtin' '#' 'offset_of' '(' Type ',' fields:(NameRef ('.' NameRef)* ) ')'
+
+AsmExpr =
+  Attr* 'builtin' '#' 'asm' '(' Expr ')'
+
+FormatArgsExpr =
+  Attr* 'builtin' '#' 'format_args' '('
+  template:Expr
+  (',' args:(FormatArgsArg (',' FormatArgsArg)* ','?)? )?
+  ')'
+
+FormatArgsArg =
+  (Name '=')? Expr
+
 MacroExpr =
   MacroCall
 
@@ -526,9 +543,6 @@ UnderscoreExpr =
 AwaitExpr =
   Attr* Expr '.' 'await'
 
-BoxExpr =
-  Attr* 'box' Expr
-
 //*************************//
 //          Types          //
 //*************************//
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 16448db04f8..7ba0d4dc656 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
@@ -805,6 +805,20 @@ impl ArrayExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct AsmExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for AsmExpr {}
+impl AsmExpr {
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AwaitExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -823,16 +837,6 @@ impl ast::HasAttrs for BinExpr {}
 impl BinExpr {}
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct BoxExpr {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ast::HasAttrs for BoxExpr {}
-impl BoxExpr {
-    pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
-    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct BreakExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -916,6 +920,24 @@ impl ForExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FormatArgsExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for FormatArgsExpr {}
+impl FormatArgsExpr {
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn format_args_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![format_args])
+    }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn args(&self) -> AstChildren<FormatArgsArg> { support::children(&self.syntax) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct IfExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -985,6 +1007,24 @@ impl MethodCallExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct OffsetOfExpr {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasAttrs for OffsetOfExpr {}
+impl OffsetOfExpr {
+    pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+    pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+    pub fn offset_of_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![offset_of])
+    }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
+    pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ParenExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1127,6 +1167,16 @@ impl UnderscoreExpr {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FormatArgsArg {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasName for FormatArgsArg {}
+impl FormatArgsArg {
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct StmtList {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1555,10 +1605,10 @@ pub enum Type {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Expr {
     ArrayExpr(ArrayExpr),
+    AsmExpr(AsmExpr),
     AwaitExpr(AwaitExpr),
     BinExpr(BinExpr),
     BlockExpr(BlockExpr),
-    BoxExpr(BoxExpr),
     BreakExpr(BreakExpr),
     CallExpr(CallExpr),
     CastExpr(CastExpr),
@@ -1566,6 +1616,7 @@ pub enum Expr {
     ContinueExpr(ContinueExpr),
     FieldExpr(FieldExpr),
     ForExpr(ForExpr),
+    FormatArgsExpr(FormatArgsExpr),
     IfExpr(IfExpr),
     IndexExpr(IndexExpr),
     Literal(Literal),
@@ -1573,6 +1624,7 @@ pub enum Expr {
     MacroExpr(MacroExpr),
     MatchExpr(MatchExpr),
     MethodCallExpr(MethodCallExpr),
+    OffsetOfExpr(OffsetOfExpr),
     ParenExpr(ParenExpr),
     PathExpr(PathExpr),
     PrefixExpr(PrefixExpr),
@@ -2453,8 +2505,8 @@ impl AstNode for ArrayExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AwaitExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
+impl AstNode for AsmExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2464,8 +2516,8 @@ impl AstNode for AwaitExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BinExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
+impl AstNode for AwaitExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2475,8 +2527,8 @@ impl AstNode for BinExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for BoxExpr {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_EXPR }
+impl AstNode for BinExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2563,6 +2615,17 @@ impl AstNode for ForExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for FormatArgsExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
+    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 IfExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2640,6 +2703,17 @@ impl AstNode for MethodCallExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for OffsetOfExpr {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
+    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 ParenExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2794,6 +2868,17 @@ impl AstNode for UnderscoreExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for FormatArgsArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
+    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 StmtList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3373,6 +3458,9 @@ impl AstNode for Type {
 impl From<ArrayExpr> for Expr {
     fn from(node: ArrayExpr) -> Expr { Expr::ArrayExpr(node) }
 }
+impl From<AsmExpr> for Expr {
+    fn from(node: AsmExpr) -> Expr { Expr::AsmExpr(node) }
+}
 impl From<AwaitExpr> for Expr {
     fn from(node: AwaitExpr) -> Expr { Expr::AwaitExpr(node) }
 }
@@ -3382,9 +3470,6 @@ impl From<BinExpr> for Expr {
 impl From<BlockExpr> for Expr {
     fn from(node: BlockExpr) -> Expr { Expr::BlockExpr(node) }
 }
-impl From<BoxExpr> for Expr {
-    fn from(node: BoxExpr) -> Expr { Expr::BoxExpr(node) }
-}
 impl From<BreakExpr> for Expr {
     fn from(node: BreakExpr) -> Expr { Expr::BreakExpr(node) }
 }
@@ -3406,6 +3491,9 @@ impl From<FieldExpr> for Expr {
 impl From<ForExpr> for Expr {
     fn from(node: ForExpr) -> Expr { Expr::ForExpr(node) }
 }
+impl From<FormatArgsExpr> for Expr {
+    fn from(node: FormatArgsExpr) -> Expr { Expr::FormatArgsExpr(node) }
+}
 impl From<IfExpr> for Expr {
     fn from(node: IfExpr) -> Expr { Expr::IfExpr(node) }
 }
@@ -3427,6 +3515,9 @@ impl From<MatchExpr> for Expr {
 impl From<MethodCallExpr> for Expr {
     fn from(node: MethodCallExpr) -> Expr { Expr::MethodCallExpr(node) }
 }
+impl From<OffsetOfExpr> for Expr {
+    fn from(node: OffsetOfExpr) -> Expr { Expr::OffsetOfExpr(node) }
+}
 impl From<ParenExpr> for Expr {
     fn from(node: ParenExpr) -> Expr { Expr::ParenExpr(node) }
 }
@@ -3474,10 +3565,10 @@ impl AstNode for Expr {
         matches!(
             kind,
             ARRAY_EXPR
+                | ASM_EXPR
                 | AWAIT_EXPR
                 | BIN_EXPR
                 | BLOCK_EXPR
-                | BOX_EXPR
                 | BREAK_EXPR
                 | CALL_EXPR
                 | CAST_EXPR
@@ -3485,6 +3576,7 @@ impl AstNode for Expr {
                 | CONTINUE_EXPR
                 | FIELD_EXPR
                 | FOR_EXPR
+                | FORMAT_ARGS_EXPR
                 | IF_EXPR
                 | INDEX_EXPR
                 | LITERAL
@@ -3492,6 +3584,7 @@ impl AstNode for Expr {
                 | MACRO_EXPR
                 | MATCH_EXPR
                 | METHOD_CALL_EXPR
+                | OFFSET_OF_EXPR
                 | PAREN_EXPR
                 | PATH_EXPR
                 | PREFIX_EXPR
@@ -3511,10 +3604,10 @@ impl AstNode for Expr {
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             ARRAY_EXPR => Expr::ArrayExpr(ArrayExpr { syntax }),
+            ASM_EXPR => Expr::AsmExpr(AsmExpr { syntax }),
             AWAIT_EXPR => Expr::AwaitExpr(AwaitExpr { syntax }),
             BIN_EXPR => Expr::BinExpr(BinExpr { syntax }),
             BLOCK_EXPR => Expr::BlockExpr(BlockExpr { syntax }),
-            BOX_EXPR => Expr::BoxExpr(BoxExpr { syntax }),
             BREAK_EXPR => Expr::BreakExpr(BreakExpr { syntax }),
             CALL_EXPR => Expr::CallExpr(CallExpr { syntax }),
             CAST_EXPR => Expr::CastExpr(CastExpr { syntax }),
@@ -3522,6 +3615,7 @@ impl AstNode for Expr {
             CONTINUE_EXPR => Expr::ContinueExpr(ContinueExpr { syntax }),
             FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }),
             FOR_EXPR => Expr::ForExpr(ForExpr { syntax }),
+            FORMAT_ARGS_EXPR => Expr::FormatArgsExpr(FormatArgsExpr { syntax }),
             IF_EXPR => Expr::IfExpr(IfExpr { syntax }),
             INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }),
             LITERAL => Expr::Literal(Literal { syntax }),
@@ -3529,6 +3623,7 @@ impl AstNode for Expr {
             MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
             MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
             METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
+            OFFSET_OF_EXPR => Expr::OffsetOfExpr(OffsetOfExpr { syntax }),
             PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
             PATH_EXPR => Expr::PathExpr(PathExpr { syntax }),
             PREFIX_EXPR => Expr::PrefixExpr(PrefixExpr { syntax }),
@@ -3550,10 +3645,10 @@ impl AstNode for Expr {
     fn syntax(&self) -> &SyntaxNode {
         match self {
             Expr::ArrayExpr(it) => &it.syntax,
+            Expr::AsmExpr(it) => &it.syntax,
             Expr::AwaitExpr(it) => &it.syntax,
             Expr::BinExpr(it) => &it.syntax,
             Expr::BlockExpr(it) => &it.syntax,
-            Expr::BoxExpr(it) => &it.syntax,
             Expr::BreakExpr(it) => &it.syntax,
             Expr::CallExpr(it) => &it.syntax,
             Expr::CastExpr(it) => &it.syntax,
@@ -3561,6 +3656,7 @@ impl AstNode for Expr {
             Expr::ContinueExpr(it) => &it.syntax,
             Expr::FieldExpr(it) => &it.syntax,
             Expr::ForExpr(it) => &it.syntax,
+            Expr::FormatArgsExpr(it) => &it.syntax,
             Expr::IfExpr(it) => &it.syntax,
             Expr::IndexExpr(it) => &it.syntax,
             Expr::Literal(it) => &it.syntax,
@@ -3568,6 +3664,7 @@ impl AstNode for Expr {
             Expr::MacroExpr(it) => &it.syntax,
             Expr::MatchExpr(it) => &it.syntax,
             Expr::MethodCallExpr(it) => &it.syntax,
+            Expr::OffsetOfExpr(it) => &it.syntax,
             Expr::ParenExpr(it) => &it.syntax,
             Expr::PathExpr(it) => &it.syntax,
             Expr::PrefixExpr(it) => &it.syntax,
@@ -4028,9 +4125,9 @@ impl AstNode for AnyHasAttrs {
                 | TYPE_PARAM
                 | LET_STMT
                 | ARRAY_EXPR
+                | ASM_EXPR
                 | AWAIT_EXPR
                 | BIN_EXPR
-                | BOX_EXPR
                 | BREAK_EXPR
                 | CALL_EXPR
                 | CAST_EXPR
@@ -4038,12 +4135,14 @@ impl AstNode for AnyHasAttrs {
                 | CONTINUE_EXPR
                 | FIELD_EXPR
                 | FOR_EXPR
+                | FORMAT_ARGS_EXPR
                 | IF_EXPR
                 | INDEX_EXPR
                 | LITERAL
                 | LOOP_EXPR
                 | MATCH_EXPR
                 | METHOD_CALL_EXPR
+                | OFFSET_OF_EXPR
                 | PAREN_EXPR
                 | PATH_EXPR
                 | PREFIX_EXPR
@@ -4179,6 +4278,7 @@ impl AstNode for AnyHasName {
                 | VARIANT
                 | CONST_PARAM
                 | TYPE_PARAM
+                | FORMAT_ARGS_ARG
                 | IDENT_PAT
         )
     }
@@ -4620,17 +4720,17 @@ impl std::fmt::Display for ArrayExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AwaitExpr {
+impl std::fmt::Display for AsmExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BinExpr {
+impl std::fmt::Display for AwaitExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for BoxExpr {
+impl std::fmt::Display for BinExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
@@ -4670,6 +4770,11 @@ impl std::fmt::Display for ForExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for FormatArgsExpr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for IfExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -4705,6 +4810,11 @@ impl std::fmt::Display for MethodCallExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for OffsetOfExpr {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for ParenExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -4775,6 +4885,11 @@ impl std::fmt::Display for UnderscoreExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for FormatArgsArg {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for StmtList {
     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/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
index 4ec388914e6..8e04ab8bedc 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs
@@ -130,7 +130,8 @@ impl Expr {
             //
             ContinueExpr(_) => (0, 0),
 
-            ClosureExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | BreakExpr(_) => (0, 1),
+            ClosureExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | BreakExpr(_)
+            | OffsetOfExpr(_) | FormatArgsExpr(_) | AsmExpr(_) => (0, 1),
 
             RangeExpr(_) => (5, 5),
 
@@ -160,7 +161,7 @@ impl Expr {
 
             CastExpr(_) => (25, 26),
 
-            BoxExpr(_) | RefExpr(_) | LetExpr(_) | PrefixExpr(_) => (0, 27),
+            RefExpr(_) | LetExpr(_) | PrefixExpr(_) => (0, 27),
 
             AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | IndexExpr(_) | TryExpr(_)
             | MacroExpr(_) => (29, 0),
@@ -202,7 +203,6 @@ impl Expr {
             let rhs = match self {
                 RefExpr(e) => e.expr(),
                 BinExpr(e) => e.rhs(),
-                BoxExpr(e) => e.expr(),
                 BreakExpr(e) => e.expr(),
                 LetExpr(e) => e.expr(),
                 RangeExpr(e) => e.end(),
@@ -279,7 +279,6 @@ impl Expr {
                 CastExpr(e) => e.as_token(),
                 FieldExpr(e) => e.dot_token(),
                 AwaitExpr(e) => e.dot_token(),
-                BoxExpr(e) => e.box_token(),
                 BreakExpr(e) => e.break_token(),
                 CallExpr(e) => e.arg_list().and_then(|args| args.l_paren_token()),
                 ClosureExpr(e) => e.param_list().and_then(|params| params.l_paren_token()),
@@ -293,7 +292,9 @@ impl Expr {
                 YieldExpr(e) => e.yield_token(),
                 YeetExpr(e) => e.do_token(),
                 LetExpr(e) => e.let_token(),
-
+                OffsetOfExpr(e) => e.builtin_token(),
+                FormatArgsExpr(e) => e.builtin_token(),
+                AsmExpr(e) => e.builtin_token(),
                 ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_)
                 | IfExpr(_) | WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_)
                 | BlockExpr(_) | RecordExpr(_) | UnderscoreExpr(_) | MacroExpr(_) => None,
@@ -310,12 +311,12 @@ impl Expr {
             ArrayExpr(_) | AwaitExpr(_) | BlockExpr(_) | CallExpr(_) | CastExpr(_)
             | ClosureExpr(_) | FieldExpr(_) | IndexExpr(_) | Literal(_) | LoopExpr(_)
             | MacroExpr(_) | MethodCallExpr(_) | ParenExpr(_) | PathExpr(_) | RecordExpr(_)
-            | TryExpr(_) | TupleExpr(_) | UnderscoreExpr(_) => false,
+            | TryExpr(_) | TupleExpr(_) | UnderscoreExpr(_) | OffsetOfExpr(_)
+            | FormatArgsExpr(_) | AsmExpr(_) => false,
 
             // For BinExpr and RangeExpr this is technically wrong -- the child can be on the left...
-            BinExpr(_) | RangeExpr(_) | BoxExpr(_) | BreakExpr(_) | ContinueExpr(_)
-            | PrefixExpr(_) | RefExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_)
-            | LetExpr(_) => self
+            BinExpr(_) | RangeExpr(_) | BreakExpr(_) | ContinueExpr(_) | PrefixExpr(_)
+            | RefExpr(_) | ReturnExpr(_) | YieldExpr(_) | YeetExpr(_) | LetExpr(_) => self
                 .syntax()
                 .parent()
                 .and_then(Expr::cast)
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 e4db33f1c69..341bda892ba 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
@@ -70,7 +70,19 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
         "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct",
         "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", "yield",
     ],
-    contextual_keywords: &["auto", "default", "existential", "union", "raw", "macro_rules", "yeet"],
+    contextual_keywords: &[
+        "auto",
+        "builtin",
+        "default",
+        "existential",
+        "union",
+        "raw",
+        "macro_rules",
+        "yeet",
+        "offset_of",
+        "asm",
+        "format_args",
+    ],
     literals: &["INT_NUMBER", "FLOAT_NUMBER", "CHAR", "BYTE", "STRING", "BYTE_STRING", "C_STRING"],
     tokens: &["ERROR", "IDENT", "WHITESPACE", "LIFETIME_IDENT", "COMMENT", "SHEBANG"],
     nodes: &[
@@ -154,7 +166,10 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
         "RECORD_EXPR",
         "RECORD_EXPR_FIELD_LIST",
         "RECORD_EXPR_FIELD",
-        "BOX_EXPR",
+        "OFFSET_OF_EXPR",
+        "ASM_EXPR",
+        "FORMAT_ARGS_EXPR",
+        "FORMAT_ARGS_ARG",
         // postfix
         "CALL_EXPR",
         "INDEX_EXPR",
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
index c49c5fa108b..56227fce9b5 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
@@ -623,7 +623,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
 }
 
 fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
-    if lower_comma_list(acc, grammar, label, rule) {
+    if lower_seperated_list(acc, grammar, label, rule) {
         return;
     }
 
@@ -689,7 +689,7 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
 }
 
 // (T (',' T)* ','?)
-fn lower_comma_list(
+fn lower_seperated_list(
     acc: &mut Vec<Field>,
     grammar: &Grammar,
     label: Option<&String>,
@@ -699,19 +699,23 @@ fn lower_comma_list(
         Rule::Seq(it) => it,
         _ => return false,
     };
-    let (node, repeat, trailing_comma) = match rule.as_slice() {
-        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
-            (node, repeat, trailing_comma)
+    let (node, repeat, trailing_sep) = match rule.as_slice() {
+        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
+            (node, repeat, Some(trailing_sep))
         }
+        [Rule::Node(node), Rule::Rep(repeat)] => (node, repeat, None),
         _ => return false,
     };
     let repeat = match &**repeat {
         Rule::Seq(it) => it,
         _ => return false,
     };
-    match repeat.as_slice() {
-        [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
-        _ => return false,
+    if !matches!(
+        repeat.as_slice(),
+        [comma, Rule::Node(n)]
+            if trailing_sep.map_or(true, |it| comma == &**it) && n == node
+    ) {
+        return false;
     }
     let ty = grammar[*node].name.clone();
     let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index c765f42447a..573f56b003a 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -899,32 +899,90 @@ pub mod fmt {
         fn fmt(&self, f: &mut Formatter<'_>) -> Result;
     }
 
-    extern "C" {
-        type Opaque;
-    }
+    mod rt {
 
-    #[lang = "format_argument"]
-    pub struct Argument<'a> {
-        value: &'a Opaque,
-        formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
-    }
+        extern "C" {
+            type Opaque;
+        }
+
+        #[lang = "format_argument"]
+        pub struct Argument<'a> {
+            value: &'a Opaque,
+            formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
+        }
+
+        impl<'a> Argument<'a> {
+            pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
+                use crate::mem::transmute;
+                unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
+            }
+        }
+
+        #[lang = "format_alignment"]
+        pub enum Alignment {
+            Left,
+            Right,
+            Center,
+            Unknown,
+        }
+
+        #[lang = "format_count"]
+        pub enum Count {
+            Is(usize),
+            Param(usize),
+            Implied,
+        }
+
+        #[lang = "format_placeholder"]
+        pub struct Placeholder {
+            pub position: usize,
+            pub fill: char,
+            pub align: Alignment,
+            pub flags: u32,
+            pub precision: Count,
+            pub width: Count,
+        }
+
+        impl Placeholder {
+            pub const fn new(
+                position: usize,
+                fill: char,
+                align: Alignment,
+                flags: u32,
+                precision: Count,
+                width: Count,
+            ) -> Self;
+        }
+
+        #[lang = "format_unsafe_arg"]
+        pub struct UnsafeArg {
+            _private: (),
+        }
 
-    impl<'a> Argument<'a> {
-        pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
-            use crate::mem::transmute;
-            unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
+        impl UnsafeArg {
+            pub unsafe fn new() -> Self;
         }
     }
 
     #[lang = "format_arguments"]
     pub struct Arguments<'a> {
         pieces: &'a [&'static str],
-        args: &'a [Argument<'a>],
+        fmt: Option<&'a [rt::Placeholder]>,
+        args: &'a [rt::Argument<'a>],
     }
 
     impl<'a> Arguments<'a> {
         pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> {
-            Arguments { pieces, args }
+            Arguments { pieces, fmt: None, args }
+        }
+
+        pub fn new_v1_formatted(
+            pieces: &'a [&'static str],
+            args: &'a [rt::Argument<'a>],
+            fmt: &'a [rt::Placeholder],
+            _unsafe_arg: rt::UnsafeArg,
+        ) -> Arguments<'a> {
+            Arguments { pieces, fmt: Some(fmt), args }
         }
     }
 
@@ -1294,8 +1352,6 @@ mod macros {
             /* compiler built-in */
         };
     }
-
-    pub(crate) use panic;
     // endregion:panic
 
     // region:fmt
@@ -1306,7 +1362,20 @@ mod macros {
         ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
     }
 
-    pub(crate) use const_format_args;
+    #[macro_export]
+    #[rustc_builtin_macro]
+    macro_rules! format_args {
+        ($fmt:expr) => {{ /* compiler built-in */ }};
+        ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
+    }
+
+    #[macro_export]
+    macro_rules! print {
+        ($($arg:tt)*) => {{
+            $crate::io::_print($crate::format_args!($($arg)*));
+        }};
+    }
+
     // endregion:fmt
 
     // region:derive
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
index 95c5142517a..11055f0280a 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
@@ -16,7 +16,7 @@ tracing = "0.1.35"
 walkdir = "2.3.2"
 crossbeam-channel = "0.5.5"
 # We demand 5.1.0 as any higher version pulls in a new windows-sys dupe
-notify = "=5.1.0"
+notify = "6.1.1"
 
 stdx.workspace = true
 vfs.workspace = true
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index fe3dfe61968..06004adad34 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -184,6 +184,11 @@ impl Vfs {
         mem::take(&mut self.changes)
     }
 
+    /// Provides a panic-less way to verify file_id validity.
+    pub fn exists(&self, file_id: FileId) -> bool {
+        self.get(file_id).is_some()
+    }
+
     /// Returns the id associated with `path`
     ///
     /// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a
diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md
index 895de5798ac..b7d585cafb3 100644
--- a/src/tools/rust-analyzer/docs/dev/architecture.md
+++ b/src/tools/rust-analyzer/docs/dev/architecture.md
@@ -268,7 +268,7 @@ They are independent from the rest of the code.
 And it also handles the actual parsing and expansion of declarative macro (a-la "Macros By Example" or mbe).
 
 For proc macros, the client-server model are used.
-We pass an argument `--proc-macro` to `rust-analyzer` binary to start a separate process  (`proc_macro_srv`).
+We start a separate process  (`proc_macro_srv`) which loads and runs the proc-macros for us.
 And the client (`proc_macro_api`) provides an interface to talk to that server separately.
 
 And then token trees are passed from client, and the server will load the corresponding dynamic library (which built by `cargo`).
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index 024acb87709..0801e988f5c 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: 149a5be3c5e469d1
+lsp/ext.rs hash: 121482ee911854da
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -322,7 +322,7 @@ Position[]
 
 ```rust
 fn main() {
-    let x: Vec<()>/*cursor here*/ = vec![]
+    let x: Vec<()>/*cursor here*/ = vec![];
 }
 ```
 
@@ -362,7 +362,7 @@ interface RunnablesParams {
 ```typescript
 interface Runnable {
     label: string;
-    /// If this Runnable is associated with a specific function/module, etc, the location of this item
+    /// If this Runnable is associated with a specific function/module, etc., the location of this item
     location?: LocationLink;
     /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities,
     // the type of `args` is specific to `kind`. The actual running is handled by the client.
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 44f1b81675a..233e7bf44b1 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -471,16 +471,13 @@
                     "default": false,
                     "type": "boolean"
                 },
-                "rust-analyzer.discoverProjectCommand": {
-                    "markdownDescription": "Sets the command that rust-analyzer uses to generate `rust-project.json` files. This command should only be used\n if a build system like Buck or Bazel is also in use. The command must accept files as arguments and return \n a rust-project.json over stdout.",
+                "rust-analyzer.discoverProjectRunner": {
+                    "markdownDescription": "Sets the extension responsible for determining which extension the rust-analyzer extension uses to generate `rust-project.json` files. This should should only be used\n if a build system like Buck or Bazel is also in use.",
                     "default": null,
                     "type": [
                         "null",
-                        "array"
-                    ],
-                    "items": {
-                        "type": "string"
-                    }
+                        "string"
+                    ]
                 },
                 "rust-analyzer.showUnlinkedFileNotification": {
                     "markdownDescription": "Whether to show a notification for unlinked files asking the user to add the corresponding Cargo.toml to the linked projects setting.",
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index aba37bac27d..245557b1e88 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient";
 import * as ra from "./lsp_ext";
 import * as path from "path";
 
-import { type Ctx, type Cmd, type CtxInit, discoverWorkspace } from "./ctx";
+import type { Ctx, Cmd, CtxInit } from "./ctx";
 import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
 import { spawnSync } from "child_process";
 import { type RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
@@ -871,22 +871,16 @@ export function rebuildProcMacros(ctx: CtxInit): Cmd {
 
 export function addProject(ctx: CtxInit): Cmd {
     return async () => {
-        const discoverProjectCommand = ctx.config.discoverProjectCommand;
-        if (!discoverProjectCommand) {
+        const extensionName = ctx.config.discoverProjectRunner;
+        // this command shouldn't be enabled in the first place if this isn't set.
+        if (!extensionName) {
             return;
         }
 
-        const workspaces: JsonProject[] = await Promise.all(
-            vscode.workspace.textDocuments
-                .filter(isRustDocument)
-                .map(async (file): Promise<JsonProject> => {
-                    return discoverWorkspace([file], discoverProjectCommand, {
-                        cwd: path.dirname(file.uri.fsPath),
-                    });
-                }),
-        );
+        const command = `${extensionName}.discoverWorkspaceCommand`;
+        const project: JsonProject = await vscode.commands.executeCommand(command);
 
-        ctx.addToDiscoveredWorkspaces(workspaces);
+        ctx.addToDiscoveredWorkspaces([project]);
 
         // this is a workaround to avoid needing writing the `rust-project.json` into
         // a workspace-level VS Code-specific settings folder. We'd like to keep the
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 39e2f767c76..9821aee6f92 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -253,8 +253,8 @@ export class Config {
         return this.get<boolean>("trace.extension");
     }
 
-    get discoverProjectCommand() {
-        return this.get<string[] | undefined>("discoverProjectCommand");
+    get discoverProjectRunner(): string | undefined {
+        return this.get<string | undefined>("discoverProjectRunner");
     }
 
     get problemMatcher(): string[] {
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 363a7a82e68..904efa4d5eb 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -1,12 +1,10 @@
 import * as vscode from "vscode";
 import type * as lc from "vscode-languageclient/node";
 import * as ra from "./lsp_ext";
-import * as path from "path";
 
 import { Config, prepareVSCodeConfig } from "./config";
 import { createClient } from "./client";
 import {
-    executeDiscoverProject,
     isDocumentInWorkspace,
     isRustDocument,
     isRustEditor,
@@ -24,7 +22,6 @@ import {
 import { execRevealDependency } from "./commands";
 import { PersistentState } from "./persistent_state";
 import { bootstrap } from "./bootstrap";
-import type { ExecOptions } from "child_process";
 
 // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
 // only those are in use. We use "Empty" to represent these scenarios
@@ -58,17 +55,6 @@ export function fetchWorkspace(): Workspace {
         : { kind: "Workspace Folder" };
 }
 
-export async function discoverWorkspace(
-    files: readonly vscode.TextDocument[],
-    command: string[],
-    options: ExecOptions,
-): Promise<JsonProject> {
-    const paths = files.map((f) => `"${f.uri.fsPath}"`).join(" ");
-    const joinedCommand = command.join(" ");
-    const data = await executeDiscoverProject(`${joinedCommand} ${paths}`, options);
-    return JSON.parse(data) as JsonProject;
-}
-
 export type CommandFactory = {
     enabled: (ctx: CtxInit) => Cmd;
     disabled?: (ctx: Ctx) => Cmd;
@@ -200,6 +186,12 @@ export class Ctx {
             };
 
             let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
+            if (this.config.discoverProjectRunner) {
+                const command = `${this.config.discoverProjectRunner}.discoverWorkspaceCommand`;
+                log.info(`running command: ${command}`);
+                const project: JsonProject = await vscode.commands.executeCommand(command);
+                this.addToDiscoveredWorkspaces([project]);
+            }
 
             if (this.workspace.kind === "Detached Files") {
                 rawInitializationOptions = {
@@ -208,21 +200,6 @@ export class Ctx {
                 };
             }
 
-            const discoverProjectCommand = this.config.discoverProjectCommand;
-            if (discoverProjectCommand) {
-                const workspaces: JsonProject[] = await Promise.all(
-                    vscode.workspace.textDocuments
-                        .filter(isRustDocument)
-                        .map(async (file): Promise<JsonProject> => {
-                            return discoverWorkspace([file], discoverProjectCommand, {
-                                cwd: path.dirname(file.uri.fsPath),
-                            });
-                        }),
-                );
-
-                this.addToDiscoveredWorkspaces(workspaces);
-            }
-
             const initializationOptions = prepareVSCodeConfig(
                 rawInitializationOptions,
                 (key, obj) => {
diff --git a/src/tools/rust-analyzer/editors/code/src/util.ts b/src/tools/rust-analyzer/editors/code/src/util.ts
index 0414ea0f806..51f921a2962 100644
--- a/src/tools/rust-analyzer/editors/code/src/util.ts
+++ b/src/tools/rust-analyzer/editors/code/src/util.ts
@@ -154,22 +154,6 @@ export function execute(command: string, options: ExecOptions): Promise<string>
     });
 }
 
-export function executeDiscoverProject(command: string, options: ExecOptions): Promise<string> {
-    options = Object.assign({ maxBuffer: 10 * 1024 * 1024 }, options);
-    log.info(`running command: ${command}`);
-    return new Promise((resolve, reject) => {
-        exec(command, options, (err, stdout, _) => {
-            if (err) {
-                log.error(err);
-                reject(err);
-                return;
-            }
-
-            resolve(stdout.trimEnd());
-        });
-    });
-}
-
 export class LazyOutputChannel implements vscode.OutputChannel {
     constructor(name: string) {
         this.name = name;
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index e1c49db39d5..7ec3247e943 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "lsp-server"
-version = "0.7.3"
+version = "0.7.4"
 description = "Generic LSP server scaffold."
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-server"
@@ -9,8 +9,7 @@ edition = "2021"
 [dependencies]
 log = "0.4.17"
 serde_json = "1.0.96"
-# See https://github.com/serde-rs/serde/issues/2538#issuecomment-1684517372 for why we pin serde
-serde = { version = "1.0.156, < 1.0.172", features = ["derive"] }
+serde = { version = "1.0.156", features = ["derive"] }
 crossbeam-channel = "0.5.6"
 
 [dev-dependencies]
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 7720ad69fe0..e52cbfca3e6 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -114,6 +114,7 @@ pub enum MeasurementType {
     AnalyzeRipgrep,
     AnalyzeWebRender,
     AnalyzeDiesel,
+    AnalyzeHyper,
 }
 
 impl FromStr for MeasurementType {
@@ -122,13 +123,26 @@ impl FromStr for MeasurementType {
         match s {
             "build" => Ok(Self::Build),
             "self" => Ok(Self::AnalyzeSelf),
-            "ripgrep" => Ok(Self::AnalyzeRipgrep),
-            "webrender" => Ok(Self::AnalyzeWebRender),
-            "diesel" => Ok(Self::AnalyzeDiesel),
+            "ripgrep-13.0.0" => Ok(Self::AnalyzeRipgrep),
+            "webrender-2022" => Ok(Self::AnalyzeWebRender),
+            "diesel-1.4.8" => Ok(Self::AnalyzeDiesel),
+            "hyper-0.14.18" => Ok(Self::AnalyzeHyper),
             _ => Err("Invalid option".to_string()),
         }
     }
 }
+impl AsRef<str> for MeasurementType {
+    fn as_ref(&self) -> &str {
+        match self {
+            Self::Build => "build",
+            Self::AnalyzeSelf => "self",
+            Self::AnalyzeRipgrep => "ripgrep-13.0.0",
+            Self::AnalyzeWebRender => "webrender-2022",
+            Self::AnalyzeDiesel => "diesel-1.4.8",
+            Self::AnalyzeHyper => "hyper-0.14.18",
+        }
+    }
+}
 
 #[derive(Debug)]
 pub struct Metrics {
diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs
index e4710260409..59d41d8e4b8 100644
--- a/src/tools/rust-analyzer/xtask/src/metrics.rs
+++ b/src/tools/rust-analyzer/xtask/src/metrics.rs
@@ -29,46 +29,38 @@ impl flags::Metrics {
 
         let _env = sh.push_env("RA_METRICS", "1");
 
-        let filename = match self.measurement_type {
-            Some(ms) => match ms {
-                MeasurementType::Build => {
-                    metrics.measure_build(sh)?;
-                    "build.json"
-                }
-                MeasurementType::AnalyzeSelf => {
-                    metrics.measure_analysis_stats_self(sh)?;
-                    "self.json"
-                }
-                MeasurementType::AnalyzeRipgrep => {
-                    metrics.measure_analysis_stats(sh, "ripgrep")?;
-                    "ripgrep.json"
-                }
-                MeasurementType::AnalyzeWebRender => {
-                    {
-                        // https://github.com/rust-lang/rust-analyzer/issues/9997
-                        let _d = sh.push_dir("target/rustc-perf/collector/benchmarks/webrender");
-                        cmd!(sh, "cargo update -p url --precise 1.6.1").run()?;
+        let name = match &self.measurement_type {
+            Some(ms) => {
+                let name = ms.as_ref();
+                match ms {
+                    MeasurementType::Build => {
+                        metrics.measure_build(sh)?;
                     }
-                    metrics.measure_analysis_stats(sh, "webrender")?;
-                    "webrender.json"
-                }
-                MeasurementType::AnalyzeDiesel => {
-                    metrics.measure_analysis_stats(sh, "diesel/diesel")?;
-                    "diesel.json"
-                }
-            },
+                    MeasurementType::AnalyzeSelf => {
+                        metrics.measure_analysis_stats_self(sh)?;
+                    }
+                    MeasurementType::AnalyzeRipgrep
+                    | MeasurementType::AnalyzeWebRender
+                    | MeasurementType::AnalyzeDiesel
+                    | MeasurementType::AnalyzeHyper => {
+                        metrics.measure_analysis_stats(sh, name)?;
+                    }
+                };
+                name
+            }
             None => {
                 metrics.measure_build(sh)?;
                 metrics.measure_analysis_stats_self(sh)?;
-                metrics.measure_analysis_stats(sh, "ripgrep")?;
-                metrics.measure_analysis_stats(sh, "webrender")?;
-                metrics.measure_analysis_stats(sh, "diesel/diesel")?;
-                "all.json"
+                metrics.measure_analysis_stats(sh, MeasurementType::AnalyzeRipgrep.as_ref())?;
+                metrics.measure_analysis_stats(sh, MeasurementType::AnalyzeWebRender.as_ref())?;
+                metrics.measure_analysis_stats(sh, MeasurementType::AnalyzeDiesel.as_ref())?;
+                metrics.measure_analysis_stats(sh, MeasurementType::AnalyzeHyper.as_ref())?;
+                "all"
             }
         };
 
         let mut file =
-            fs::File::options().write(true).create(true).open(format!("target/{}", filename))?;
+            fs::File::options().write(true).create(true).open(format!("target/{}.json", name))?;
         writeln!(file, "{}", metrics.json())?;
         eprintln!("{metrics:#?}");
         Ok(())
@@ -93,7 +85,7 @@ impl Metrics {
         self.measure_analysis_stats_path(
             sh,
             bench,
-            &format!("./target/rustc-perf/collector/benchmarks/{bench}"),
+            &format!("./target/rustc-perf/collector/compile-benchmarks/{bench}"),
         )
     }
     fn measure_analysis_stats_path(
@@ -102,6 +94,7 @@ impl Metrics {
         name: &str,
         path: &str,
     ) -> anyhow::Result<()> {
+        assert!(Path::new(path).exists(), "unable to find bench in {path}");
         eprintln!("\nMeasuring analysis-stats/{name}");
         let output = cmd!(sh, "./target/release/rust-analyzer -q analysis-stats {path}").read()?;
         for (metric, value, unit) in parse_metrics(&output) {
@@ -145,7 +138,7 @@ impl Metrics {
         let host = Host::new(sh)?;
         let timestamp = SystemTime::now();
         let revision = cmd!(sh, "git rev-parse HEAD").read()?;
-        let perf_revision = "c52ee623e231e7690a93be88d943016968c1036b".into();
+        let perf_revision = "a584462e145a0c04760fd9391daefb4f6bd13a99".into();
         Ok(Metrics { host, timestamp, revision, perf_revision, metrics: BTreeMap::new() })
     }
 
diff --git a/src/tools/rustdoc-themes/main.rs b/src/tools/rustdoc-themes/main.rs
index 7cac985a9a3..cc13df1f5ba 100644
--- a/src/tools/rustdoc-themes/main.rs
+++ b/src/tools/rustdoc-themes/main.rs
@@ -1,25 +1,37 @@
 use std::env::args;
-use std::fs::read_dir;
+use std::fs::File;
+use std::io::{BufRead, BufReader, BufWriter, Write};
 use std::path::Path;
 use std::process::{exit, Command};
 
-const FILES_TO_IGNORE: &[&str] = &["light.css"];
-
-fn get_folders<P: AsRef<Path>>(folder_path: P) -> Vec<String> {
+fn get_themes<P: AsRef<Path>>(style_path: P) -> Vec<String> {
     let mut ret = Vec::with_capacity(10);
 
-    for entry in read_dir(folder_path.as_ref()).expect("read_dir failed") {
-        let entry = entry.expect("Couldn't unwrap entry");
-        let path = entry.path();
+    const BEGIN_THEME_MARKER: &'static str = "/* Begin theme: ";
+    const END_THEME_MARKER: &'static str = "/* End theme: ";
+
+    let timestamp =
+        std::time::SystemTime::UNIX_EPOCH.elapsed().expect("time is after UNIX epoch").as_millis();
 
-        if !path.is_file() {
-            continue;
+    let mut in_theme = None;
+    for line in BufReader::new(File::open(style_path).expect("read rustdoc.css failed")).lines() {
+        let line = line.expect("read line from rustdoc.css failed");
+        let line = line.trim();
+        if line.starts_with(BEGIN_THEME_MARKER) {
+            let theme_name = &line[BEGIN_THEME_MARKER.len()..].trim().trim_end_matches("*/").trim();
+            let filename = format!("build/tmp/rustdoc.bootstrap.{timestamp}.{theme_name}.css");
+            in_theme = Some(BufWriter::new(
+                File::create(&filename).expect("failed to create temporary test css file"),
+            ));
+            ret.push(filename);
+        }
+        if let Some(in_theme) = in_theme.as_mut() {
+            in_theme.write_all(line.as_bytes()).expect("write to temporary test css file");
+            in_theme.write_all(b"\n").expect("write to temporary test css file");
         }
-        let filename = path.file_name().expect("file_name failed");
-        if FILES_TO_IGNORE.iter().any(|x| x == &filename) {
-            continue;
+        if line.starts_with(END_THEME_MARKER) {
+            in_theme = None;
         }
-        ret.push(format!("{}", path.display()));
     }
     ret
 }
@@ -32,10 +44,10 @@ fn main() {
         exit(1);
     }
     let rustdoc_bin = &argv[1];
-    let themes_folder = &argv[2];
-    let themes = get_folders(&themes_folder);
+    let style_path = &argv[2];
+    let themes = get_themes(&style_path);
     if themes.is_empty() {
-        eprintln!("No theme found in \"{}\"...", themes_folder);
+        eprintln!("No themes found in \"{}\"...", style_path);
         exit(1);
     }
     let arg_name = "--check-theme".to_owned();
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 9b19b8eecc7..fc69c143222 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -63,7 +63,7 @@ pub mod features;
 pub mod fluent_alphabetical;
 pub mod mir_opt_tests;
 pub mod pal;
-pub mod primitive_docs;
+pub mod rustdoc_css_themes;
 pub mod rustdoc_gui_tests;
 pub mod style;
 pub mod target_specific_tests;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 5fa91715a07..80e58ba00fc 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -104,6 +104,7 @@ fn main() {
         check!(ui_tests, &tests_path);
         check!(mir_opt_tests, &tests_path, bless);
         check!(rustdoc_gui_tests, &tests_path);
+        check!(rustdoc_css_themes, &librustdoc_path);
 
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
@@ -111,7 +112,6 @@ fn main() {
 
         // Checks that only make sense for the std libs.
         check!(pal, &library_path);
-        check!(primitive_docs, &library_path);
 
         // Checks that need to be done for both the compiler and std libraries.
         check!(unit_tests, &src_path);
diff --git a/src/tools/tidy/src/primitive_docs.rs b/src/tools/tidy/src/primitive_docs.rs
deleted file mode 100644
index f3200e0afd7..00000000000
--- a/src/tools/tidy/src/primitive_docs.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//! Tidy check to make sure `library/{std,core}/src/primitive_docs.rs` are the same file.  These are
-//! different files so that relative links work properly without having to have `CARGO_PKG_NAME`
-//! set, but conceptually they should always be the same.
-
-use std::path::Path;
-
-pub fn check(library_path: &Path, bad: &mut bool) {
-    let std_name = "std/src/primitive_docs.rs";
-    let core_name = "core/src/primitive_docs.rs";
-    let std_contents = std::fs::read_to_string(library_path.join(std_name))
-        .unwrap_or_else(|e| panic!("failed to read library/{std_name}: {e}"));
-    let core_contents = std::fs::read_to_string(library_path.join(core_name))
-        .unwrap_or_else(|e| panic!("failed to read library/{core_name}: {e}"));
-    if std_contents != core_contents {
-        tidy_error!(bad, "library/{core_name} and library/{std_name} have different contents");
-    }
-}
diff --git a/src/tools/tidy/src/rustdoc_css_themes.rs b/src/tools/tidy/src/rustdoc_css_themes.rs
new file mode 100644
index 00000000000..852d6e14e91
--- /dev/null
+++ b/src/tools/tidy/src/rustdoc_css_themes.rs
@@ -0,0 +1,99 @@
+//! Tidy check to make sure light and dark themes are synchronized between
+//! JS-controlled rustdoc.css and noscript.css
+
+use std::path::Path;
+
+pub fn check(librustdoc_path: &Path, bad: &mut bool) {
+    let rustdoc_css = "html/static/css/rustdoc.css";
+    let noscript_css = "html/static/css/noscript.css";
+    let rustdoc_css_contents = std::fs::read_to_string(librustdoc_path.join(rustdoc_css))
+        .unwrap_or_else(|e| panic!("failed to read librustdoc/{rustdoc_css}: {e}"));
+    let noscript_css_contents = std::fs::read_to_string(librustdoc_path.join(noscript_css))
+        .unwrap_or_else(|e| panic!("failed to read librustdoc/{noscript_css}: {e}"));
+    compare_themes_from_files(
+        "light",
+        rustdoc_css_contents.lines().enumerate().map(|(i, l)| (i + 1, l.trim())),
+        noscript_css_contents.lines().enumerate().map(|(i, l)| (i + 1, l.trim())),
+        bad,
+    );
+    compare_themes_from_files(
+        "dark",
+        rustdoc_css_contents.lines().enumerate(),
+        noscript_css_contents.lines().enumerate(),
+        bad,
+    );
+}
+
+fn compare_themes_from_files<'a>(
+    name: &str,
+    mut rustdoc_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    mut noscript_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    bad: &mut bool,
+) {
+    let begin_theme_pat = format!("/* Begin theme: {name}");
+    let mut found_theme = None;
+    let mut found_theme_noscript = None;
+    while let Some((rustdoc_css_line_number, rustdoc_css_line)) = rustdoc_css_lines.next() {
+        if !rustdoc_css_line.starts_with(&begin_theme_pat) {
+            continue;
+        }
+        if let Some(found_theme) = found_theme {
+            tidy_error!(
+                bad,
+                "rustdoc.css contains two {name} themes on lines {rustdoc_css_line_number} and {found_theme}",
+            );
+            return;
+        }
+        found_theme = Some(rustdoc_css_line_number);
+        while let Some((noscript_css_line_number, noscript_css_line)) = noscript_css_lines.next() {
+            if !noscript_css_line.starts_with(&begin_theme_pat) {
+                continue;
+            }
+            if let Some(found_theme_noscript) = found_theme_noscript {
+                tidy_error!(
+                    bad,
+                    "noscript.css contains two {name} themes on lines {noscript_css_line_number} and {found_theme_noscript}",
+                );
+                return;
+            }
+            found_theme_noscript = Some(noscript_css_line_number);
+            compare_themes(name, &mut rustdoc_css_lines, &mut noscript_css_lines, bad);
+        }
+    }
+}
+
+fn compare_themes<'a>(
+    name: &str,
+    rustdoc_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    noscript_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    bad: &mut bool,
+) {
+    let end_theme_pat = format!("/* End theme: {name}");
+    for (
+        (rustdoc_css_line_number, rustdoc_css_line),
+        (noscript_css_line_number, noscript_css_line),
+    ) in rustdoc_css_lines.zip(noscript_css_lines)
+    {
+        if noscript_css_line.starts_with(":root {")
+            && rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#))
+        {
+            // selectors are different between rustdoc.css and noscript.css
+            // that's why they both exist: one uses JS, the other uses media queries
+            continue;
+        }
+        if noscript_css_line.starts_with(&end_theme_pat)
+            && rustdoc_css_line.starts_with(&end_theme_pat)
+        {
+            break;
+        }
+        if rustdoc_css_line != noscript_css_line {
+            tidy_error!(
+                bad,
+                "noscript.css:{noscript_css_line_number} and rustdoc.css:{rustdoc_css_line_number} contain copies of {name} theme that are not the same",
+            );
+            eprintln!("- {noscript_css_line}");
+            eprintln!("+ {rustdoc_css_line}");
+            return;
+        }
+    }
+}
diff --git a/tests/coverage-map/status-quo/closure.cov-map b/tests/coverage-map/status-quo/closure.cov-map
index f3a32f091a9..7dbf6ec834d 100644
--- a/tests/coverage-map/status-quo/closure.cov-map
+++ b/tests/coverage-map/status-quo/closure.cov-map
@@ -1,5 +1,5 @@
 Function name: closure::main
-Raw bytes (170): 0x[01, 01, 17, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 05, 05, 5a, 01, 05, 18, 01, 08, 01, 0f, 0d, 03, 16, 0e, 06, 0a, 07, 10, 05, 13, 0d, 0b, 1a, 0e, 08, 09, 0f, 10, 05, 0e, 09, 13, 16, 05, 0d, 18, 17, 19, 09, 01, 21, 1b, 04, 09, 00, 29, 1f, 01, 09, 00, 2d, 23, 01, 09, 00, 24, 27, 05, 09, 00, 24, 2b, 02, 09, 00, 21, 2f, 04, 09, 00, 21, 33, 04, 09, 00, 28, 37, 09, 09, 00, 32, 3b, 04, 09, 00, 33, 3f, 07, 09, 00, 4b, 43, 08, 09, 01, 09, 47, 0a, 09, 01, 09, 4b, 08, 09, 01, 09, 4f, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 5a, 04, 06, 00, 07, 57, 01, 05, 03, 02]
+Raw bytes (170): 0x[01, 01, 17, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 00, 01, 05, 05, 5a, 01, 05, 18, 01, 08, 01, 0f, 0d, 03, 16, 0e, 06, 0a, 07, 10, 05, 13, 0d, 0b, 1a, 0e, 06, 0a, 0f, 10, 05, 0c, 16, 13, 16, 05, 0d, 18, 17, 19, 09, 01, 1e, 1b, 04, 09, 00, 29, 1f, 01, 09, 00, 2d, 23, 01, 09, 00, 24, 27, 05, 09, 00, 24, 2b, 02, 09, 00, 21, 2f, 04, 09, 00, 21, 33, 04, 09, 00, 28, 37, 09, 09, 00, 32, 3b, 04, 09, 00, 33, 3f, 07, 09, 00, 4b, 43, 08, 09, 00, 48, 47, 0a, 09, 00, 47, 4b, 08, 09, 00, 44, 4f, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 5a, 04, 06, 00, 07, 57, 01, 05, 03, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 23
@@ -32,13 +32,13 @@ Number of file 0 mappings: 24
     = (c0 + Zero)
 - Code(Expression(1, Add)) at (prev + 16, 5) to (start + 19, 13)
     = (c0 + Zero)
-- Code(Expression(2, Add)) at (prev + 26, 14) to (start + 8, 9)
+- Code(Expression(2, Add)) at (prev + 26, 14) to (start + 6, 10)
     = (c0 + Zero)
-- Code(Expression(3, Add)) at (prev + 16, 5) to (start + 14, 9)
+- Code(Expression(3, Add)) at (prev + 16, 5) to (start + 12, 22)
     = (c0 + Zero)
 - Code(Expression(4, Add)) at (prev + 22, 5) to (start + 13, 24)
     = (c0 + Zero)
-- Code(Expression(5, Add)) at (prev + 25, 9) to (start + 1, 33)
+- Code(Expression(5, Add)) at (prev + 25, 9) to (start + 1, 30)
     = (c0 + Zero)
 - Code(Expression(6, Add)) at (prev + 4, 9) to (start + 0, 41)
     = (c0 + Zero)
@@ -60,11 +60,11 @@ Number of file 0 mappings: 24
     = (c0 + Zero)
 - Code(Expression(15, Add)) at (prev + 7, 9) to (start + 0, 75)
     = (c0 + Zero)
-- Code(Expression(16, Add)) at (prev + 8, 9) to (start + 1, 9)
+- Code(Expression(16, Add)) at (prev + 8, 9) to (start + 0, 72)
     = (c0 + Zero)
-- Code(Expression(17, Add)) at (prev + 10, 9) to (start + 1, 9)
+- Code(Expression(17, Add)) at (prev + 10, 9) to (start + 0, 71)
     = (c0 + Zero)
-- Code(Expression(18, Add)) at (prev + 8, 9) to (start + 1, 9)
+- Code(Expression(18, Add)) at (prev + 8, 9) to (start + 0, 68)
     = (c0 + Zero)
 - Code(Expression(19, Add)) at (prev + 10, 8) to (start + 0, 16)
     = (c0 + Zero)
diff --git a/tests/coverage-map/status-quo/closure_bug.cov-map b/tests/coverage-map/status-quo/closure_bug.cov-map
new file mode 100644
index 00000000000..4fe2e5ad243
--- /dev/null
+++ b/tests/coverage-map/status-quo/closure_bug.cov-map
@@ -0,0 +1,148 @@
+Function name: closure_bug::main
+Raw bytes (241): 0x[01, 01, 34, 01, 00, 01, 05, 05, ce, 01, 01, 05, cb, 01, 00, 05, ce, 01, 01, 05, cb, 01, 09, 05, ce, 01, 01, 05, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, c3, 01, 00, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, c3, 01, 0d, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, 0d, be, 01, c3, 01, 0d, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, bb, 01, 00, 0d, be, 01, c3, 01, 0d, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, bb, 01, 11, 0d, be, 01, c3, 01, 0d, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, 11, b6, 01, bb, 01, 11, 0d, be, 01, c3, 01, 0d, 09, c6, 01, cb, 01, 09, 05, ce, 01, 01, 05, 11, 01, 06, 01, 03, 0a, 03, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, ce, 01, 00, 17, 00, 18, cb, 01, 02, 09, 00, 0a, 13, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, c6, 01, 00, 17, 00, 18, c3, 01, 02, 09, 00, 0a, 3b, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, be, 01, 00, 17, 00, 18, bb, 01, 02, 09, 00, 0a, 7b, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, b6, 01, 00, 17, 00, 18, b3, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 52
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 4 operands: lhs = Expression(50, Add), rhs = Zero
+- expression 5 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 6 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 7 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 8 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 9 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 10 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 11 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 12 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 13 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 14 operands: lhs = Expression(48, Add), rhs = Zero
+- expression 15 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 16 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 17 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 18 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 19 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 20 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 21 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 22 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 23 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 24 operands: lhs = Counter(3), rhs = Expression(47, Sub)
+- expression 25 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 26 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 27 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 28 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 29 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 30 operands: lhs = Expression(46, Add), rhs = Zero
+- expression 31 operands: lhs = Counter(3), rhs = Expression(47, Sub)
+- expression 32 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 33 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 34 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 35 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 36 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 37 operands: lhs = Expression(46, Add), rhs = Counter(4)
+- expression 38 operands: lhs = Counter(3), rhs = Expression(47, Sub)
+- expression 39 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 40 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 41 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 42 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 43 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 44 operands: lhs = Counter(4), rhs = Expression(45, Sub)
+- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(4)
+- expression 46 operands: lhs = Counter(3), rhs = Expression(47, Sub)
+- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 48 operands: lhs = Counter(2), rhs = Expression(49, Sub)
+- expression 49 operands: lhs = Expression(50, Add), rhs = Counter(2)
+- expression 50 operands: lhs = Counter(1), rhs = Expression(51, Sub)
+- expression 51 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 17
+- Code(Counter(0)) at (prev + 6, 1) to (start + 3, 10)
+- Code(Expression(0, Add)) at (prev + 9, 5) to (start + 1, 14)
+    = (c0 + Zero)
+- Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(51, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c1)
+- Code(Expression(50, Add)) at (prev + 2, 9) to (start + 0, 10)
+    = (c1 + (c0 - c1))
+- Code(Expression(4, Add)) at (prev + 6, 5) to (start + 1, 14)
+    = ((c1 + (c0 - c1)) + Zero)
+- Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(49, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = ((c1 + (c0 - c1)) - c2)
+- Code(Expression(48, Add)) at (prev + 2, 9) to (start + 0, 10)
+    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(14, Add)) at (prev + 6, 5) to (start + 1, 14)
+    = ((c2 + ((c1 + (c0 - c1)) - c2)) + Zero)
+- Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(47, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
+- Code(Expression(46, Add)) at (prev + 2, 9) to (start + 0, 10)
+    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Expression(30, Add)) at (prev + 6, 5) to (start + 1, 14)
+    = ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) + Zero)
+- Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(45, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)
+- Code(Expression(44, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+
+Function name: closure_bug::main::{closure#0}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0d, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 13, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+    = (c1 + (c0 - c1))
+
+Function name: closure_bug::main::{closure#1}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 22, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+    = (c1 + (c0 - c1))
+
+Function name: closure_bug::main::{closure#2}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1f, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 31, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+    = (c1 + (c0 - c1))
+
+Function name: closure_bug::main::{closure#3}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 40, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+    = (c1 + (c0 - c1))
+
diff --git a/tests/coverage-map/status-quo/closure_bug.rs b/tests/coverage-map/status-quo/closure_bug.rs
new file mode 100644
index 00000000000..739bc5f0b51
--- /dev/null
+++ b/tests/coverage-map/status-quo/closure_bug.rs
@@ -0,0 +1,44 @@
+// Regression test for #115930.
+// All of these closures are identical, and should produce identical output in
+// the coverage report. However, an unstable sort was causing them to be treated
+// inconsistently when preparing coverage spans.
+
+fn main() {
+    let truthy = std::env::args().len() == 1;
+
+    let a
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    a();
+    if truthy { a(); }
+
+    let b
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    b();
+    if truthy { b(); }
+
+    let c
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    c();
+    if truthy { c(); }
+
+    let d
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    d();
+    if truthy { d(); }
+}
diff --git a/tests/coverage-map/status-quo/generator.cov-map b/tests/coverage-map/status-quo/generator.cov-map
index 6e10b58a941..a66c1af30f9 100644
--- a/tests/coverage-map/status-quo/generator.cov-map
+++ b/tests/coverage-map/status-quo/generator.cov-map
@@ -14,7 +14,7 @@ Number of file 0 mappings: 4
     = (c1 + (c0 - c1))
 
 Function name: generator::main
-Raw bytes (71): 0x[01, 01, 0b, 01, 00, 05, 0b, 09, 0d, 11, 00, 11, 15, 2a, 19, 11, 15, 15, 19, 26, 00, 2a, 19, 11, 15, 09, 01, 0f, 01, 02, 19, 03, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 07, 01, 0e, 00, 35, 0f, 02, 0b, 00, 2e, 2a, 01, 22, 00, 27, 26, 00, 2c, 00, 2e, 1f, 01, 0e, 00, 35, 23, 02, 01, 00, 02]
+Raw bytes (71): 0x[01, 01, 0b, 01, 00, 05, 0b, 09, 0d, 11, 00, 11, 15, 2a, 19, 11, 15, 15, 19, 26, 00, 2a, 19, 11, 15, 09, 01, 0f, 01, 02, 16, 03, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 07, 01, 0e, 00, 35, 0f, 02, 0b, 00, 2e, 2a, 01, 22, 00, 27, 26, 00, 2c, 00, 2e, 1f, 01, 0e, 00, 35, 23, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 11
@@ -30,7 +30,7 @@ Number of expressions: 11
 - expression 9 operands: lhs = Expression(10, Sub), rhs = Counter(6)
 - expression 10 operands: lhs = Counter(4), rhs = Counter(5)
 Number of file 0 mappings: 9
-- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 25)
+- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 22)
 - Code(Expression(0, Add)) at (prev + 7, 11) to (start + 0, 46)
     = (c0 + Zero)
 - Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45)
diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
index acbb7904985..958078b9706 100644
--- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
+++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-abort.mir
@@ -2,11 +2,7 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: Adt(
-                std::string::String,
-                [
-                ],
-            ),
+            ty: std::string::String,
             source_info: SourceInfo {
                 span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
index c17d4421542..7e050e585b1 100644
--- a/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
+++ b/tests/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.panic-unwind.mir
@@ -2,11 +2,7 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: Adt(
-                std::string::String,
-                [
-                ],
-            ),
+            ty: std::string::String,
             source_info: SourceInfo {
                 span: $DIR/generator_drop_cleanup.rs:11:13: 11:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
index e33f5f59de1..13d703b908c 100644
--- a/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
@@ -2,11 +2,7 @@
 /* generator_layout = GeneratorLayout {
     field_tys: {
         _0: GeneratorSavedTy {
-            ty: Adt(
-                HasDrop,
-                [
-                ],
-            ),
+            ty: HasDrop,
             source_info: SourceInfo {
                 span: $DIR/generator_tiny.rs:20:13: 20:15 (#0),
                 scope: scope[0],
diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
index b6a673b6355..132b713356e 100644
--- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x00000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
index 9d112cfa20a..132b713356e 100644
--- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [Const { ty: &ReStatic [u8; Const { ty: usize, kind: Leaf(0x0000000000000004) }], kind: UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] } }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:12:16: 12:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), args: [] }: &ReStatic [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 56b0f816573..c581d0f8471 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -22,7 +22,7 @@
 |
 fn main() -> () {
     let mut _0: ();
-    let mut _1: [usize; Const { ty: usize, kind: Leaf(0x00000003) }];
+    let mut _1: [usize; ValTree(Leaf(0x00000003): usize)];
     let _3: usize;
     let mut _4: usize;
     let mut _5: bool;
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index 83b851eed74..48243e34d08 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -22,7 +22,7 @@
 |
 fn main() -> () {
     let mut _0: ();
-    let mut _1: [usize; Const { ty: usize, kind: Leaf(0x0000000000000003) }];
+    let mut _1: [usize; ValTree(Leaf(0x0000000000000003): usize)];
     let _3: usize;
     let mut _4: usize;
     let mut _5: bool;
diff --git a/tests/run-coverage/closure.coverage b/tests/run-coverage/closure.coverage
index 930348dc431..67014f792c8 100644
--- a/tests/run-coverage/closure.coverage
+++ b/tests/run-coverage/closure.coverage
@@ -76,8 +76,8 @@
    LL|      1|    some_string = None;
    LL|      1|    let
    LL|      1|        a
-   LL|      1|    =
-   LL|      1|        ||
+   LL|       |    =
+   LL|       |        ||
    LL|      1|    {
    LL|      1|        let mut countdown = 0;
    LL|      1|        if is_false {
@@ -98,8 +98,8 @@
    LL|      1|
    LL|      1|    let
    LL|      1|        quote_closure
-   LL|      1|    =
-   LL|      1|        |val|
+   LL|       |    =
+   LL|       |        |val|
    LL|      5|    {
    LL|      5|        let mut countdown = 0;
    LL|      5|        if is_false {
@@ -186,7 +186,7 @@
    LL|       |    ;
    LL|       |
    LL|      1|    let short_used_not_covered_closure_line_break_block_embedded_branch =
-   LL|      1|        | _unused_arg: u8 |
+   LL|       |        | _unused_arg: u8 |
    LL|      0|        {
    LL|      0|            println!(
    LL|      0|                "not called: {}",
@@ -196,7 +196,7 @@
    LL|       |    ;
    LL|       |
    LL|      1|    let short_used_covered_closure_line_break_no_block_embedded_branch =
-   LL|      1|        | _unused_arg: u8 |
+   LL|       |        | _unused_arg: u8 |
    LL|      1|            println!(
    LL|      1|                "not called: {}",
    LL|      1|                if is_true { "check" } else { "me" }
@@ -205,7 +205,7 @@
    LL|       |    ;
    LL|       |
    LL|      1|    let short_used_covered_closure_line_break_block_embedded_branch =
-   LL|      1|        | _unused_arg: u8 |
+   LL|       |        | _unused_arg: u8 |
    LL|      1|        {
    LL|      1|            println!(
    LL|      1|                "not called: {}",
diff --git a/tests/run-coverage/closure_bug.coverage b/tests/run-coverage/closure_bug.coverage
new file mode 100644
index 00000000000..f3299834bce
--- /dev/null
+++ b/tests/run-coverage/closure_bug.coverage
@@ -0,0 +1,53 @@
+   LL|       |// Regression test for #115930.
+   LL|       |// All of these closures are identical, and should produce identical output in
+   LL|       |// the coverage report. However, an unstable sort was causing them to be treated
+   LL|       |// inconsistently when preparing coverage spans.
+   LL|       |
+   LL|      1|fn main() {
+   LL|      1|    let truthy = std::env::args().len() == 1;
+   LL|      1|
+   LL|      1|    let a
+   LL|       |        =
+   LL|       |        |
+   LL|       |        |
+   LL|      2|        if truthy { true } else { false };
+                                                ^0
+   LL|       |
+   LL|      1|    a();
+   LL|      1|    if truthy { a(); }
+                                    ^0
+   LL|       |
+   LL|      1|    let b
+   LL|       |        =
+   LL|       |        |
+   LL|       |        |
+   LL|      2|        if truthy { true } else { false };
+                                                ^0
+   LL|       |
+   LL|      1|    b();
+   LL|      1|    if truthy { b(); }
+                                    ^0
+   LL|       |
+   LL|      1|    let c
+   LL|       |        =
+   LL|       |        |
+   LL|       |        |
+   LL|      2|        if truthy { true } else { false };
+                                                ^0
+   LL|       |
+   LL|      1|    c();
+   LL|      1|    if truthy { c(); }
+                                    ^0
+   LL|       |
+   LL|      1|    let d
+   LL|       |        =
+   LL|       |        |
+   LL|       |        |
+   LL|      2|        if truthy { true } else { false };
+                                                ^0
+   LL|       |
+   LL|      1|    d();
+   LL|      1|    if truthy { d(); }
+                                    ^0
+   LL|      1|}
+
diff --git a/tests/run-coverage/closure_bug.rs b/tests/run-coverage/closure_bug.rs
new file mode 100644
index 00000000000..739bc5f0b51
--- /dev/null
+++ b/tests/run-coverage/closure_bug.rs
@@ -0,0 +1,44 @@
+// Regression test for #115930.
+// All of these closures are identical, and should produce identical output in
+// the coverage report. However, an unstable sort was causing them to be treated
+// inconsistently when preparing coverage spans.
+
+fn main() {
+    let truthy = std::env::args().len() == 1;
+
+    let a
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    a();
+    if truthy { a(); }
+
+    let b
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    b();
+    if truthy { b(); }
+
+    let c
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    c();
+    if truthy { c(); }
+
+    let d
+        =
+        |
+        |
+        if truthy { true } else { false };
+
+    d();
+    if truthy { d(); }
+}
diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout
index de8ff0e5f89..f5981045b03 100644
--- a/tests/run-make/issue-88756-default-output/output-default.stdout
+++ b/tests/run-make/issue-88756-default-output/output-default.stdout
@@ -100,7 +100,7 @@ Options:
                         check if given theme is valid
         --resource-suffix PATH
                         suffix to add to CSS and JavaScript files, e.g.,
-                        "light.css" will become "light-suffix.css"
+                        "search-index.js" will become "search-index-suffix.js"
         --edition EDITION
                         edition to use when compiling rust code (default:
                         2015)
diff --git a/tests/run-make/metadata-dep-info/Makefile b/tests/run-make/metadata-dep-info/Makefile
new file mode 100644
index 00000000000..f9043f21433
--- /dev/null
+++ b/tests/run-make/metadata-dep-info/Makefile
@@ -0,0 +1,13 @@
+include ../tools.mk
+
+ifdef RUSTC_BLESS_TEST
+    RUSTC_TEST_OP = cp
+else
+    RUSTC_TEST_OP = $(DIFF)
+endif
+
+all:
+	$(RUSTC) --emit=metadata,dep-info --crate-type lib dash-separated.rs -C extra-filename=_something-extra
+	# Strip TMPDIR since it is a machine specific absolute path
+	sed "s%.*[/\\]%%" "$(TMPDIR)"/dash-separated_something-extra.d > "$(TMPDIR)"/dash-separated_something-extra.normalized.d
+	$(RUSTC_TEST_OP) "$(TMPDIR)"/dash-separated_something-extra.normalized.d dash-separated_something-extra.normalized.d
diff --git a/tests/run-make/metadata-dep-info/dash-separated.rs b/tests/run-make/metadata-dep-info/dash-separated.rs
new file mode 100644
index 00000000000..4202afd3d08
--- /dev/null
+++ b/tests/run-make/metadata-dep-info/dash-separated.rs
@@ -0,0 +1,4 @@
+//! It is important that this file has at least one `-` in the file name since
+//! we want to test that it becomes a `_` when appropriate.
+
+pub struct Foo;
diff --git a/tests/run-make/metadata-dep-info/dash-separated_something-extra.normalized.d b/tests/run-make/metadata-dep-info/dash-separated_something-extra.normalized.d
new file mode 100644
index 00000000000..497d76b4ea1
--- /dev/null
+++ b/tests/run-make/metadata-dep-info/dash-separated_something-extra.normalized.d
@@ -0,0 +1,5 @@
+libdash_separated_something-extra.rmeta: dash-separated.rs
+
+dash-separated_something-extra.d: dash-separated.rs
+
+dash-separated.rs:
diff --git a/tests/run-make/rustdoc-themes/Makefile b/tests/run-make/rustdoc-themes/Makefile
index a6d9a43addf..a4980eb0b3e 100644
--- a/tests/run-make/rustdoc-themes/Makefile
+++ b/tests/run-make/rustdoc-themes/Makefile
@@ -5,6 +5,7 @@ include ../tools.mk
 OUTPUT_DIR := "$(TMPDIR)/rustdoc-themes"
 
 all:
-	cp $(S)/src/librustdoc/html/static/css/themes/light.css $(TMPDIR)/test.css
+	awk '/Begin theme: light/ {in_theme=1;next} /End theme:/ {in_theme=0} { if (in_theme) print }' \
+		< '$(S)/src/librustdoc/html/static/css/noscript.css' > '$(TMPDIR)/test.css'
 	$(RUSTDOC) -o $(OUTPUT_DIR) foo.rs --theme $(TMPDIR)/test.css
 	$(HTMLDOCCK) $(OUTPUT_DIR) foo.rs
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index f9f81c5ba04..44677dfbfef 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -151,7 +151,7 @@ assert-css: (
 )
 assert-css: (
     "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a",
-    {"color": "#fff", "background-color": "rgb(60, 60, 60)"},
+    {"color": "#fff", "background-color": "#3c3c3c"},
 )
 
 // Dark theme
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning.rs b/tests/rustdoc-ui/custom_code_classes_in_docs-warning.rs
new file mode 100644
index 00000000000..dd8759b7e37
--- /dev/null
+++ b/tests/rustdoc-ui/custom_code_classes_in_docs-warning.rs
@@ -0,0 +1,85 @@
+// This test ensures that warnings are working as expected for "custom_code_classes_in_docs"
+// feature.
+
+#![feature(custom_code_classes_in_docs)]
+#![deny(warnings)]
+#![feature(no_core)]
+#![no_core]
+
+/// ```{. }
+/// main;
+/// ```
+//~^^^ ERROR unexpected ` ` character after `.`
+pub fn foo() {}
+
+/// ```{class= a}
+/// main;
+/// ```
+//~^^^ ERROR unexpected ` ` character after `=`
+pub fn foo2() {}
+
+/// ```{#id}
+/// main;
+/// ```
+//~^^^ ERROR unexpected character `#`
+pub fn foo3() {}
+
+/// ```{{
+/// main;
+/// ```
+//~^^^ ERROR unexpected character `{`
+pub fn foo4() {}
+
+/// ```}
+/// main;
+/// ```
+//~^^^ ERROR unexpected character `}`
+pub fn foo5() {}
+
+/// ```)
+/// main;
+/// ```
+//~^^^ ERROR unexpected character `)`
+pub fn foo6() {}
+
+/// ```{class=}
+/// main;
+/// ```
+//~^^^ ERROR unexpected `}` character after `=`
+pub fn foo7() {}
+
+/// ```(
+/// main;
+/// ```
+//~^^^ ERROR unclosed comment: missing `)` at the end
+pub fn foo8() {}
+
+/// ```{class=one=two}
+/// main;
+/// ```
+//~^^^ ERROR unexpected `=`
+pub fn foo9() {}
+
+/// ```{.one.two}
+/// main;
+/// ```
+//~^^^ ERROR unexpected `.` character
+pub fn foo10() {}
+
+/// ```{class=.one}
+/// main;
+/// ```
+//~^^^ ERROR unexpected `.` character after `=`
+pub fn foo11() {}
+
+/// ```{class=one.two}
+/// main;
+/// ```
+//~^^^ ERROR unexpected `.` character
+pub fn foo12() {}
+
+/// ```{(comment)}
+/// main;
+/// ```
+//~^^^ ERROR unexpected character `(`
+pub fn foo13() {}
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning.stderr b/tests/rustdoc-ui/custom_code_classes_in_docs-warning.stderr
new file mode 100644
index 00000000000..3e0dc4b2f7a
--- /dev/null
+++ b/tests/rustdoc-ui/custom_code_classes_in_docs-warning.stderr
@@ -0,0 +1,113 @@
+error: unexpected ` ` character after `.`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:9:1
+   |
+LL | / /// ```{. }
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+   |
+note: the lint level is defined here
+  --> $DIR/custom_code_classes_in_docs-warning.rs:5:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
+
+error: unexpected ` ` character after `=`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:15:1
+   |
+LL | / /// ```{class= a}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected character `#`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:21:1
+   |
+LL | / /// ```{#id}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected character `{`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:27:1
+   |
+LL | / /// ```{{
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected character `}`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:33:1
+   |
+LL | / /// ```}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected character `)`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:39:1
+   |
+LL | / /// ```)
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected `}` character after `=`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:45:1
+   |
+LL | / /// ```{class=}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unclosed comment: missing `)` at the end
+  --> $DIR/custom_code_classes_in_docs-warning.rs:51:1
+   |
+LL | / /// ```(
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected `=` character
+  --> $DIR/custom_code_classes_in_docs-warning.rs:57:1
+   |
+LL | / /// ```{class=one=two}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected `.` character
+  --> $DIR/custom_code_classes_in_docs-warning.rs:63:1
+   |
+LL | / /// ```{.one.two}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected `.` character after `=`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:69:1
+   |
+LL | / /// ```{class=.one}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected `.` character
+  --> $DIR/custom_code_classes_in_docs-warning.rs:75:1
+   |
+LL | / /// ```{class=one.two}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: unexpected character `(`
+  --> $DIR/custom_code_classes_in_docs-warning.rs:81:1
+   |
+LL | / /// ```{(comment)}
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: aborting due to 13 previous errors
+
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
new file mode 100644
index 00000000000..57d9038cb0c
--- /dev/null
+++ b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
@@ -0,0 +1,17 @@
+// This test ensures that warnings are working as expected for "custom_code_classes_in_docs"
+// feature.
+
+#![feature(custom_code_classes_in_docs)]
+#![deny(warnings)]
+#![feature(no_core)]
+#![no_core]
+
+/// ```{class="}
+/// main;
+/// ```
+//~^^^ ERROR unclosed quote string
+//~| ERROR unclosed quote string
+/// ```"
+/// main;
+/// ```
+pub fn foo() {}
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
new file mode 100644
index 00000000000..4f2ded78c29
--- /dev/null
+++ b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
@@ -0,0 +1,33 @@
+error: unclosed quote string `"`
+  --> $DIR/custom_code_classes_in_docs-warning3.rs:9:1
+   |
+LL | / /// ```{class="}
+LL | | /// main;
+LL | | /// ```
+LL | |
+...  |
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+   |
+note: the lint level is defined here
+  --> $DIR/custom_code_classes_in_docs-warning3.rs:5:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
+
+error: unclosed quote string `"`
+  --> $DIR/custom_code_classes_in_docs-warning3.rs:9:1
+   |
+LL | / /// ```{class="}
+LL | | /// main;
+LL | | /// ```
+LL | |
+...  |
+LL | | /// main;
+LL | | /// ```
+   | |_______^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.rs b/tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.rs
new file mode 100644
index 00000000000..3f0f8b5b9f9
--- /dev/null
+++ b/tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+/// ```{class=language-c}
+/// int main(void) { return 0; }
+/// ```
+//~^^^ WARNING custom classes in code blocks will change behaviour
+//~| NOTE found these custom classes: class=language-c
+//~| NOTE see issue #79483 <https://github.com/rust-lang/rust/issues/79483>
+//~| HELP add `#![feature(custom_code_classes_in_docs)]` to the crate attributes to enable
+pub struct Bar;
diff --git a/tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.stderr b/tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.stderr
new file mode 100644
index 00000000000..1a2360d9b30
--- /dev/null
+++ b/tests/rustdoc-ui/feature-gate-custom_code_classes_in_docs.stderr
@@ -0,0 +1,14 @@
+warning: custom classes in code blocks will change behaviour
+  --> $DIR/feature-gate-custom_code_classes_in_docs.rs:3:1
+   |
+LL | / /// ```{class=language-c}
+LL | | /// int main(void) { return 0; }
+LL | | /// ```
+   | |_______^
+   |
+   = note: see issue #79483 <https://github.com/rust-lang/rust/issues/79483> for more information
+   = help: add `#![feature(custom_code_classes_in_docs)]` to the crate attributes to enable
+   = note: found these custom classes: class=language-c
+
+warning: 1 warning emitted
+
diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout
index 16783524363..bbea7e5c212 100644
--- a/tests/rustdoc-ui/issues/issue-91713.stdout
+++ b/tests/rustdoc-ui/issues/issue-91713.stdout
@@ -1,4 +1,5 @@
 Available passes for running rustdoc:
+check-custom-code-classes - check for custom code classes without the feature-gate enabled
 check_doc_test_visibility - run various visibility-related lints on doctests
         strip-hidden - strips all `#[doc(hidden)]` items from the output
        strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
@@ -10,6 +11,7 @@ calculate-doc-coverage - counts the number of items with and without documentati
            run-lints - runs some of rustdoc's lints
 
 Default passes for rustdoc:
+check-custom-code-classes
  collect-trait-impls
 check_doc_test_visibility
         strip-hidden  (when not --document-hidden-items)
diff --git a/tests/rustdoc/custom_code_classes.rs b/tests/rustdoc/custom_code_classes.rs
new file mode 100644
index 00000000000..cd20d8b7d6c
--- /dev/null
+++ b/tests/rustdoc/custom_code_classes.rs
@@ -0,0 +1,28 @@
+// Test for `custom_code_classes_in_docs` feature.
+
+#![feature(custom_code_classes_in_docs)]
+#![crate_name = "foo"]
+#![feature(no_core)]
+#![no_core]
+
+// @has 'foo/struct.Bar.html'
+// @has - '//*[@id="main-content"]//pre[@class="language-whatever hoho-c"]' 'main;'
+// @has - '//*[@id="main-content"]//pre[@class="language-whatever2 haha-c"]' 'main;'
+// @has - '//*[@id="main-content"]//pre[@class="language-whatever4 huhu-c"]' 'main;'
+
+/// ```{class=hoho-c},whatever
+/// main;
+/// ```
+///
+/// Testing multiple kinds of orders.
+///
+/// ```whatever2 {class=haha-c}
+/// main;
+/// ```
+///
+/// Testing with multiple "unknown". Only the first should be used.
+///
+/// ```whatever4,{.huhu-c} whatever5
+/// main;
+/// ```
+pub struct Bar;
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
index ac37d7b6bff..77715ee4023 100644
--- a/tests/ui/abi/debug.rs
+++ b/tests/ui/abi/debug.rs
@@ -4,7 +4,6 @@
 // normalize-stderr-test "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
 // This pattern is prepared for when we account for alignment in the niche.
 // normalize-stderr-test "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL"
-// normalize-stderr-test "Leaf\(0x0*20\)" -> "Leaf(0x0...20)"
 // Some attributes are only computed for release builds:
 // compile-flags: -O
 #![feature(rustc_attrs)]
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index f56f5c525ab..00fc7d1ece1 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -87,7 +87,7 @@ error: fn_abi_of(test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:16:1
+  --> $DIR/debug.rs:15:1
    |
 LL | fn test(_x: u8) -> bool { true }
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:19:1
+  --> $DIR/debug.rs:18:1
    |
 LL | type TestFnPtr = fn(bool) -> u8;
    | ^^^^^^^^^^^^^^
@@ -190,7 +190,7 @@ error: fn_abi_of(test_generic) = FnAbi {
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: *const T/#0,
+                       ty: *const T,
                        layout: Layout {
                            size: $SOME_SIZE,
                            align: AbiAndPrefAlign {
@@ -257,13 +257,13 @@ error: fn_abi_of(test_generic) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:22:1
+  --> $DIR/debug.rs:21:1
    |
 LL | fn test_generic<T>(_x: *const T) { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:25:1
+  --> $DIR/debug.rs:24:1
    |
 LL | const C: () = ();
    | ^^^^^^^^^^^
@@ -409,7 +409,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:41:1
+  --> $DIR/debug.rs:40:1
    |
 LL | type TestAbiNe = (fn(u8), fn(u32));
    | ^^^^^^^^^^^^^^
@@ -419,7 +419,7 @@ error: ABIs are not compatible
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: [u8; Const { ty: usize, kind: Leaf(0x0...20) }],
+                       ty: [u8; 32],
                        layout: Layout {
                            size: Size(32 bytes),
                            align: AbiAndPrefAlign {
@@ -450,7 +450,7 @@ error: ABIs are not compatible
                                Align(1 bytes),
                            ),
                        },
-                       extra_attrs: None,
+                       meta_attrs: None,
                        on_stack: false,
                    },
                },
@@ -490,7 +490,7 @@ error: ABIs are not compatible
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: [u32; Const { ty: usize, kind: Leaf(0x0...20) }],
+                       ty: [u32; 32],
                        layout: Layout {
                            size: Size(128 bytes),
                            align: AbiAndPrefAlign {
@@ -521,7 +521,7 @@ error: ABIs are not compatible
                                Align(4 bytes),
                            ),
                        },
-                       extra_attrs: None,
+                       meta_attrs: None,
                        on_stack: false,
                    },
                },
@@ -557,7 +557,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:44:1
+  --> $DIR/debug.rs:43:1
    |
 LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32]));
    | ^^^^^^^^^^^^^^^^^^^^
@@ -700,7 +700,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:47:1
+  --> $DIR/debug.rs:46:1
    |
 LL | type TestAbiNeFloat = (fn(f32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^^
@@ -846,13 +846,13 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:51:1
+  --> $DIR/debug.rs:50:1
    |
 LL | type TestAbiNeSign = (fn(i32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/debug.rs:54:46
+  --> $DIR/debug.rs:53:46
    |
 LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
    |                                              ^^^^^^^^^^ doesn't have a size known at compile-time
@@ -861,7 +861,7 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
    = note: only the last element of a tuple may have a dynamically sized type
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:29:5
+  --> $DIR/debug.rs:28:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
@@ -870,7 +870,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
            args: [
                ArgAbi {
                    layout: TyAndLayout {
-                       ty: &ReErased Adt(S, []),
+                       ty: &S,
                        layout: Layout {
                            size: $SOME_SIZE,
                            align: AbiAndPrefAlign {
@@ -949,7 +949,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:34:5
+  --> $DIR/debug.rs:33:5
    |
 LL |     fn assoc_test(&self) { }
    |     ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/associated-consts/defaults-cyclic-fail.rs b/tests/ui/associated-consts/defaults-cyclic-fail.rs
index a1c6840a0f1..9ef0003da17 100644
--- a/tests/ui/associated-consts/defaults-cyclic-fail.rs
+++ b/tests/ui/associated-consts/defaults-cyclic-fail.rs
@@ -3,7 +3,7 @@
 // Cyclic assoc. const defaults don't error unless *used*
 trait Tr {
     const A: u8 = Self::B;
-    //~^ cycle detected when const-evaluating + checking `Tr::A`
+    //~^ cycle detected
 
     const B: u8 = Self::A;
 }
diff --git a/tests/ui/associated-consts/defaults-cyclic-fail.stderr b/tests/ui/associated-consts/defaults-cyclic-fail.stderr
index ebdb76e4286..e29c32f5dfd 100644
--- a/tests/ui/associated-consts/defaults-cyclic-fail.stderr
+++ b/tests/ui/associated-consts/defaults-cyclic-fail.stderr
@@ -1,15 +1,25 @@
-error[E0391]: cycle detected when const-evaluating + checking `Tr::A`
+error[E0391]: cycle detected when simplifying constant for the type system `Tr::A`
+  --> $DIR/defaults-cyclic-fail.rs:5:5
+   |
+LL |     const A: u8 = Self::B;
+   |     ^^^^^^^^^^^
+   |
+note: ...which requires const-evaluating + checking `Tr::A`...
   --> $DIR/defaults-cyclic-fail.rs:5:19
    |
 LL |     const A: u8 = Self::B;
    |                   ^^^^^^^
+note: ...which requires simplifying constant for the type system `Tr::B`...
+  --> $DIR/defaults-cyclic-fail.rs:8:5
    |
+LL |     const B: u8 = Self::A;
+   |     ^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `Tr::B`...
   --> $DIR/defaults-cyclic-fail.rs:8:19
    |
 LL |     const B: u8 = Self::A;
    |                   ^^^^^^^
-   = note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle
+   = note: ...which again requires simplifying constant for the type system `Tr::A`, completing the cycle
 note: cycle used when const-evaluating + checking `main::promoted[1]`
   --> $DIR/defaults-cyclic-fail.rs:16:16
    |
diff --git a/tests/ui/associated-consts/defaults-not-assumed-fail.stderr b/tests/ui/associated-consts/defaults-not-assumed-fail.stderr
index 9b761b00691..d659912341a 100644
--- a/tests/ui/associated-consts/defaults-not-assumed-fail.stderr
+++ b/tests/ui/associated-consts/defaults-not-assumed-fail.stderr
@@ -4,13 +4,13 @@ error[E0080]: evaluation of `<() as Tr>::B` failed
 LL |     const B: u8 = Self::A + 1;
    |                   ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/defaults-not-assumed-fail.rs:33:16
    |
 LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
    |                ^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/defaults-not-assumed-fail.rs:33:5
    |
 LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
@@ -18,7 +18,7 @@ LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
    |
    = note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/defaults-not-assumed-fail.rs:33:5
    |
 LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
index 51bf0cb5e5c..4418fb7556b 100644
--- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
+++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
@@ -4,7 +4,12 @@ error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-249
 LL |     const BAR: u32 = IMPL_REF_BAR;
    |                      ^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
+note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
+   |
+LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
    |
 LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
@@ -14,6 +19,11 @@ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
    |
 LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
    |                           ^^^^^^^^^^^^^^^^^^
+note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
+   |
+LL |     const BAR: u32 = IMPL_REF_BAR;
+   |     ^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
    |
diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr
index 8277d41a1c9..392cd5e3443 100644
--- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr
+++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr
@@ -4,7 +4,12 @@ error[E0391]: cycle detected when elaborating drops for `FooDefault::BAR`
 LL |     const BAR: u32 = DEFAULT_REF_BAR;
    |                      ^^^^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
+note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
+   |
+LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
    |
 LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
@@ -14,6 +19,11 @@ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
    |
 LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
    |                              ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
+   |
+LL |     const BAR: u32 = DEFAULT_REF_BAR;
+   |     ^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `FooDefault::BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
    |
diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr
index 9983ba794cd..6cbddca9c62 100644
--- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr
+++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr
@@ -4,7 +4,12 @@ error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-249
 LL |     const BAR: u32 = TRAIT_REF_BAR;
    |                      ^^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
+note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
+   |
+LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
    |
 LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
@@ -14,6 +19,11 @@ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
    |
 LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
    |                            ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
+   |
+LL |     const BAR: u32 = TRAIT_REF_BAR;
+   |     ^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
    |
diff --git a/tests/ui/borrowck/issue-81899.stderr b/tests/ui/borrowck/issue-81899.stderr
index 1b03bc3af9c..63e817239c6 100644
--- a/tests/ui/borrowck/issue-81899.stderr
+++ b/tests/ui/borrowck/issue-81899.stderr
@@ -16,7 +16,7 @@ LL | const _CONST: &[u8] = &f(&[], |_| {});
    |                        ^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-81899.rs:4:23
    |
 LL | const _CONST: &[u8] = &f(&[], |_| {});
diff --git a/tests/ui/borrowck/issue-88434-minimal-example.stderr b/tests/ui/borrowck/issue-88434-minimal-example.stderr
index a5a571c6d4d..4c887b2ad42 100644
--- a/tests/ui/borrowck/issue-88434-minimal-example.stderr
+++ b/tests/ui/borrowck/issue-88434-minimal-example.stderr
@@ -16,7 +16,7 @@ LL | const _CONST: &() = &f(&|_| {});
    |                      ^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-88434-minimal-example.rs:3:21
    |
 LL | const _CONST: &() = &f(&|_| {});
diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
index 00023c459a8..f7257817a8b 100644
--- a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
+++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
@@ -16,7 +16,7 @@ LL | const _CONST: &[u8] = &f(&[], |_| {});
    |                        ^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-88434-removal-index-should-be-less.rs:3:23
    |
 LL | const _CONST: &[u8] = &f(&[], |_| {});
diff --git a/tests/ui/c-variadic/variadic-ffi-2.rs b/tests/ui/c-variadic/variadic-ffi-2.rs
index c34b7e55f6a..67a0a9a1dec 100644
--- a/tests/ui/c-variadic/variadic-ffi-2.rs
+++ b/tests/ui/c-variadic/variadic-ffi-2.rs
@@ -3,10 +3,13 @@
 
 fn baz(f: extern "stdcall" fn(usize, ...)) {
     //~^ ERROR: C-variadic function must have a compatible calling convention,
-    // like C, cdecl, win64, sysv64 or efiapi
+    // like C, cdecl, aapcs, win64, sysv64 or efiapi
     f(22, 44);
 }
 
+fn aapcs(f: extern "aapcs" fn(usize, ...)) {
+    f(22, 44);
+}
 fn sysv(f: extern "sysv64" fn(usize, ...)) {
     f(22, 44);
 }
diff --git a/tests/ui/c-variadic/variadic-ffi-2.stderr b/tests/ui/c-variadic/variadic-ffi-2.stderr
index e21001ecaf8..8884fc6fb2a 100644
--- a/tests/ui/c-variadic/variadic-ffi-2.stderr
+++ b/tests/ui/c-variadic/variadic-ffi-2.stderr
@@ -1,4 +1,4 @@
-error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `win64`, `sysv64` or `efiapi`
+error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`
   --> $DIR/variadic-ffi-2.rs:4:11
    |
 LL | fn baz(f: extern "stdcall" fn(usize, ...)) {
diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs
index 750a88f97eb..511a02718fe 100644
--- a/tests/ui/cast/cast-as-bool.rs
+++ b/tests/ui/cast/cast-as-bool.rs
@@ -1,11 +1,11 @@
 fn main() {
     let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool`
                        //~| HELP compare with zero instead
-                       //~| SUGGESTION 5 != 0
+                       //~| SUGGESTION != 0
 
     let t = (1 + 2) as bool; //~ ERROR cannot cast `i32` as `bool`
                              //~| HELP compare with zero instead
-                             //~| SUGGESTION (1 + 2) != 0
+                             //~| SUGGESTION != 0
 
     let _ = 5_u32 as bool; //~ ERROR cannot cast `u32` as `bool`
                            //~| HELP compare with zero instead
diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr
index 852fb30cc20..4ff56a95e49 100644
--- a/tests/ui/cast/cast-as-bool.stderr
+++ b/tests/ui/cast/cast-as-bool.stderr
@@ -2,25 +2,45 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-as-bool.rs:2:13
    |
 LL |     let u = 5 as bool;
-   |             ^^^^^^^^^ help: compare with zero instead: `5 != 0`
+   |             ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let u = 5 != 0;
+   |               ~~~~
 
 error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-as-bool.rs:6:13
    |
 LL |     let t = (1 + 2) as bool;
-   |             ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
+   |             ^^^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let t = (1 + 2) != 0;
+   |                     ~~~~
 
 error[E0054]: cannot cast `u32` as `bool`
   --> $DIR/cast-as-bool.rs:10:13
    |
 LL |     let _ = 5_u32 as bool;
-   |             ^^^^^^^^^^^^^ help: compare with zero instead: `5_u32 != 0`
+   |             ^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 5_u32 != 0;
+   |                   ~~~~
 
 error[E0054]: cannot cast `f64` as `bool`
   --> $DIR/cast-as-bool.rs:13:13
    |
 LL |     let _ = 64.0_f64 as bool;
-   |             ^^^^^^^^^^^^^^^^ help: compare with zero instead: `64.0_f64 != 0`
+   |             ^^^^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 64.0_f64 != 0;
+   |                      ~~~~
 
 error[E0054]: cannot cast `IntEnum` as `bool`
   --> $DIR/cast-as-bool.rs:24:13
diff --git a/tests/ui/cast/cast-rfc0401-2.stderr b/tests/ui/cast/cast-rfc0401-2.stderr
index 5dc21ca847c..dd90c3a9723 100644
--- a/tests/ui/cast/cast-rfc0401-2.stderr
+++ b/tests/ui/cast/cast-rfc0401-2.stderr
@@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-rfc0401-2.rs:6:13
    |
 LL |     let _ = 3 as bool;
-   |             ^^^^^^^^^ help: compare with zero instead: `3 != 0`
+   |             ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 3 != 0;
+   |               ~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/closures/2229_closure_analysis/repr_packed.rs b/tests/ui/closures/2229_closure_analysis/repr_packed.rs
index f23670f63ac..8c23454fae9 100644
--- a/tests/ui/closures/2229_closure_analysis/repr_packed.rs
+++ b/tests/ui/closures/2229_closure_analysis/repr_packed.rs
@@ -3,7 +3,8 @@
 #![feature(rustc_attrs)]
 
 // `u8` aligned at a byte and are unaffected by repr(packed).
-// Therefore we can precisely (and safely) capture references to both the fields.
+// Therefore we *could* precisely (and safely) capture references to both the fields,
+// but we don't, since we don't want capturing to change when field types change alignment.
 fn test_alignment_not_affected() {
     #[repr(packed)]
     struct Foo { x: u8, y: u8 }
@@ -17,11 +18,10 @@ fn test_alignment_not_affected() {
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         let z1: &u8 = &foo.x;
-        //~^ NOTE: Capturing foo[(0, 0)] -> ImmBorrow
-        //~| NOTE: Min Capture foo[(0, 0)] -> ImmBorrow
+        //~^ NOTE: Capturing foo[] -> ImmBorrow
         let z2: &mut u8 = &mut foo.y;
-        //~^ NOTE: Capturing foo[(1, 0)] -> MutBorrow
-        //~| NOTE: Min Capture foo[(1, 0)] -> MutBorrow
+        //~^ NOTE: Capturing foo[] -> MutBorrow
+        //~| NOTE: Min Capture foo[] -> MutBorrow
 
         *z2 = 42;
 
diff --git a/tests/ui/closures/2229_closure_analysis/repr_packed.stderr b/tests/ui/closures/2229_closure_analysis/repr_packed.stderr
index 580061ebc6e..32b3d844c6e 100644
--- a/tests/ui/closures/2229_closure_analysis/repr_packed.stderr
+++ b/tests/ui/closures/2229_closure_analysis/repr_packed.stderr
@@ -1,5 +1,5 @@
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/repr_packed.rs:13:17
+  --> $DIR/repr_packed.rs:14:17
    |
 LL |     let mut c = #[rustc_capture_analysis]
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error: First Pass analysis includes:
-  --> $DIR/repr_packed.rs:16:5
+  --> $DIR/repr_packed.rs:17:5
    |
 LL | /     || {
 LL | |
@@ -37,19 +37,19 @@ LL | |         println!("({}, {})", z1, z2);
 LL | |     };
    | |_____^
    |
-note: Capturing foo[(0, 0)] -> ImmBorrow
-  --> $DIR/repr_packed.rs:19:24
+note: Capturing foo[] -> ImmBorrow
+  --> $DIR/repr_packed.rs:20:24
    |
 LL |         let z1: &u8 = &foo.x;
    |                        ^^^^^
-note: Capturing foo[(1, 0)] -> MutBorrow
+note: Capturing foo[] -> MutBorrow
   --> $DIR/repr_packed.rs:22:32
    |
 LL |         let z2: &mut u8 = &mut foo.y;
    |                                ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/repr_packed.rs:16:5
+  --> $DIR/repr_packed.rs:17:5
    |
 LL | /     || {
 LL | |
@@ -60,12 +60,7 @@ LL | |         println!("({}, {})", z1, z2);
 LL | |     };
    | |_____^
    |
-note: Min Capture foo[(0, 0)] -> ImmBorrow
-  --> $DIR/repr_packed.rs:19:24
-   |
-LL |         let z1: &u8 = &foo.x;
-   |                        ^^^^^
-note: Min Capture foo[(1, 0)] -> MutBorrow
+note: Min Capture foo[] -> MutBorrow
   --> $DIR/repr_packed.rs:22:32
    |
 LL |         let z2: &mut u8 = &mut foo.y;
diff --git a/tests/ui/consts/const-err-late.stderr b/tests/ui/consts/const-err-late.stderr
index 149d3b5236b..85bc56baed8 100644
--- a/tests/ui/consts/const-err-late.stderr
+++ b/tests/ui/consts/const-err-late.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of `S::<i32>::FOO` failed
 LL |     const FOO: u8 = [5u8][1];
    |                     ^^^^^^^^ index out of bounds: the length is 1 but the index is 1
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-err-late.rs:19:16
    |
 LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
@@ -16,13 +16,13 @@ error[E0080]: evaluation of `S::<u32>::FOO` failed
 LL |     const FOO: u8 = [5u8][1];
    |                     ^^^^^^^^ index out of bounds: the length is 1 but the index is 1
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-err-late.rs:19:31
    |
 LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
    |                               ^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-err-late.rs:19:16
    |
 LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
diff --git a/tests/ui/consts/const-err-multi.stderr b/tests/ui/consts/const-err-multi.stderr
index 28af8e5eb09..1ad504b3a80 100644
--- a/tests/ui/consts/const-err-multi.stderr
+++ b/tests/ui/consts/const-err-multi.stderr
@@ -4,19 +4,19 @@ error[E0080]: evaluation of constant value failed
 LL | pub const A: i8 = -i8::MIN;
    |                   ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-err-multi.rs:3:19
    |
 LL | pub const B: i8 = A;
    |                   ^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-err-multi.rs:5:19
    |
 LL | pub const C: u8 = A as u8;
    |                   ^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-err-multi.rs:7:24
    |
 LL | pub const D: i8 = 50 - A;
diff --git a/tests/ui/consts/const-eval/erroneous-const.stderr b/tests/ui/consts/const-eval/erroneous-const.stderr
index 770f95062ab..0e31520fdbb 100644
--- a/tests/ui/consts/const-eval/erroneous-const.stderr
+++ b/tests/ui/consts/const-eval/erroneous-const.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
 LL |     const VOID: () = [()][2];
    |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/erroneous-const.rs:13:13
    |
 LL |             PrintName::<T>::VOID;
diff --git a/tests/ui/consts/const-eval/erroneous-const2.stderr b/tests/ui/consts/const-eval/erroneous-const2.stderr
index 082c2876575..4ca44694cd7 100644
--- a/tests/ui/consts/const-eval/erroneous-const2.stderr
+++ b/tests/ui/consts/const-eval/erroneous-const2.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
 LL |     const VOID: () = [()][2];
    |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/erroneous-const2.rs:13:9
    |
 LL |         PrintName::<i32>::VOID;
diff --git a/tests/ui/consts/const-eval/issue-44578.stderr b/tests/ui/consts/const-eval/issue-44578.stderr
index f3952809e4b..c7aaee94271 100644
--- a/tests/ui/consts/const-eval/issue-44578.stderr
+++ b/tests/ui/consts/const-eval/issue-44578.stderr
@@ -4,13 +4,13 @@ error[E0080]: evaluation of `<Bar<u16, u8> as Foo>::AMT` failed
 LL |     const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-44578.rs:25:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-44578.rs:25:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
@@ -18,7 +18,7 @@ LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
    |
    = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-44578.rs:25:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
diff --git a/tests/ui/consts/const-eval/issue-50814-2.stderr b/tests/ui/consts/const-eval/issue-50814-2.stderr
index 956f7aec9da..450fb002373 100644
--- a/tests/ui/consts/const-eval/issue-50814-2.stderr
+++ b/tests/ui/consts/const-eval/issue-50814-2.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of `<A<()> as Foo<()>>::BAR` failed
 LL |     const BAR: usize = [5, 6, 7][T::BOO];
    |                        ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-50814-2.rs:18:6
    |
 LL |     &<A<T> as Foo<T>>::BAR
diff --git a/tests/ui/consts/const-eval/issue-50814.stderr b/tests/ui/consts/const-eval/issue-50814.stderr
index 05b6271f4e4..48a20d0bbd0 100644
--- a/tests/ui/consts/const-eval/issue-50814.stderr
+++ b/tests/ui/consts/const-eval/issue-50814.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of `<Sum<U8, U8> as Unsigned>::MAX` failed
 LL |     const MAX: u8 = A::MAX + B::MAX;
    |                     ^^^^^^^^^^^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-50814.rs:20:6
    |
 LL |     &Sum::<U8, U8>::MAX
diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs
index 1abe708d19e..88ce5b0d895 100644
--- a/tests/ui/consts/const-eval/panic-assoc-never-type.rs
+++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -11,5 +11,5 @@ impl PrintName {
 }
 
 fn main() {
-    let _ = PrintName::VOID; //~ erroneous constant used
+    let _ = PrintName::VOID; //~ erroneous constant encountered
 }
diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr
index 7c36a3a426e..4706497dbc4 100644
--- a/tests/ui/consts/const-eval/panic-assoc-never-type.stderr
+++ b/tests/ui/consts/const-eval/panic-assoc-never-type.stderr
@@ -6,13 +6,13 @@ LL |     const VOID: ! = panic!();
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/panic-assoc-never-type.rs:14:13
    |
 LL |     let _ = PrintName::VOID;
    |             ^^^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/panic-assoc-never-type.rs:14:13
    |
 LL |     let _ = PrintName::VOID;
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index e087a0ebec7..042e7eeb31e 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -341,7 +341,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/raw-bytes.rs:160:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
@@ -358,7 +358,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/raw-bytes.rs:166:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
@@ -375,7 +375,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran
                ╾ALLOC_ID╼                                     │ ╾──╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/raw-bytes.rs:170:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index 4c655161f79..8426a95055c 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -341,7 +341,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/raw-bytes.rs:160:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
@@ -358,7 +358,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/raw-bytes.rs:166:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
@@ -375,7 +375,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran
                ╾ALLOC_ID╼                         │ ╾──────╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/raw-bytes.rs:170:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index 0ee1e60877f..6d5c36cea7d 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -60,7 +60,7 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/ub-ref-ptr.rs:36:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
@@ -75,7 +75,7 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = 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
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/ub-ref-ptr.rs:39:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
index 02bbbf50435..d8add67fac1 100644
--- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -139,7 +139,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
                HEX_DUMP
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/ub-wide-ptr.rs:85:40
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
@@ -156,7 +156,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3
                HEX_DUMP
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/ub-wide-ptr.rs:92:42
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
@@ -173,7 +173,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran
                HEX_DUMP
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/ub-wide-ptr.rs:96:42
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr
index 9899c56c0ec..ce260300fc8 100644
--- a/tests/ui/consts/const-eval/union-const-eval-field.stderr
+++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr
@@ -4,13 +4,13 @@ error[E0080]: evaluation of constant value failed
 LL |     const FIELD3: Field3 = unsafe { UNION.field3 };
    |                                     ^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/union-const-eval-field.rs:31:5
    |
 LL |     FIELD3
    |     ^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/union-const-eval-field.rs:31:5
    |
 LL |     FIELD3
diff --git a/tests/ui/consts/const-float-bits-reject-conv.stderr b/tests/ui/consts/const-float-bits-reject-conv.stderr
index 7ad02252094..1511dab12b0 100644
--- a/tests/ui/consts/const-float-bits-reject-conv.stderr
+++ b/tests/ui/consts/const-float-bits-reject-conv.stderr
@@ -30,25 +30,25 @@ LL |     const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
    |                              ^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:35:34
    |
 LL |     const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
    |                                  ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:36:34
    |
 LL |     const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
    |                                  ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:42:34
    |
 LL |     const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
    |                                  ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:43:34
    |
 LL |     const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
@@ -86,25 +86,25 @@ LL |     const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
    |                              ^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:57:34
    |
 LL |     const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
    |                                  ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:58:34
    |
 LL |     const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
    |                                  ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:61:34
    |
 LL |     const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
    |                                  ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-float-bits-reject-conv.rs:62:34
    |
 LL |     const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
diff --git a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr
index d9208d0706a..b7b5b648c12 100644
--- a/tests/ui/consts/const-len-underflow-separate-spans.next.stderr
+++ b/tests/ui/consts/const-len-underflow-separate-spans.next.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL | const LEN: usize = ONE - TWO;
    |                    ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-len-underflow-separate-spans.rs:14:17
    |
 LL |     let a: [i8; LEN] = unimplemented!();
diff --git a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr
index d9208d0706a..b7b5b648c12 100644
--- a/tests/ui/consts/const-len-underflow-separate-spans.old.stderr
+++ b/tests/ui/consts/const-len-underflow-separate-spans.old.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL | const LEN: usize = ONE - TWO;
    |                    ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/const-len-underflow-separate-spans.rs:14:17
    |
 LL |     let a: [i8; LEN] = unimplemented!();
diff --git a/tests/ui/consts/invalid-union.32bit.stderr b/tests/ui/consts/invalid-union.32bit.stderr
index 0dd18a55786..b6cf060e5ae 100644
--- a/tests/ui/consts/invalid-union.32bit.stderr
+++ b/tests/ui/consts/invalid-union.32bit.stderr
@@ -9,13 +9,13 @@ LL | fn main() {
                ╾─alloc7──╼                                     │ ╾──╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/invalid-union.rs:43:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/invalid-union.rs:43:25
    |
 LL |     let _: &'static _ = &C;
diff --git a/tests/ui/consts/invalid-union.64bit.stderr b/tests/ui/consts/invalid-union.64bit.stderr
index 07f36ee2832..e3a3ef62c4a 100644
--- a/tests/ui/consts/invalid-union.64bit.stderr
+++ b/tests/ui/consts/invalid-union.64bit.stderr
@@ -9,13 +9,13 @@ LL | fn main() {
                ╾───────alloc7────────╼                         │ ╾──────╼
            }
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/invalid-union.rs:43:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/invalid-union.rs:43:25
    |
 LL |     let _: &'static _ = &C;
diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr
index 190b41062f8..6fcfe3ed28c 100644
--- a/tests/ui/consts/issue-36163.stderr
+++ b/tests/ui/consts/issue-36163.stderr
@@ -1,15 +1,25 @@
-error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{constant#0}`
+error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}`
   --> $DIR/issue-36163.rs:4:9
    |
 LL |     B = A,
    |         ^
    |
+note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`...
+  --> $DIR/issue-36163.rs:4:9
+   |
+LL |     B = A,
+   |         ^
+note: ...which requires simplifying constant for the type system `A`...
+  --> $DIR/issue-36163.rs:1:1
+   |
+LL | const A: isize = Foo::B as isize;
+   | ^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `A`...
   --> $DIR/issue-36163.rs:1:18
    |
 LL | const A: isize = Foo::B as isize;
    |                  ^^^^^^^^^^^^^^^
-   = note: ...which again requires const-evaluating + checking `Foo::B::{constant#0}`, completing the cycle
+   = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle
 note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}`
   --> $DIR/issue-36163.rs:4:9
    |
diff --git a/tests/ui/consts/miri_unleashed/assoc_const.stderr b/tests/ui/consts/miri_unleashed/assoc_const.stderr
index d97097d352a..274b1de7e7d 100644
--- a/tests/ui/consts/miri_unleashed/assoc_const.stderr
+++ b/tests/ui/consts/miri_unleashed/assoc_const.stderr
@@ -13,13 +13,13 @@ note: inside `<String as Bar<Vec<u32>, String>>::F`
 LL |     const F: u32 = (U::X, 42).1;
    |                               ^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/assoc_const.rs:29:13
    |
 LL |     let y = <String as Bar<Vec<u32>, String>>::F;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/assoc_const.rs:29:13
    |
 LL |     let y = <String as Bar<Vec<u32>, String>>::F;
diff --git a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr
index ae7b03fc9dd..c8e4cab4e71 100644
--- a/tests/ui/consts/miri_unleashed/assoc_const_2.stderr
+++ b/tests/ui/consts/miri_unleashed/assoc_const_2.stderr
@@ -4,13 +4,13 @@ error[E0080]: evaluation of `<std::string::String as Bar<std::string::String>>::
 LL |     const F: u32 = 100 / U::X;
    |                    ^^^^^^^^^^ attempt to divide `100_u32` by zero
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/assoc_const_2.rs:27:13
    |
 LL |     let y = <String as Bar<String>>::F;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/assoc_const_2.rs:27:13
    |
 LL |     let y = <String as Bar<String>>::F;
diff --git a/tests/ui/consts/uninhabited-const-issue-61744.stderr b/tests/ui/consts/uninhabited-const-issue-61744.stderr
index adefbf336c2..f48e6c4ce51 100644
--- a/tests/ui/consts/uninhabited-const-issue-61744.stderr
+++ b/tests/ui/consts/uninhabited-const-issue-61744.stderr
@@ -645,13 +645,13 @@ note: inside `<i32 as Const>::CONSTANT`
 LL |     const CONSTANT: i32 = unsafe { fake_type() };
    |                                    ^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/uninhabited-const-issue-61744.rs:18:10
    |
 LL |     dbg!(i32::CONSTANT);
    |          ^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/uninhabited-const-issue-61744.rs:18:10
    |
 LL |     dbg!(i32::CONSTANT);
diff --git a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs b/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs
index a686ed9c84e..b08e291621f 100644
--- a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs
+++ b/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs
@@ -1,12 +1,12 @@
 #[diagnostic::non_existing_attribute]
 //~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
-//~|WARNING unknown diagnostic attribute [unknown_diagnostic_attributes]
+//~|WARNING unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes]
 pub trait Bar {
 }
 
 #[diagnostic::non_existing_attribute(with_option = "foo")]
 //~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
-//~|WARNING unknown diagnostic attribute [unknown_diagnostic_attributes]
+//~|WARNING unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes]
 struct Foo;
 
 fn main() {
diff --git a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr b/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr
index 45c95cbb3c7..017d00e2c8e 100644
--- a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr
+++ b/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr
@@ -4,7 +4,7 @@ error[E0658]: `#[diagnostic]` attribute name space is experimental
 LL | #[diagnostic::non_existing_attribute]
    |   ^^^^^^^^^^
    |
-   = note: see issue #94785 <https://github.com/rust-lang/rust/issues/94785> for more information
+   = note: see issue #111996 <https://github.com/rust-lang/rust/issues/111996> for more information
    = help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
 
 error[E0658]: `#[diagnostic]` attribute name space is experimental
@@ -13,7 +13,7 @@ error[E0658]: `#[diagnostic]` attribute name space is experimental
 LL | #[diagnostic::non_existing_attribute(with_option = "foo")]
    |   ^^^^^^^^^^
    |
-   = note: see issue #94785 <https://github.com/rust-lang/rust/issues/94785> for more information
+   = note: see issue #111996 <https://github.com/rust-lang/rust/issues/111996> for more information
    = help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
 
 warning: unknown diagnostic attribute
@@ -22,7 +22,7 @@ warning: unknown diagnostic attribute
 LL | #[diagnostic::non_existing_attribute]
    |               ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(unknown_diagnostic_attributes)]` on by default
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: unknown diagnostic attribute
   --> $DIR/feature-gate-diagnostic_namespace.rs:7:15
diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
index 4f9b7ba2bcf..753077b365e 100644
--- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
+++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr
@@ -4,7 +4,7 @@ warning: unknown diagnostic attribute
 LL | #[diagnostic::non_existing_attribute]
    |               ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(unknown_diagnostic_attributes)]` on by default
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: unknown diagnostic attribute
   --> $DIR/non_existing_attributes_accepted.rs:8:15
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
new file mode 100644
index 00000000000..00fb59d14d7
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
@@ -0,0 +1,37 @@
+#![feature(diagnostic_namespace)]
+
+#[diagnostic::on_unimplemented(unsupported = "foo")]
+//~^WARN malformed `on_unimplemented` attribute
+//~|WARN malformed `on_unimplemented` attribute
+trait Foo {}
+
+#[diagnostic::on_unimplemented(message = "Baz")]
+//~^WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
+struct Bar {}
+
+#[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
+//~^WARN malformed `on_unimplemented` attribute
+//~|WARN malformed `on_unimplemented` attribute
+trait Baz {}
+
+#[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
+//~^WARN malformed `on_unimplemented` attribute
+//~|WARN malformed `on_unimplemented` attribute
+trait Boom {}
+
+#[diagnostic::on_unimplemented = "boom"]
+//~^WARN malformed `on_unimplemented` attribute
+trait Doom {}
+
+fn take_foo(_: impl Foo) {}
+fn take_baz(_: impl Baz) {}
+fn take_boom(_: impl Boom) {}
+
+fn main() {
+    take_foo(1_i32);
+    //~^ERROR the trait bound `i32: Foo` is not satisfied
+    take_baz(1_i32);
+    //~^ERROR Boom
+    take_boom(1_i32);
+    //~^ERROR Boom
+}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
new file mode 100644
index 00000000000..bb1b29ef248
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -0,0 +1,110 @@
+warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:8:1
+   |
+LL | #[diagnostic::on_unimplemented(message = "Baz")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
+   |
+LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
+   |                                ^^^^^^^^^^^^^^^^^^^
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
+   |
+LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
+   |                                                  ^^^^^^^^^^^^^^^^^^^
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
+   |
+LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1
+   |
+LL | #[diagnostic::on_unimplemented = "boom"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
+   |
+LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
+   |                                ^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14
+   |
+LL |     take_foo(1_i32);
+   |     -------- ^^^^^ the trait `Foo` is not implemented for `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
+note: required by a bound in `take_foo`
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^ required by this bound in `take_foo`
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
+   |
+LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
+   |                                                  ^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: Boom
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14
+   |
+LL |     take_baz(1_i32);
+   |     -------- ^^^^^ the trait `Baz` is not implemented for `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:1
+   |
+LL | trait Baz {}
+   | ^^^^^^^^^
+note: required by a bound in `take_baz`
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21
+   |
+LL | fn take_baz(_: impl Baz) {}
+   |                     ^^^ required by this bound in `take_baz`
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
+   |
+LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: Boom
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15
+   |
+LL |     take_boom(1_i32);
+   |     --------- ^^^^^ the trait `Boom` is not implemented for `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:1
+   |
+LL | trait Boom {}
+   | ^^^^^^^^^^
+note: required by a bound in `take_boom`
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22
+   |
+LL | fn take_boom(_: impl Boom) {}
+   |                      ^^^^ required by this bound in `take_boom`
+
+error: aborting due to 3 previous errors; 8 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs b/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs
new file mode 100644
index 00000000000..609a840c118
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs
@@ -0,0 +1,7 @@
+#[diagnostic::on_unimplemented(message = "Foo")]
+//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658]
+pub trait Bar {
+}
+
+fn main() {
+}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr
new file mode 100644
index 00000000000..21f02e3a73b
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `#[diagnostic]` attribute name space is experimental
+  --> $DIR/feature-gate-diagnostic_on_unimplemented.rs:1:3
+   |
+LL | #[diagnostic::on_unimplemented(message = "Foo")]
+   |   ^^^^^^^^^^
+   |
+   = note: see issue #111996 <https://github.com/rust-lang/rust/issues/111996> for more information
+   = help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs
new file mode 100644
index 00000000000..797edbc9ec5
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs
@@ -0,0 +1,11 @@
+#![feature(diagnostic_namespace)]
+
+#[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz")]
+trait Foo {}
+
+fn takes_foo(_: impl Foo) {}
+
+fn main() {
+    takes_foo(());
+    //~^ERROR Foo
+}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr
new file mode 100644
index 00000000000..549c7caa720
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr
@@ -0,0 +1,24 @@
+error[E0277]: Foo
+  --> $DIR/on_unimplemented_simple.rs:9:15
+   |
+LL |     takes_foo(());
+   |     --------- ^^ Bar
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo` is not implemented for `()`
+   = note: Baz
+help: this trait has no implementations, consider adding one
+  --> $DIR/on_unimplemented_simple.rs:4:1
+   |
+LL | trait Foo {}
+   | ^^^^^^^^^
+note: required by a bound in `takes_foo`
+  --> $DIR/on_unimplemented_simple.rs:6:22
+   |
+LL | fn takes_foo(_: impl Foo) {}
+   |                      ^^^ required by this bound in `takes_foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/error-codes/E0040.stderr b/tests/ui/error-codes/E0040.stderr
index 9fcda1a9385..839be79d28d 100644
--- a/tests/ui/error-codes/E0040.stderr
+++ b/tests/ui/error-codes/E0040.stderr
@@ -2,10 +2,12 @@ error[E0040]: explicit use of destructor method
   --> $DIR/E0040.rs:16:7
    |
 LL |     x.drop();
-   |     --^^^^--
-   |     | |
-   |     | explicit destructor calls not allowed
-   |     help: consider using `drop` function: `drop(x)`
+   |       ^^^^ explicit destructor calls not allowed
+   |
+help: consider using `drop` function
+   |
+LL |     drop(x);
+   |     +++++ ~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0054.stderr b/tests/ui/error-codes/E0054.stderr
index ea81f4476a7..0a4adabbaf6 100644
--- a/tests/ui/error-codes/E0054.stderr
+++ b/tests/ui/error-codes/E0054.stderr
@@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/E0054.rs:3:24
    |
 LL |     let x_is_nonzero = x as bool;
-   |                        ^^^^^^^^^ help: compare with zero instead: `x != 0`
+   |                        ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let x_is_nonzero = x != 0;
+   |                          ~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr
index 74a2bc8d768..9d75671c4e6 100644
--- a/tests/ui/error-festival.stderr
+++ b/tests/ui/error-festival.stderr
@@ -63,7 +63,12 @@ error[E0054]: cannot cast `{integer}` as `bool`
   --> $DIR/error-festival.rs:33:24
    |
 LL |     let x_is_nonzero = x as bool;
-   |                        ^^^^^^^^^ help: compare with zero instead: `x != 0`
+   |                        ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let x_is_nonzero = x != 0;
+   |                          ~~~~
 
 error[E0606]: casting `&u8` as `u32` is invalid
   --> $DIR/error-festival.rs:37:18
diff --git a/tests/ui/explicit/explicit-call-to-dtor.stderr b/tests/ui/explicit/explicit-call-to-dtor.stderr
index f3c9bf6cccd..f2e0b73b6c5 100644
--- a/tests/ui/explicit/explicit-call-to-dtor.stderr
+++ b/tests/ui/explicit/explicit-call-to-dtor.stderr
@@ -2,10 +2,12 @@ error[E0040]: explicit use of destructor method
   --> $DIR/explicit-call-to-dtor.rs:15:7
    |
 LL |     x.drop();
-   |     --^^^^--
-   |     | |
-   |     | explicit destructor calls not allowed
-   |     help: consider using `drop` function: `drop(x)`
+   |       ^^^^ explicit destructor calls not allowed
+   |
+help: consider using `drop` function
+   |
+LL |     drop(x);
+   |     +++++ ~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr
index c7067117349..5fa42fcf191 100644
--- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr
+++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr
@@ -2,10 +2,12 @@ error[E0040]: explicit use of destructor method
   --> $DIR/explicit-call-to-supertrait-dtor.rs:22:14
    |
 LL |         self.drop();
-   |         -----^^^^--
-   |         |    |
-   |         |    explicit destructor calls not allowed
-   |         help: consider using `drop` function: `drop(self)`
+   |              ^^^^ explicit destructor calls not allowed
+   |
+help: consider using `drop` function
+   |
+LL |         drop(self);
+   |         +++++    ~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/fmt/raw-idents.rs b/tests/ui/fmt/raw-idents.rs
new file mode 100644
index 00000000000..29a74c55a4a
--- /dev/null
+++ b/tests/ui/fmt/raw-idents.rs
@@ -0,0 +1,17 @@
+// Regression test for https://github.com/rust-lang/rust/issues/115466
+
+// The "identifier" in format strings is parsed as an IDENTIFIER_OR_KEYWORD, not an IDENTIFIER.
+// Test that there is an actionable diagnostic if a RAW_IDENTIFIER is used instead.
+
+fn main() {
+    let r#type = "foobar";
+    println!("It is {r#type}"); //~ ERROR: invalid format string: raw identifiers are not supported
+    println!(r##"It still is {r#type}"##); //~ ERROR: invalid format string: raw identifiers are not supported
+    println!(concat!("{r#", "type}")); //~ ERROR: invalid format string: raw identifiers are not supported
+    println!("{\x72\x23type:?}"); //~ ERROR: invalid format string: raw identifiers are not supported
+
+    // OK
+    println!("{type}");
+    println!("{let}", let = r#type);
+    println!("{let}", r#let = r#type);
+}
diff --git a/tests/ui/fmt/raw-idents.stderr b/tests/ui/fmt/raw-idents.stderr
new file mode 100644
index 00000000000..2ddc114d286
--- /dev/null
+++ b/tests/ui/fmt/raw-idents.stderr
@@ -0,0 +1,44 @@
+error: invalid format string: raw identifiers are not supported
+  --> $DIR/raw-idents.rs:8:22
+   |
+LL |     println!("It is {r#type}");
+   |                      --^^^^
+   |                      |
+   |                      raw identifier used here in format string
+   |                      help: remove the `r#`
+   |
+   = note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`
+
+error: invalid format string: raw identifiers are not supported
+  --> $DIR/raw-idents.rs:9:31
+   |
+LL |     println!(r##"It still is {r#type}"##);
+   |                               --^^^^
+   |                               |
+   |                               raw identifier used here in format string
+   |                               help: remove the `r#`
+   |
+   = note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`
+
+error: invalid format string: raw identifiers are not supported
+  --> $DIR/raw-idents.rs:10:14
+   |
+LL |     println!(concat!("{r#", "type}"));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^ raw identifier used here in format string
+   |
+   = note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: invalid format string: raw identifiers are not supported
+  --> $DIR/raw-idents.rs:11:16
+   |
+LL |     println!("{\x72\x23type:?}");
+   |                --------^^^^
+   |                |
+   |                raw identifier used here in format string
+   |                help: remove the `r#`
+   |
+   = note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/issues/issue-17252.stderr b/tests/ui/issues/issue-17252.stderr
index daaf82e80ad..32e20d77465 100644
--- a/tests/ui/issues/issue-17252.stderr
+++ b/tests/ui/issues/issue-17252.stderr
@@ -1,10 +1,15 @@
-error[E0391]: cycle detected when const-evaluating + checking `FOO`
+error[E0391]: cycle detected when simplifying constant for the type system `FOO`
+  --> $DIR/issue-17252.rs:1:1
+   |
+LL | const FOO: usize = FOO;
+   | ^^^^^^^^^^^^^^^^
+   |
+note: ...which requires const-evaluating + checking `FOO`...
   --> $DIR/issue-17252.rs:1:20
    |
 LL | const FOO: usize = FOO;
    |                    ^^^
-   |
-   = note: ...which immediately requires const-evaluating + checking `FOO` again
+   = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle
 note: cycle used when const-evaluating + checking `main::{constant#0}`
   --> $DIR/issue-17252.rs:4:18
    |
diff --git a/tests/ui/issues/issue-23302-1.stderr b/tests/ui/issues/issue-23302-1.stderr
index d807e24403e..d753bdeb9f7 100644
--- a/tests/ui/issues/issue-23302-1.stderr
+++ b/tests/ui/issues/issue-23302-1.stderr
@@ -1,10 +1,15 @@
-error[E0391]: cycle detected when const-evaluating + checking `X::A::{constant#0}`
+error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}`
   --> $DIR/issue-23302-1.rs:4:9
    |
 LL |     A = X::A as isize,
    |         ^^^^^^^^^^^^^
    |
-   = note: ...which immediately requires const-evaluating + checking `X::A::{constant#0}` again
+note: ...which requires const-evaluating + checking `X::A::{constant#0}`...
+  --> $DIR/issue-23302-1.rs:4:9
+   |
+LL |     A = X::A as isize,
+   |         ^^^^^^^^^^^^^
+   = note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle
 note: cycle used when simplifying constant for the type system `X::A::{constant#0}`
   --> $DIR/issue-23302-1.rs:4:9
    |
diff --git a/tests/ui/issues/issue-23302-2.stderr b/tests/ui/issues/issue-23302-2.stderr
index 91b39dba1ba..b756ee1d5e2 100644
--- a/tests/ui/issues/issue-23302-2.stderr
+++ b/tests/ui/issues/issue-23302-2.stderr
@@ -1,10 +1,15 @@
-error[E0391]: cycle detected when const-evaluating + checking `Y::A::{constant#0}`
+error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}`
   --> $DIR/issue-23302-2.rs:4:9
    |
 LL |     A = Y::B as isize,
    |         ^^^^^^^^^^^^^
    |
-   = note: ...which immediately requires const-evaluating + checking `Y::A::{constant#0}` again
+note: ...which requires const-evaluating + checking `Y::A::{constant#0}`...
+  --> $DIR/issue-23302-2.rs:4:9
+   |
+LL |     A = Y::B as isize,
+   |         ^^^^^^^^^^^^^
+   = note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle
 note: cycle used when simplifying constant for the type system `Y::A::{constant#0}`
   --> $DIR/issue-23302-2.rs:4:9
    |
diff --git a/tests/ui/issues/issue-23302-3.stderr b/tests/ui/issues/issue-23302-3.stderr
index 6b708d81f73..6cdc94551fe 100644
--- a/tests/ui/issues/issue-23302-3.stderr
+++ b/tests/ui/issues/issue-23302-3.stderr
@@ -1,15 +1,25 @@
-error[E0391]: cycle detected when const-evaluating + checking `A`
+error[E0391]: cycle detected when simplifying constant for the type system `A`
+  --> $DIR/issue-23302-3.rs:1:1
+   |
+LL | const A: i32 = B;
+   | ^^^^^^^^^^^^
+   |
+note: ...which requires const-evaluating + checking `A`...
   --> $DIR/issue-23302-3.rs:1:16
    |
 LL | const A: i32 = B;
    |                ^
+note: ...which requires simplifying constant for the type system `B`...
+  --> $DIR/issue-23302-3.rs:3:1
    |
+LL | const B: i32 = A;
+   | ^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `B`...
   --> $DIR/issue-23302-3.rs:3:16
    |
 LL | const B: i32 = A;
    |                ^
-   = note: ...which again requires const-evaluating + checking `A`, completing the cycle
+   = note: ...which again requires simplifying constant for the type system `A`, completing the cycle
 note: cycle used when simplifying constant for the type system `A`
   --> $DIR/issue-23302-3.rs:1:1
    |
diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
index ba385d887fb..6f9302bc4a5 100644
--- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
+++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
@@ -13,7 +13,7 @@ LL |     type MyA: TraitA;
 LL | impl TraitB for B {
    | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17
    |
 LL |     let _ = [0; B::VALUE];
diff --git a/tests/ui/limits/issue-55878.stderr b/tests/ui/limits/issue-55878.stderr
index f0c7210dde7..93716c0b347 100644
--- a/tests/ui/limits/issue-55878.stderr
+++ b/tests/ui/limits/issue-55878.stderr
@@ -11,7 +11,7 @@ note: inside `main`
 LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-55878.rs:7:26
    |
 LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
@@ -19,7 +19,7 @@ LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
    |
    = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-note: erroneous constant used
+note: erroneous constant encountered
   --> $DIR/issue-55878.rs:7:26
    |
 LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
diff --git a/tests/ui/lint/ptr_null_checks.rs b/tests/ui/lint/ptr_null_checks.rs
index e677ea3094d..3028084e962 100644
--- a/tests/ui/lint/ptr_null_checks.rs
+++ b/tests/ui/lint/ptr_null_checks.rs
@@ -38,15 +38,15 @@ fn main() {
     if (&mut 8 as *mut i32).is_null() {}
     //~^ WARN references are not nullable
     if ptr::from_mut(&mut 8).is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if (&8 as *const i32).is_null() {}
     //~^ WARN references are not nullable
     if ptr::from_ref(&8).is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if ptr::from_ref(&8).cast_mut().is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
-    //~^ WARN references are not nullable
+    //~^ WARN call is never null
     if (&8 as *const i32) == std::ptr::null() {}
     //~^ WARN references are not nullable
     let ref_num = &8;
@@ -65,6 +65,12 @@ fn main() {
     if (&*{ static_i32() } as *const i32).is_null() {}
     //~^ WARN references are not nullable
 
+    // ---------------- Functions -------------------
+    if ptr::NonNull::new(&mut 8).unwrap().as_ptr().is_null() {}
+    //~^ WARN call is never null
+    if ptr::NonNull::<u8>::dangling().as_ptr().is_null() {}
+    //~^ WARN call is never null
+
     // ----------------------------------------------
     const ZPTR: *const () = 0 as *const _;
     const NOT_ZPTR: *const () = 1 as *const _;
diff --git a/tests/ui/lint/ptr_null_checks.stderr b/tests/ui/lint/ptr_null_checks.stderr
index 3cee1804b62..0edc1b86536 100644
--- a/tests/ui/lint/ptr_null_checks.stderr
+++ b/tests/ui/lint/ptr_null_checks.stderr
@@ -117,13 +117,11 @@ LL |     if (&mut 8 as *mut i32).is_null() {}
    |         |
    |         expression has type `&mut i32`
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_mut` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:40:8
    |
 LL |     if ptr::from_mut(&mut 8).is_null() {}
-   |        ^^^^^^^^^^^^^^------^^^^^^^^^^^
-   |                      |
-   |                      expression has type `&mut i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: references are not nullable, so checking them for null will always return false
   --> $DIR/ptr_null_checks.rs:42:8
@@ -133,29 +131,23 @@ LL |     if (&8 as *const i32).is_null() {}
    |         |
    |         expression has type `&i32`
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:44:8
    |
 LL |     if ptr::from_ref(&8).is_null() {}
-   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^
-   |                      |
-   |                      expression has type `&i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:46:8
    |
 LL |     if ptr::from_ref(&8).cast_mut().is_null() {}
-   |        ^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^
-   |                      |
-   |                      expression has type `&i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: references are not nullable, so checking them for null will always return false
+warning: returned pointer of `from_ref` call is never null, so checking it for null will always return false
   --> $DIR/ptr_null_checks.rs:48:8
    |
 LL |     if (ptr::from_ref(&8).cast_mut() as *mut i32).is_null() {}
-   |        ^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                       |
-   |                       expression has type `&i32`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: references are not nullable, so checking them for null will always return false
   --> $DIR/ptr_null_checks.rs:50:8
@@ -221,5 +213,17 @@ LL |     if (&*{ static_i32() } as *const i32).is_null() {}
    |         |
    |         expression has type `&i32`
 
-warning: 25 warnings emitted
+warning: returned pointer of `as_ptr` call is never null, so checking it for null will always return false
+  --> $DIR/ptr_null_checks.rs:69:8
+   |
+LL |     if ptr::NonNull::new(&mut 8).unwrap().as_ptr().is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: returned pointer of `as_ptr` call is never null, so checking it for null will always return false
+  --> $DIR/ptr_null_checks.rs:71:8
+   |
+LL |     if ptr::NonNull::<u8>::dangling().as_ptr().is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 27 warnings emitted
 
diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr
index 0cea60746bf..d63cec48917 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.stderr
+++ b/tests/ui/mismatched_types/cast-rfc0401.stderr
@@ -86,7 +86,12 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-rfc0401.rs:39:13
    |
 LL |     let _ = 3_i32 as bool;
-   |             ^^^^^^^^^^^^^ help: compare with zero instead: `3_i32 != 0`
+   |             ^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 3_i32 != 0;
+   |                   ~~~~
 
 error[E0054]: cannot cast `E` as `bool`
   --> $DIR/cast-rfc0401.rs:40:13
diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr
index ecfc56961ee..96c1ffb2f7e 100644
--- a/tests/ui/range/range-1.stderr
+++ b/tests/ui/range/range-1.stderr
@@ -19,7 +19,7 @@ LL |     for i in false..true {}
              i64
              i128
              usize
-           and 6 others
+           and 8 others
    = note: required for `std::ops::Range<bool>` to implement `Iterator`
    = note: required for `std::ops::Range<bool>` to implement `IntoIterator`
 
diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.rs b/tests/ui/repr/repr-transparent-non-exhaustive.rs
index 506f1dcf3fc..84dd3f49239 100644
--- a/tests/ui/repr/repr-transparent-non-exhaustive.rs
+++ b/tests/ui/repr/repr-transparent-non-exhaustive.rs
@@ -93,4 +93,44 @@ pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
 //~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
 //~| WARN this was previously accepted by the compiler
 
+#[repr(transparent)]
+pub struct T17(NonExhaustive, Sized);
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T18(NonExhaustive, NonExhaustive);
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T19(NonExhaustive, Private);
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T19Flipped(Private, NonExhaustive);
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T20(NonExhaustive);
+// Okay, since it's the only field.
+
+#[repr(transparent)]
+pub struct T21(NonExhaustive, InternalNonExhaustive);
+// Okay, since there's only 1 foreign non-exhaustive type.
+
+#[repr(transparent)]
+pub struct T21Flipped(InternalNonExhaustive, NonExhaustive);
+// Okay, since there's only 1 foreign non-exhaustive type.
+
+#[repr(transparent)]
+pub struct T22(NonExhaustive, InternalPrivate);
+// Okay, since there's only 1 foreign non-exhaustive type.
+
+#[repr(transparent)]
+pub struct T22Flipped(InternalPrivate, NonExhaustive);
+// Okay, since there's only 1 foreign non-exhaustive type.
+
 fn main() {}
diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.stderr b/tests/ui/repr/repr-transparent-non-exhaustive.stderr
index 16edf59c7cc..808b9bc986d 100644
--- a/tests/ui/repr/repr-transparent-non-exhaustive.stderr
+++ b/tests/ui/repr/repr-transparent-non-exhaustive.stderr
@@ -123,5 +123,45 @@ LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
    = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
    = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
 
-error: aborting due to 12 previous errors
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:97:16
+   |
+LL | pub struct T17(NonExhaustive, Sized);
+   |                ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:102:31
+   |
+LL | pub struct T18(NonExhaustive, NonExhaustive);
+   |                               ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:107:31
+   |
+LL | pub struct T19(NonExhaustive, Private);
+   |                               ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:112:32
+   |
+LL | pub struct T19Flipped(Private, NonExhaustive);
+   |                                ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/repr/repr-transparent.rs b/tests/ui/repr/repr-transparent.rs
index 8c9d1639c0a..87cf59ce9af 100644
--- a/tests/ui/repr/repr-transparent.rs
+++ b/tests/ui/repr/repr-transparent.rs
@@ -23,23 +23,26 @@ struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
 struct ContainsZstAndNonZst((), [i32; 2]);
 
 #[repr(transparent)]
-struct MultipleNonZst(u8, u8); //~ ERROR needs at most one non-zero-sized field
+struct MultipleNonZst(u8, u8); //~ ERROR needs at most one field with non-trivial size or alignment
 
 trait Mirror { type It: ?Sized; }
 impl<T: ?Sized> Mirror for T { type It = Self; }
 
 #[repr(transparent)]
 pub struct StructWithProjection(f32, <f32 as Mirror>::It);
-//~^ ERROR needs at most one non-zero-sized field
+//~^ ERROR needs at most one field with non-trivial size or alignment
 
 #[repr(transparent)]
-struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1
+struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR needs at most one field with non-trivial size or alignment
 
 #[repr(align(32))]
 struct ZstAlign32<T>(PhantomData<T>);
 
 #[repr(transparent)]
-struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
+struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR needs at most one field with non-trivial size or alignment
+
+#[repr(transparent)]
+struct WrapsZstWithAlignment([i32; 0]);
 
 #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
 enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
@@ -58,7 +61,7 @@ enum UnitFieldEnum {
 enum TooManyFieldsEnum {
     Foo(u32, String),
 }
-//~^^^ ERROR transparent enum needs at most one non-zero-sized field, but has 2
+//~^^^ ERROR transparent enum needs at most one field with non-trivial size or alignment, but has 2
 
 #[repr(transparent)]
 enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
@@ -67,13 +70,13 @@ enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, bu
 }
 
 #[repr(transparent)]
-enum NontrivialAlignZstEnum {
-    Foo(u32, [u16; 0]), //~ ERROR alignment larger than 1
+enum NontrivialAlignZstEnum { //~ ERROR needs at most one field with non-trivial size or alignment
+    Foo(u32, [u16; 0]),
 }
 
 #[repr(transparent)]
-enum GenericAlignEnum<T> {
-    Foo { bar: ZstAlign32<T>, baz: u32 } //~ ERROR alignment larger than 1
+enum GenericAlignEnum<T> { //~ ERROR needs at most one field with non-trivial size or alignment
+    Foo { bar: ZstAlign32<T>, baz: u32 }
 }
 
 #[repr(transparent)]
@@ -82,7 +85,7 @@ union UnitUnion {
 }
 
 #[repr(transparent)]
-union TooManyFields { //~ ERROR transparent union needs at most one non-zero-sized field, but has 2
+union TooManyFields { //~ ERROR transparent union needs at most one field with non-trivial size or alignment, but has 2
     u: u32,
     s: i32
 }
diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr
index 028fc25db46..d0c78a8418a 100644
--- a/tests/ui/repr/repr-transparent.stderr
+++ b/tests/ui/repr/repr-transparent.stderr
@@ -1,35 +1,41 @@
-error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
+error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2
   --> $DIR/repr-transparent.rs:26:1
    |
 LL | struct MultipleNonZst(u8, u8);
-   | ^^^^^^^^^^^^^^^^^^^^^ --  -- this field is non-zero-sized
+   | ^^^^^^^^^^^^^^^^^^^^^ --  -- this field has non-zero size or requires alignment
    | |                     |
-   | |                     this field is non-zero-sized
-   | needs at most one non-zero-sized field, but has 2
+   | |                     this field has non-zero size or requires alignment
+   | needs at most one field with non-trivial size or alignment, but has 2
 
-error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
+error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2
   --> $DIR/repr-transparent.rs:32:1
    |
 LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---  ------------------- this field is non-zero-sized
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---  ------------------- this field has non-zero size or requires alignment
    | |                               |
-   | |                               this field is non-zero-sized
-   | needs at most one non-zero-sized field, but has 2
+   | |                               this field has non-zero size or requires alignment
+   | needs at most one field with non-trivial size or alignment, but has 2
 
-error[E0691]: zero-sized field in transparent struct has alignment larger than 1
-  --> $DIR/repr-transparent.rs:36:32
+error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/repr-transparent.rs:36:1
    |
 LL | struct NontrivialAlignZst(u32, [u16; 0]);
-   |                                ^^^^^^^^ has alignment of 2, which is larger than 1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ ---  -------- this field has non-zero size or requires alignment
+   | |                         |
+   | |                         this field has non-zero size or requires alignment
+   | needs at most one field with non-trivial size or alignment, but has 2
 
-error[E0691]: zero-sized field in transparent struct has alignment larger than 1
-  --> $DIR/repr-transparent.rs:42:24
+error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/repr-transparent.rs:42:1
    |
 LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
-   |                        ^^^^^^^^^^^^^ has alignment of 32, which is larger than 1
+   | ^^^^^^^^^^^^^^^^^^^^^^ -------------  --- this field has non-zero size or requires alignment
+   | |                      |
+   | |                      this field has non-zero size or requires alignment
+   | needs at most one field with non-trivial size or alignment, but has 2
 
 error[E0084]: unsupported representation for zero-variant enum
-  --> $DIR/repr-transparent.rs:44:1
+  --> $DIR/repr-transparent.rs:47:1
    |
 LL | #[repr(transparent)]
    | ^^^^^^^^^^^^^^^^^^^^
@@ -37,23 +43,23 @@ LL | enum Void {}
    | --------- zero-variant enum
 
 error[E0731]: transparent enum needs exactly one variant, but has 0
-  --> $DIR/repr-transparent.rs:45:1
+  --> $DIR/repr-transparent.rs:48:1
    |
 LL | enum Void {}
    | ^^^^^^^^^ needs exactly one variant, but has 0
 
-error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
-  --> $DIR/repr-transparent.rs:58:1
+error[E0690]: the variant of a transparent enum needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/repr-transparent.rs:61:1
    |
 LL | enum TooManyFieldsEnum {
-   | ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
+   | ^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2
 LL |     Foo(u32, String),
-   |         ---  ------ this field is non-zero-sized
+   |         ---  ------ this field has non-zero size or requires alignment
    |         |
-   |         this field is non-zero-sized
+   |         this field has non-zero size or requires alignment
 
 error[E0731]: transparent enum needs exactly one variant, but has 2
-  --> $DIR/repr-transparent.rs:64:1
+  --> $DIR/repr-transparent.rs:67:1
    |
 LL | enum MultipleVariants {
    | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
@@ -62,29 +68,37 @@ LL |     Foo(String),
 LL |     Bar,
    |     --- too many variants in `MultipleVariants`
 
-error[E0691]: zero-sized field in transparent enum has alignment larger than 1
-  --> $DIR/repr-transparent.rs:71:14
+error[E0690]: the variant of a transparent enum needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/repr-transparent.rs:73:1
    |
+LL | enum NontrivialAlignZstEnum {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2
 LL |     Foo(u32, [u16; 0]),
-   |              ^^^^^^^^ has alignment of 2, which is larger than 1
+   |         ---  -------- this field has non-zero size or requires alignment
+   |         |
+   |         this field has non-zero size or requires alignment
 
-error[E0691]: zero-sized field in transparent enum has alignment larger than 1
-  --> $DIR/repr-transparent.rs:76:11
+error[E0690]: the variant of a transparent enum needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/repr-transparent.rs:78:1
    |
+LL | enum GenericAlignEnum<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2
 LL |     Foo { bar: ZstAlign32<T>, baz: u32 }
-   |           ^^^^^^^^^^^^^^^^^^ has alignment of 32, which is larger than 1
+   |           ------------------  -------- this field has non-zero size or requires alignment
+   |           |
+   |           this field has non-zero size or requires alignment
 
-error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
-  --> $DIR/repr-transparent.rs:85:1
+error[E0690]: transparent union needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/repr-transparent.rs:88:1
    |
 LL | union TooManyFields {
-   | ^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
+   | ^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2
 LL |     u: u32,
-   |     ------ this field is non-zero-sized
+   |     ------ this field has non-zero size or requires alignment
 LL |     s: i32
-   |     ------ this field is non-zero-sized
+   |     ------ this field has non-zero size or requires alignment
 
 error: aborting due to 11 previous errors
 
-Some errors have detailed explanations: E0084, E0690, E0691, E0731.
+Some errors have detailed explanations: E0084, E0690, E0731.
 For more information about an error, try `rustc --explain E0084`.
diff --git a/tests/ui/span/send-is-not-static-std-sync.rs b/tests/ui/span/send-is-not-static-std-sync.rs
index f8ab5243c22..9c1ee287154 100644
--- a/tests/ui/span/send-is-not-static-std-sync.rs
+++ b/tests/ui/span/send-is-not-static-std-sync.rs
@@ -46,7 +46,7 @@ fn channel() {
         tx.send(&z).unwrap();
     }
     //~^^ ERROR `z` does not live long enough
-    // (channels lack #[may_dangle], thus their dtors are implicit uses of `z`)
+    tx.use_ref(); // (channel drop glue does not use `z` => needs explicit use)
 }
 
 fn main() {}
diff --git a/tests/ui/span/send-is-not-static-std-sync.stderr b/tests/ui/span/send-is-not-static-std-sync.stderr
index eaba415adaa..46534b39168 100644
--- a/tests/ui/span/send-is-not-static-std-sync.stderr
+++ b/tests/ui/span/send-is-not-static-std-sync.stderr
@@ -75,11 +75,9 @@ LL |         tx.send(&z).unwrap();
    |                 ^^ borrowed value does not live long enough
 LL |     }
    |     - `z` dropped here while still borrowed
-...
-LL | }
-   | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `Sender`
-   |
-   = note: values in a scope are dropped in the opposite order they are defined
+LL |
+LL |     tx.use_ref(); // (channel drop glue does not use `z` => needs explicit use)
+   |     -- borrow later used here
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout
index af7f2b67152..7bddc925996 100644
--- a/tests/ui/thir-print/thir-flat-const-variant.stdout
+++ b/tests/ui/thir-print/thir-flat-const-variant.stdout
@@ -1,11 +1,7 @@
 DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1):
 Thir {
     body_type: Const(
-        Adt(
-            Foo,
-            [
-            ],
-        ),
+        Foo,
     ),
     arms: [],
     blocks: [],
@@ -50,11 +46,7 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -68,11 +60,7 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -84,11 +72,7 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -102,11 +86,7 @@ Thir {
 DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2):
 Thir {
     body_type: Const(
-        Adt(
-            Foo,
-            [
-            ],
-        ),
+        Foo,
     ),
     arms: [],
     blocks: [],
@@ -151,11 +131,7 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -169,11 +145,7 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -185,11 +157,7 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -203,11 +171,7 @@ Thir {
 DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3):
 Thir {
     body_type: Const(
-        Adt(
-            Foo,
-            [
-            ],
-        ),
+        Foo,
     ),
     arms: [],
     blocks: [],
@@ -252,11 +216,7 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -270,11 +230,7 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -286,11 +242,7 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -304,11 +256,7 @@ Thir {
 DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4):
 Thir {
     body_type: Const(
-        Adt(
-            Foo,
-            [
-            ],
-        ),
+        Foo,
     ),
     arms: [],
     blocks: [],
@@ -353,11 +301,7 @@ Thir {
                     base: None,
                 },
             ),
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -371,11 +315,7 @@ Thir {
                 ),
                 value: e2,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
@@ -387,11 +327,7 @@ Thir {
                 lint_level: Inherited,
                 value: e3,
             },
-            ty: Adt(
-                Foo,
-                [
-                ],
-            ),
+            ty: Foo,
             temp_lifetime: Some(
                 Node(3),
             ),
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 0e21b98307b..3fc130f0176 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -1,13 +1,13 @@
 DefId(0:16 ~ thir_tree_match[fcf8]::has_match):
 params: [
     Param {
-        ty: Adt(Foo, [])
+        ty: Foo
         ty_span: Some($DIR/thir-tree-match.rs:15:19: 15:22 (#0))
         self_kind: None
         hir_id: Some(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).1))
         param: Some( 
             Pat: {
-                ty: Adt(Foo, [])
+                ty: Foo
                 span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
                 kind: PatKind {
                     Binding {
@@ -15,7 +15,7 @@ params: [
                         name: "foo"
                         mode: ByValue
                         var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2))
-                        ty: Adt(Foo, [])
+                        ty: Foo
                         is_primary: true
                         subpattern: None
                     }
@@ -73,7 +73,7 @@ body:
                                                                             Match {
                                                                                 scrutinee:
                                                                                     Expr {
-                                                                                        ty: Adt(Foo, [])
+                                                                                        ty: Foo
                                                                                         temp_lifetime: Some(Node(26))
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
@@ -82,7 +82,7 @@ body:
                                                                                                 lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
                                                                                                 value:
                                                                                                     Expr {
-                                                                                                        ty: Adt(Foo, [])
+                                                                                                        ty: Foo
                                                                                                         temp_lifetime: Some(Node(26))
                                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                                         kind: 
@@ -96,7 +96,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Adt(Foo, [])
+                                                                                                ty: Foo
                                                                                                 span: $DIR/thir-tree-match.rs:17:9: 17:32 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
@@ -110,7 +110,7 @@ body:
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
                                                                                                             Pat: {
-                                                                                                                ty: Adt(Bar, [])
+                                                                                                                ty: Bar
                                                                                                                 span: $DIR/thir-tree-match.rs:17:21: 17:31 (#0)
                                                                                                                 kind: PatKind {
                                                                                                                     Variant {
@@ -169,7 +169,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Adt(Foo, [])
+                                                                                                ty: Foo
                                                                                                 span: $DIR/thir-tree-match.rs:18:9: 18:23 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
@@ -183,7 +183,7 @@ body:
                                                                                                         variant_index: 0
                                                                                                         subpatterns: [
                                                                                                             Pat: {
-                                                                                                                ty: Adt(Bar, [])
+                                                                                                                ty: Bar
                                                                                                                 span: $DIR/thir-tree-match.rs:18:21: 18:22 (#0)
                                                                                                                 kind: PatKind {
                                                                                                                     Wild
@@ -232,7 +232,7 @@ body:
                                                                                     Arm {
                                                                                         pattern: 
                                                                                             Pat: {
-                                                                                                ty: Adt(Foo, [])
+                                                                                                ty: Foo
                                                                                                 span: $DIR/thir-tree-match.rs:19:9: 19:20 (#0)
                                                                                                 kind: PatKind {
                                                                                                     Variant {
diff --git a/triagebot.toml b/triagebot.toml
index d9d523bef39..5b4e653b100 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -585,7 +585,7 @@ cc = ["@nnethercote"]
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
-users_on_vacation = ["jyn514"]
+users_on_vacation = ["jyn514", "jackh726"]
 
 [assign.adhoc_groups]
 compiler-team = [
@@ -621,6 +621,7 @@ bootstrap = [
 ]
 infra-ci = [
     "@Mark-Simulacrum",
+    "@Kobzol",
 ]
 rustdoc = [
     "@jsha",