about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/pull_request_template.md10
-rw-r--r--.github/workflows/ci.yml3
-rw-r--r--.gitmodules6
-rw-r--r--Cargo.lock593
-rw-r--r--compiler/rustc_ast/src/ast.rs7
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs11
-rw-r--r--compiler/rustc_ast/src/ptr.rs2
-rw-r--r--compiler/rustc_ast_passes/messages.ftl5
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs23
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_attr/src/builtin.rs10
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/facts.rs27
-rw-r--r--compiler/rustc_borrowck/src/lib.rs3
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs3
-rw-r--r--compiler/rustc_borrowck/src/polonius/mod.rs10
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs18
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl2
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs36
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs14
-rw-r--r--compiler/rustc_const_eval/src/lib.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs29
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs9
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs6
-rw-r--r--compiler/rustc_expand/src/base.rs21
-rw-r--r--compiler/rustc_expand/src/config.rs9
-rw-r--r--compiler/rustc_expand/src/expand.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs24
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs6
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs15
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs104
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs75
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs144
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs (renamed from compiler/rustc_hir_typeck/src/method/prelude2021.rs)54
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs213
-rw-r--r--compiler/rustc_infer/messages.ftl5
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs161
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs44
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs81
-rw-r--r--compiler/rustc_interface/src/interface.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs69
-rw-r--r--compiler/rustc_lint/messages.ftl247
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs144
-rw-r--r--compiler/rustc_lint/src/builtin.rs21
-rw-r--r--compiler/rustc_lint/src/context.rs22
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs601
-rw-r--r--compiler/rustc_lint/src/context/diagnostics/check_cfg.rs329
-rw-r--r--compiler/rustc_lint/src/early.rs12
-rw-r--r--compiler/rustc_lint/src/lib.rs8
-rw-r--r--compiler/rustc_lint/src/lints.rs861
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs2
-rw-r--r--compiler/rustc_lint/src/shadowed_into_iter.rs157
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs21
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs116
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs16
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs12
-rw-r--r--compiler/rustc_macros/src/lib.rs6
-rw-r--r--compiler/rustc_metadata/messages.ftl2
-rw-r--r--compiler/rustc_metadata/src/creader.rs21
-rw-r--r--compiler/rustc_metadata/src/lib.rs17
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs25
-rw-r--r--compiler/rustc_middle/messages.ftl14
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs17
-rw-r--r--compiler/rustc_middle/src/lib.rs44
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs183
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs4
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs1
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs19
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs34
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs3
-rw-r--r--compiler/rustc_middle/src/traits/solve/cache.rs34
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs8
-rw-r--r--compiler/rustc_middle/src/ty/context.rs5
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs1
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs48
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/region.rs18
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs23
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs85
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs6
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs27
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs42
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs8
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs5
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs42
-rw-r--r--compiler/rustc_next_trait_solver/src/lib.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/resolve.rs83
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs8
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs3
-rw-r--r--compiler/rustc_parse/src/parser/item.rs12
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs32
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs146
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_passes/src/lang_items.rs5
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs86
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs12
-rw-r--r--compiler/rustc_resolve/src/ident.rs15
-rw-r--r--compiler/rustc_resolve/src/imports.rs22
-rw-r--r--compiler/rustc_resolve/src/late.rs20
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs109
-rw-r--r--compiler/rustc_resolve/src/lib.rs10
-rw-r--r--compiler/rustc_resolve/src/macros.rs63
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs20
-rw-r--r--compiler/rustc_session/src/session.rs14
-rw-r--r--compiler/rustc_session/src/version.rs13
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs29
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_target/src/spec/base/apple/mod.rs5
-rw-r--r--compiler/rustc_target/src/spec/mod.rs35
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs62
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs39
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs57
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs483
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs6
-rw-r--r--compiler/rustc_type_ir/src/debug.rs32
-rw-r--r--compiler/rustc_type_ir/src/generic_arg.rs14
-rw-r--r--compiler/rustc_type_ir/src/infcx.rs44
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs16
-rw-r--r--compiler/rustc_type_ir/src/interner.rs7
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs27
-rw-r--r--compiler/stable_mir/src/ty.rs1
-rw-r--r--library/alloc/Cargo.toml4
-rw-r--r--library/alloc/src/boxed.rs86
-rw-r--r--library/alloc/src/ffi/c_str.rs13
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/rc.rs75
-rw-r--r--library/alloc/src/sync.rs167
-rw-r--r--library/alloc/src/vec/in_place_collect.rs5
-rw-r--r--library/alloc/src/vec/into_iter.rs54
-rw-r--r--library/core/Cargo.toml2
-rw-r--r--library/core/src/array/iter.rs2
-rw-r--r--library/core/src/fmt/nofloat.rs1
-rw-r--r--library/core/src/intrinsics/simd.rs7
-rw-r--r--library/core/src/io/borrowed_buf.rs24
-rw-r--r--library/core/src/iter/traits/collect.rs3
-rw-r--r--library/core/src/slice/iter.rs3
-rw-r--r--library/portable-simd/crates/core_simd/src/ops.rs2
-rw-r--r--library/std/Cargo.toml8
-rw-r--r--library/std/src/io/cursor.rs27
-rw-r--r--library/std/src/io/impls.rs6
-rw-r--r--library/std/src/io/stdio.rs34
-rw-r--r--library/std/src/io/tests.rs32
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/hermit/mod.rs2
-rw-r--r--library/std/src/os/raw/tests.rs2
-rw-r--r--library/std/src/os/windows/process.rs49
-rw-r--r--library/std/src/path.rs9
-rw-r--r--library/std/src/process.rs48
-rw-r--r--library/std/src/sys/pal/hermit/alloc.rs10
-rw-r--r--library/std/src/sys/pal/hermit/fd.rs12
-rw-r--r--library/std/src/sys/pal/hermit/fs.rs51
-rw-r--r--library/std/src/sys/pal/hermit/futex.rs16
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs40
-rw-r--r--library/std/src/sys/pal/hermit/net.rs25
-rw-r--r--library/std/src/sys/pal/hermit/os.rs10
-rw-r--r--library/std/src/sys/pal/hermit/stdio.rs10
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs16
-rw-r--r--library/std/src/sys/pal/hermit/time.rs10
-rw-r--r--library/std/src/sys/pal/unix/args.rs238
-rw-r--r--library/std/src/sys/pal/unix/mod.rs11
-rw-r--r--library/std/src/sys/pal/unix/os.rs28
-rw-r--r--library/sysroot/Cargo.toml1
-rw-r--r--rustfmt.toml1
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs7
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/synthetic_targets.rs5
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs41
-rw-r--r--src/bootstrap/src/core/sanity.rs24
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile8
-rwxr-xr-xsrc/ci/docker/scripts/x86_64-gnu-llvm.sh4
-rw-r--r--src/ci/github-actions/jobs.yml48
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md18
-rw-r--r--src/doc/rustc/src/check-cfg/cargo-specifics.md73
-rw-r--r--src/doc/rustc/src/platform-support.md26
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md55
-rw-r--r--src/doc/rustc/src/platform-support/apple-darwin.md59
-rw-r--r--src/doc/rustc/src/platform-support/apple-ios-macabi.md58
-rw-r--r--src/doc/rustc/src/platform-support/apple-ios.md74
-rw-r--r--src/doc/rustc/src/platform-support/apple-tvos.md79
-rw-r--r--src/doc/rustc/src/platform-support/apple-visionos.md60
-rw-r--r--src/doc/rustc/src/platform-support/apple-watchos.md71
-rw-r--r--src/doc/rustc/src/platform-support/arm64e-apple-darwin.md2
-rw-r--r--src/doc/rustc/src/platform-support/arm64e-apple-ios.md3
-rw-r--r--src/doc/rustc/src/platform-support/i686-apple-darwin.md41
-rw-r--r--src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md5
-rw-r--r--src/librustdoc/passes/strip_aliased_non_local.rs9
m---------src/llvm-project0
m---------src/tools/cargo0
-rwxr-xr-xsrc/tools/clippy/.github/driver.sh19
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml6
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml4
-rw-r--r--src/tools/clippy/CHANGELOG.md7
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md42
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs31
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs3
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs570
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs14
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mod.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs95
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs129
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_float.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs256
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_filter.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs14
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs18
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs78
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs84
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs10
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr30
-rw-r--r--src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml8
-rw-r--r--src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs260
-rw-r--r--src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr187
-rw-r--r--src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs15
-rw-r--r--src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr17
-rw-r--r--src/tools/clippy/tests/ui-toml/panic/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/panic/panic.rs54
-rw-r--r--src/tools/clippy/tests/ui-toml/panic/panic.stderr11
-rw-r--r--src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr46
-rw-r--r--src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr34
-rw-r--r--src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs110
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs6
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr9
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.fixed26
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.rs26
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.stderr46
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed47
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs47
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr76
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed77
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.rs77
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr136
-rw-r--r--src/tools/clippy/tests/ui/duplicated_attributes.rs6
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.fixed11
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.rs11
-rw-r--r--src/tools/clippy/tests/ui/from_str_radix_10.stderr16
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.fixed1
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.rs1
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.stderr58
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.stderr122
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.fixed241
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.rs5
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.stderr257
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed61
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs1
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr18
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs18
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs28
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr30
-rw-r--r--src/tools/clippy/tests/ui/missing_panics_doc.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed42
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs36
-rw-r--r--src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr26
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.stderr177
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs13
-rw-r--r--src/tools/clippy/tests/ui/no_effect.stderr68
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs2
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs56
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr28
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed32
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs32
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr4
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.fixed43
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.rs43
-rw-r--r--src/tools/clippy/tests/ui/while_float.rs14
-rw-r--r--src/tools/clippy/tests/ui/while_float.stderr20
-rw-r--r--src/tools/clippy/util/gh-pages/script.js2
-rw-r--r--src/tools/compiletest/src/common.rs4
-rw-r--r--src/tools/compiletest/src/lib.rs2
-rw-r--r--src/tools/jsondoclint/src/validator.rs2
-rw-r--r--src/tools/lld-wrapper/src/main.rs2
-rw-r--r--src/tools/miri/cargo-miri/src/util.rs2
-rw-r--r--src/tools/miri/miri-script/src/commands.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs2
-rw-r--r--src/tools/miri/src/concurrency/thread.rs2
-rw-r--r--src/tools/miri/src/concurrency/weak_memory.rs2
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs2
-rw-r--r--src/tools/miri/src/machine.rs4
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs2
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs2
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs6
-rw-r--r--src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs2
-rw-r--r--src/tools/miri/tests/pass/intrinsics/portable-simd.rs15
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/opt-dist/src/main.rs55
-rwxr-xr-xsrc/tools/publish_toolstate.py3
-rw-r--r--src/tools/rust-analyzer/.git-blame-ignore-revs7
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml6
-rw-r--r--src/tools/rust-analyzer/.github/workflows/metrics.yaml39
-rw-r--r--src/tools/rust-analyzer/.github/workflows/rustdoc.yaml2
-rw-r--r--src/tools/rust-analyzer/Cargo.lock400
-rw-r--r--src/tools/rust-analyzer/Cargo.toml10
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/change.rs2
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs12
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/tests.rs30
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs84
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs84
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs118
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs111
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs90
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/eager.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs265
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs58
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs45
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs208
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs265
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs436
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs286
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs150
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs116
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs94
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs288
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs81
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs58
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs84
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs42
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs62
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs89
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs639
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs68
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html2
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/benchmark.rs3
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs70
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs9
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast457
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs20
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs10
-rw-r--r--src/tools/rust-analyzer/crates/profile/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/profile/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/profile/src/memory_usage.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs68
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs11
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/env.rs7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs23
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs16
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs14
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs36
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs68
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs535
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt18
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/build.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs9
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs14
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs35
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs56
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs100
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs29
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs101
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs125
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs228
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs1
-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.rs1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lru.rs6
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/revision.rs2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/process.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs3
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs101
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation/block.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs77
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/vfs/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/lib.rs121
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md20
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md2
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc24
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc4
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json31
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts16
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts1
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs28
-rw-r--r--src/tools/rust-analyzer/rust-version1
-rw-r--r--src/tools/rust-analyzer/xtask/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/xtask/src/flags.rs38
-rw-r--r--src/tools/rust-analyzer/xtask/src/main.rs3
-rw-r--r--src/tools/rust-analyzer/xtask/src/release.rs178
m---------src/tools/rustc-perf0
-rw-r--r--src/tools/tidy/config/black.toml1
-rw-r--r--src/tools/tidy/config/ruff.toml2
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt5
-rw-r--r--src/tools/tidy/src/deps.rs3
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--src/tools/tidy/src/walk.rs1
-rw-r--r--tests/codegen/array-cmp.rs18
-rw-r--r--tests/codegen/vec-in-place.rs22
-rw-r--r--tests/coverage/abort.cov-map42
-rw-r--r--tests/coverage/async.cov-map16
-rw-r--r--tests/coverage/async2.cov-map16
-rw-r--r--tests/coverage/async_block.cov-map16
-rw-r--r--tests/coverage/branch/generics.cov-map24
-rw-r--r--tests/coverage/branch/if-let.cov-map8
-rw-r--r--tests/coverage/branch/if.cov-map140
-rw-r--r--tests/coverage/branch/lazy-boolean.cov-map107
-rw-r--r--tests/coverage/branch/let-else.cov-map8
-rw-r--r--tests/coverage/branch/while.cov-map26
-rw-r--r--tests/coverage/closure.cov-map80
-rw-r--r--tests/coverage/closure_bug.cov-map109
-rw-r--r--tests/coverage/closure_macro.cov-map8
-rw-r--r--tests/coverage/closure_macro_async.cov-map8
-rw-r--r--tests/coverage/conditions.cov-map404
-rw-r--r--tests/coverage/coroutine.cov-map8
-rw-r--r--tests/coverage/dead_code.cov-map8
-rw-r--r--tests/coverage/drop_trait.cov-map8
-rw-r--r--tests/coverage/fn_sig_into_try.cov-map24
-rw-r--r--tests/coverage/generics.cov-map8
-rw-r--r--tests/coverage/if.cov-map8
-rw-r--r--tests/coverage/if_else.cov-map21
-rw-r--r--tests/coverage/if_not.cov-map38
-rw-r--r--tests/coverage/inline-dead.cov-map8
-rw-r--r--tests/coverage/inline.cov-map8
-rw-r--r--tests/coverage/inner_items.cov-map21
-rw-r--r--tests/coverage/issue-84561.cov-map167
-rw-r--r--tests/coverage/lazy_boolean.cov-map236
-rw-r--r--tests/coverage/loops_branches.cov-map240
-rw-r--r--tests/coverage/match_or_pattern.cov-map96
-rw-r--r--tests/coverage/no_cov_crate.cov-map16
-rw-r--r--tests/coverage/overflow.cov-map8
-rw-r--r--tests/coverage/simple_loop.cov-map23
-rw-r--r--tests/coverage/simple_match.cov-map35
-rw-r--r--tests/coverage/sort_groups.cov-map40
-rw-r--r--tests/coverage/try_error_result.cov-map32
-rw-r--r--tests/coverage/unicode.cov-map28
-rw-r--r--tests/coverage/uses_inline_crate.cov-map8
-rw-r--r--tests/coverage/while.cov-map8
-rw-r--r--tests/crashes/124833.rs10
-rw-r--r--tests/crashes/124857.rs11
-rw-r--r--tests/crashes/124891.rs22
-rw-r--r--tests/crashes/124894.rs11
-rw-r--r--tests/crashes/125081.rs7
-rw-r--r--tests/crashes/125099.rs24
-rw-r--r--tests/crashes/125155.rs17
-rw-r--r--tests/crashes/125185.rs16
-rw-r--r--tests/crashes/125249.rs8
-rw-r--r--tests/debuginfo/strings-and-strs.rs4
-rw-r--r--tests/incremental/foreign.rs27
-rw-r--r--tests/mir-opt/building/custom/operators.f.built.after.mir2
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff2
-rw-r--r--tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff2
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff6
-rw-r--r--tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff4
-rw-r--r--tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff12
-rw-r--r--tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff12
-rw-r--r--tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir2
-rw-r--r--tests/mir-opt/lower_intrinsics.rs6
-rw-r--r--tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff6
-rw-r--r--tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff6
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff2
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff2
-rw-r--r--tests/pretty/issue-4264.pp46
-rw-r--r--tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs5
-rw-r--r--tests/run-make/const_fn_mir/dump.mir4
-rw-r--r--tests/run-make/link-path-order/main.rs6
-rw-r--r--tests/run-make/no-intermediate-extras/Makefile8
-rw-r--r--tests/run-make/no-intermediate-extras/rmake.rs17
-rw-r--r--tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-scrape-examples-multiple/Makefile5
-rw-r--r--tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs6
-rw-r--r--tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk21
-rw-r--r--tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/scrape.rs3
-rw-r--r--tests/run-make/rustdoc-scrape-examples-test/Makefile6
-rw-r--r--tests/run-make/rustdoc-scrape-examples-test/rmake.rs6
-rw-r--r--tests/run-make/rustdoc-scrape-examples-whitespace/Makefile5
-rw-r--r--tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs6
-rw-r--r--tests/run-make/rustdoc-with-short-out-dir-option/Makefile8
-rw-r--r--tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs16
-rw-r--r--tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs5
-rw-r--r--tests/rustdoc/typedef-inner-variants.rs7
-rw-r--r--tests/ui/asm/empty_global_asm.rs (renamed from tests/ui/empty_global_asm.rs)0
-rw-r--r--tests/ui/asm/simple_global_asm.rs (renamed from tests/ui/simple_global_asm.rs)0
-rw-r--r--tests/ui/associated-types/associated-types-eq-2.rs2
-rw-r--r--tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr3
-rw-r--r--tests/ui/attributes/rustc_confusables_std_cases.stderr8
-rw-r--r--tests/ui/backtrace/apple-no-dsymutil.rs (renamed from tests/ui/backtrace-apple-no-dsymutil.rs)0
-rw-r--r--tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs (renamed from tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs)0
-rw-r--r--tests/ui/backtrace/auxiliary/dylib-dep-helper.rs (renamed from tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs)0
-rw-r--r--tests/ui/backtrace/auxiliary/line-tables-only-helper.rs (renamed from tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs)0
-rw-r--r--tests/ui/backtrace/backtrace.rs (renamed from tests/ui/backtrace.rs)0
-rw-r--r--tests/ui/backtrace/dylib-dep.rs (renamed from tests/ui/debuginfo/backtrace-dylib-dep.rs)0
-rw-r--r--tests/ui/backtrace/line-tables-only.rs (renamed from tests/ui/debuginfo/backtrace-line-tables-only.rs)0
-rw-r--r--tests/ui/backtrace/std-backtrace.rs (renamed from tests/ui/std-backtrace.rs)0
-rw-r--r--tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr8
-rw-r--r--tests/ui/check-cfg/allow-same-level.stderr2
-rw-r--r--tests/ui/check-cfg/cargo-feature.none.stderr22
-rw-r--r--tests/ui/check-cfg/cargo-feature.some.stderr22
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr2
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr2
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name.stderr2
-rw-r--r--tests/ui/check-cfg/compact-names.stderr2
-rw-r--r--tests/ui/check-cfg/compact-values.stderr2
-rw-r--r--tests/ui/check-cfg/concat-values.stderr4
-rw-r--r--tests/ui/check-cfg/diagnotics.cargo.stderr60
-rw-r--r--tests/ui/check-cfg/diagnotics.rs5
-rw-r--r--tests/ui/check-cfg/diagnotics.rustc.stderr26
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr2
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.feature.stderr2
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.full.stderr2
-rw-r--r--tests/ui/check-cfg/exhaustive-names.stderr2
-rw-r--r--tests/ui/check-cfg/mix.stderr4
-rw-r--r--tests/ui/check-cfg/stmt-no-ice.stderr2
-rw-r--r--tests/ui/check-cfg/unexpected-cfg-value.stderr4
-rw-r--r--tests/ui/check-cfg/well-known-names.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr32
-rw-r--r--tests/ui/closures/closure-return-type-mismatch.stderr3
-rw-r--r--tests/ui/coherence/associated-type2.rs2
-rw-r--r--tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs (renamed from tests/ui/auxiliary/orphan-check-diagnostics.rs)0
-rw-r--r--tests/ui/coherence/orphan-check-diagnostics.rs (renamed from tests/ui/orphan-check-diagnostics.rs)0
-rw-r--r--tests/ui/coherence/orphan-check-diagnostics.stderr (renamed from tests/ui/orphan-check-diagnostics.stderr)0
-rw-r--r--tests/ui/coroutine/static-move-suggestion.fixed19
-rw-r--r--tests/ui/coroutine/static-move-suggestion.rs19
-rw-r--r--tests/ui/coroutine/static-move-suggestion.stderr26
-rw-r--r--tests/ui/cross-crate/address-insignificant.rs (renamed from tests/ui/cross-crate/xcrate-address-insignificant.rs)0
-rw-r--r--tests/ui/cross-crate/associated-type-defaults.rs (renamed from tests/ui/cross-crate/xcrate-associated-type-defaults.rs)0
-rw-r--r--tests/ui/cross-crate/auxiliary/static_priv_by_default.rs (renamed from tests/ui/xcrate/auxiliary/static_priv_by_default.rs)0
-rw-r--r--tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs (renamed from tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs)0
-rw-r--r--tests/ui/cross-crate/generic_fn_nested_return.rs (renamed from tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs)0
-rw-r--r--tests/ui/cross-crate/private-by-default.rs (renamed from tests/ui/xcrate/xcrate-private-by-default.rs)0
-rw-r--r--tests/ui/cross-crate/private-by-default.stderr (renamed from tests/ui/xcrate/xcrate-private-by-default.stderr)20
-rw-r--r--tests/ui/cross-crate/static-addresses.rs (renamed from tests/ui/cross-crate/xcrate-static-addresses.rs)0
-rw-r--r--tests/ui/cross-crate/trait-lifetime-param.rs (renamed from tests/ui/cross-crate/xcrate-trait-lifetime-param.rs)0
-rw-r--r--tests/ui/cross-crate/unit-struct-2.rs (renamed from tests/ui/xcrate/xcrate-unit-struct-2.rs)0
-rw-r--r--tests/ui/cross-crate/unit-struct.rs (renamed from tests/ui/xcrate/xcrate-unit-struct.rs)0
-rw-r--r--tests/ui/cross-crate/unit-struct.stderr (renamed from tests/ui/xcrate/xcrate-unit-struct.stderr)4
-rw-r--r--tests/ui/derives/deriving-with-repr-packed-2.stderr8
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr12
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr21
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs60
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs (renamed from tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs)14
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr15
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs39
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr52
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr11
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.rs7
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr15
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr15
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs21
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs8
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr14
-rw-r--r--tests/ui/error-codes/E0259.rs4
-rw-r--r--tests/ui/error-codes/E0259.stderr4
-rw-r--r--tests/ui/expr/block-fn.rs (renamed from tests/ui/expr-block-fn.rs)0
-rw-r--r--tests/ui/expr/block-generic.rs (renamed from tests/ui/expr-block-generic.rs)0
-rw-r--r--tests/ui/expr/block.rs (renamed from tests/ui/expr-block.rs)0
-rw-r--r--tests/ui/expr/copy.rs (renamed from tests/ui/expr-copy.rs)0
-rw-r--r--tests/ui/expr/if-generic.rs (renamed from tests/ui/expr-if-generic.rs)0
-rw-r--r--tests/ui/expr/if-panic-all.rs (renamed from tests/ui/expr-if-panic-all.rs)0
-rw-r--r--tests/ui/expr/scope.rs (renamed from tests/ui/expr-scope.rs)0
-rw-r--r--tests/ui/feature-gates/feature-gate-global-registration.rs3
-rw-r--r--tests/ui/feature-gates/feature-gate-global-registration.stderr13
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs2
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr2
-rw-r--r--tests/ui/feature-gates/rustc-private.rs2
-rw-r--r--tests/ui/feature-gates/rustc-private.stderr4
-rw-r--r--tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs (renamed from tests/ui/stmt_expr_attrs_no_feature.rs)0
-rw-r--r--tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr (renamed from tests/ui/stmt_expr_attrs_no_feature.stderr)0
-rw-r--r--tests/ui/ffi-attrs/ffi_const.rs (renamed from tests/ui/ffi_const.rs)0
-rw-r--r--tests/ui/ffi-attrs/ffi_const.stderr (renamed from tests/ui/ffi_const.stderr)0
-rw-r--r--tests/ui/ffi-attrs/ffi_const2.rs (renamed from tests/ui/ffi_const2.rs)0
-rw-r--r--tests/ui/ffi-attrs/ffi_const2.stderr (renamed from tests/ui/ffi_const2.stderr)0
-rw-r--r--tests/ui/ffi-attrs/ffi_pure.rs (renamed from tests/ui/ffi_pure.rs)0
-rw-r--r--tests/ui/ffi-attrs/ffi_pure.stderr (renamed from tests/ui/ffi_pure.stderr)0
-rw-r--r--tests/ui/fn-main/wrong-location.rs (renamed from tests/ui/main-wrong-location.rs)0
-rw-r--r--tests/ui/fn-main/wrong-location.stderr (renamed from tests/ui/main-wrong-location.stderr)8
-rw-r--r--tests/ui/fn-main/wrong-type.rs (renamed from tests/ui/main-wrong-type.rs)0
-rw-r--r--tests/ui/fn-main/wrong-type.stderr (renamed from tests/ui/main-wrong-type.stderr)2
-rw-r--r--tests/ui/foreign/foreign-fn-linkname.rs10
-rw-r--r--tests/ui/foreign/foreign-fn-return-lifetime.rs (renamed from tests/ui/foreign-fn-return-lifetime.rs)0
-rw-r--r--tests/ui/foreign/foreign-fn-return-lifetime.stderr (renamed from tests/ui/foreign-fn-return-lifetime.stderr)0
-rw-r--r--tests/ui/foreign/foreign2.rs30
-rw-r--r--tests/ui/fuel/optimization-fuel-0.rs (renamed from tests/ui/optimization-fuel-0.rs)0
-rw-r--r--tests/ui/fuel/optimization-fuel-0.stderr (renamed from tests/ui/optimization-fuel-0.stderr)0
-rw-r--r--tests/ui/fuel/optimization-fuel-1.rs (renamed from tests/ui/optimization-fuel-1.rs)0
-rw-r--r--tests/ui/fuel/optimization-fuel-1.stderr (renamed from tests/ui/optimization-fuel-1.stderr)0
-rw-r--r--tests/ui/fuel/print-fuel.rs (renamed from tests/ui/print-fuel/print-fuel.rs)0
-rw-r--r--tests/ui/fuel/print-fuel.stderr (renamed from tests/ui/print-fuel/print-fuel.stderr)0
-rw-r--r--tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs28
-rw-r--r--tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr92
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs2
-rw-r--r--tests/ui/impl-trait/issue-99914.stderr4
-rw-r--r--tests/ui/imports/issue-37887.rs4
-rw-r--r--tests/ui/imports/issue-37887.stderr16
-rw-r--r--tests/ui/inference/infer-fn-tail-expr.rs (renamed from tests/ui/infer-fn-tail-expr.rs)0
-rw-r--r--tests/ui/inference/lambda-infer-unresolved.rs (renamed from tests/ui/lambda-infer-unresolved.rs)0
-rw-r--r--tests/ui/inference/order-dependent-cast-inference.rs (renamed from tests/ui/order-dependent-cast-inference.rs)0
-rw-r--r--tests/ui/inference/order-dependent-cast-inference.stderr (renamed from tests/ui/order-dependent-cast-inference.stderr)0
-rw-r--r--tests/ui/intrinsics/always-extern.rs (renamed from tests/ui/intrinsics-always-extern.rs)0
-rw-r--r--tests/ui/intrinsics/always-extern.stderr (renamed from tests/ui/intrinsics-always-extern.stderr)8
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.rs (renamed from tests/ui/reify-intrinsic.rs)0
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.stderr (renamed from tests/ui/reify-intrinsic.stderr)0
-rw-r--r--tests/ui/iterators/into-iter-on-arrays-2018.stderr10
-rw-r--r--tests/ui/iterators/into-iter-on-arrays-lint.stderr24
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-2021.rs46
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr60
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-2024.rs20
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed30
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-lint.rs30
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr35
-rw-r--r--tests/ui/lifetimes/issue-17728.stderr4
-rw-r--r--tests/ui/lifetimes/issue-90170-elision-mismatch.stderr2
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed14
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs17
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr20
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr5
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed14
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs14
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr20
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr6
-rw-r--r--tests/ui/lint/anonymous-reexport.stderr2
-rw-r--r--tests/ui/lint/group-denied-lint-allowed.rs (renamed from tests/ui/lint-group-denied-lint-allowed.rs)0
-rw-r--r--tests/ui/lint/group-forbid-always-trumps-cli.rs (renamed from tests/ui/lint-group-forbid-always-trumps-cli.rs)0
-rw-r--r--tests/ui/lint/group-forbid-always-trumps-cli.stderr (renamed from tests/ui/lint-group-forbid-always-trumps-cli.stderr)2
-rw-r--r--tests/ui/lint/unknown-lints-at-crate-level.rs (renamed from tests/ui/lint-unknown-lints-at-crate-level.rs)0
-rw-r--r--tests/ui/lint/unnecessary-extern-crate.rs14
-rw-r--r--tests/ui/lint/unnecessary-extern-crate.stderr12
-rw-r--r--tests/ui/lint/unused/import_remove_line.stderr2
-rw-r--r--tests/ui/lint/unused/lint-unused-imports.rs2
-rw-r--r--tests/ui/lint/unused/lint-unused-imports.stderr2
-rw-r--r--tests/ui/macros/compile_error_macro.rs (renamed from tests/ui/compile_error_macro.rs)0
-rw-r--r--tests/ui/macros/compile_error_macro.stderr (renamed from tests/ui/compile_error_macro.stderr)0
-rw-r--r--tests/ui/macros/module-macro_use-arguments.rs (renamed from tests/ui/module-macro_use-arguments.rs)0
-rw-r--r--tests/ui/macros/module-macro_use-arguments.stderr (renamed from tests/ui/module-macro_use-arguments.stderr)0
-rw-r--r--tests/ui/macros/no-patterns-in-args-macro.rs (renamed from tests/ui/no-patterns-in-args-macro.rs)0
-rw-r--r--tests/ui/macros/no-patterns-in-args-macro.stderr (renamed from tests/ui/no-patterns-in-args-macro.stderr)0
-rw-r--r--tests/ui/malformed/malformed-regressions.rs6
-rw-r--r--tests/ui/malformed/malformed-regressions.stderr6
-rw-r--r--tests/ui/match/issue-82392.stdout14
-rw-r--r--tests/ui/meta/no_std-extern-libc.rs1
-rw-r--r--tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs7
-rw-r--r--tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr17
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs10
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr38
-rw-r--r--tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs6
-rw-r--r--tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr8
-rw-r--r--tests/ui/parser/issues/issue-49040.rs2
-rw-r--r--tests/ui/parser/issues/issue-49040.stderr6
-rw-r--r--tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs5
-rw-r--r--tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr10
-rw-r--r--tests/ui/parser/label-is-actually-char.rs2
-rw-r--r--tests/ui/parser/super-fast-paren-parsing.rs (renamed from tests/ui/super-fast-paren-parsing.rs)5
-rw-r--r--tests/ui/pattern/by-move-pattern-binding.rs (renamed from tests/ui/by-move-pattern-binding.rs)0
-rw-r--r--tests/ui/pattern/by-move-pattern-binding.stderr (renamed from tests/ui/by-move-pattern-binding.stderr)0
-rw-r--r--tests/ui/pattern/fn-in-pat.rs (renamed from tests/ui/fn-in-pat.rs)0
-rw-r--r--tests/ui/pattern/fn-in-pat.stderr (renamed from tests/ui/fn-in-pat.stderr)0
-rw-r--r--tests/ui/pattern/inc-range-pat.rs (renamed from tests/ui/inc-range-pat.rs)0
-rw-r--r--tests/ui/pattern/no-patterns-in-args-2.rs (renamed from tests/ui/no-patterns-in-args-2.rs)0
-rw-r--r--tests/ui/pattern/no-patterns-in-args-2.stderr (renamed from tests/ui/no-patterns-in-args-2.stderr)0
-rw-r--r--tests/ui/pattern/no-patterns-in-args.rs (renamed from tests/ui/no-patterns-in-args.rs)0
-rw-r--r--tests/ui/pattern/no-patterns-in-args.stderr (renamed from tests/ui/no-patterns-in-args.stderr)0
-rw-r--r--tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs2
-rw-r--r--tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr2
-rw-r--r--tests/ui/process/env-args-reverse-iterator.rs (renamed from tests/ui/env-args-reverse-iterator.rs)0
-rw-r--r--tests/ui/process/env-funky-keys.rs (renamed from tests/ui/env-funky-keys.rs)0
-rw-r--r--tests/ui/process/env-null-vars.rs (renamed from tests/ui/env-null-vars.rs)14
-rw-r--r--tests/ui/process/env-vars.rs (renamed from tests/ui/env-vars.rs)0
-rw-r--r--tests/ui/process/exec-env.rs (renamed from tests/ui/exec-env.rs)0
-rw-r--r--tests/ui/process/inherit-env.rs (renamed from tests/ui/inherit-env.rs)0
-rw-r--r--tests/ui/process/no-stdio.rs8
-rw-r--r--tests/ui/range/impossible_range.fixed (renamed from tests/ui/impossible_range.fixed)0
-rw-r--r--tests/ui/range/impossible_range.rs (renamed from tests/ui/impossible_range.rs)0
-rw-r--r--tests/ui/range/impossible_range.stderr (renamed from tests/ui/impossible_range.stderr)0
-rw-r--r--tests/ui/range/range_inclusive.rs (renamed from tests/ui/range_inclusive.rs)0
-rw-r--r--tests/ui/repr/conflicting-repr-hints.rs (renamed from tests/ui/conflicting-repr-hints.rs)0
-rw-r--r--tests/ui/repr/conflicting-repr-hints.stderr (renamed from tests/ui/conflicting-repr-hints.stderr)0
-rw-r--r--tests/ui/return/ret-bang.rs (renamed from tests/ui/ret-bang.rs)0
-rw-r--r--tests/ui/return/ret-non-nil.rs (renamed from tests/ui/ret-non-nil.rs)0
-rw-r--r--tests/ui/return/ret-non-nil.stderr (renamed from tests/ui/ret-non-nil.stderr)0
-rw-r--r--tests/ui/return/return-disjoint-regions.rs (renamed from tests/ui/return-disjoint-regions.rs)0
-rw-r--r--tests/ui/return/return-disjoint-regions.stderr (renamed from tests/ui/return-disjoint-regions.stderr)0
-rw-r--r--tests/ui/return/return-nil.rs (renamed from tests/ui/return-nil.rs)0
-rw-r--r--tests/ui/return/tail-expr-if-as-return.rs5
-rw-r--r--tests/ui/return/tail-expr-if-as-return.stderr12
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr25
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs45
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr50
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs10
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr13
-rw-r--r--tests/ui/runtime/on-broken-pipe/error.rs1
-rw-r--r--tests/ui/runtime/on-broken-pipe/inherit.rs1
-rw-r--r--tests/ui/runtime/on-broken-pipe/kill.rs1
-rw-r--r--tests/ui/runtime/on-broken-pipe/not-used.rs1
-rw-r--r--tests/ui/runtime/on-broken-pipe/with-rustc_main.rs1
-rw-r--r--tests/ui/runtime/out-of-stack.rs7
-rw-r--r--tests/ui/runtime/stdout-during-shutdown-unix.rs (renamed from tests/ui/runtime/stdout-during-shutdown.rs)1
-rw-r--r--tests/ui/runtime/stdout-during-shutdown-unix.run.stdout (renamed from tests/ui/runtime/stdout-during-shutdown.run.stdout)0
-rw-r--r--tests/ui/runtime/stdout-during-shutdown-windows.rs20
-rw-r--r--tests/ui/runtime/stdout-during-shutdown-windows.run.stdout1
-rw-r--r--tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed27
-rw-r--r--tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs27
-rw-r--r--tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr15
-rw-r--r--tests/ui/rustc-env/README.md6
-rw-r--r--tests/ui/rustc-env/auxiliary/rust-log-aux.rs (renamed from tests/ui/auxiliary/rustc-rust-log-aux.rs)0
-rw-r--r--tests/ui/rustc-env/min-stack-banana.rs2
-rw-r--r--tests/ui/rustc-env/min-stack-banana.stderr4
-rw-r--r--tests/ui/rustc-env/rust-log.rs (renamed from tests/ui/rustc-rust-log.rs)2
-rw-r--r--tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr6
-rw-r--r--tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr6
-rw-r--r--tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr5
-rw-r--r--tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs18
-rw-r--r--tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr43
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.fixed47
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.rs10
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.stderr24
-rw-r--r--tests/ui/self/elision/lt-ref-self.fixed46
-rw-r--r--tests/ui/self/elision/lt-ref-self.rs9
-rw-r--r--tests/ui/self/elision/lt-ref-self.stderr36
-rw-r--r--tests/ui/self/elision/ref-mut-self.fixed44
-rw-r--r--tests/ui/self/elision/ref-mut-self.rs7
-rw-r--r--tests/ui/self/elision/ref-mut-self.stderr36
-rw-r--r--tests/ui/self/elision/ref-mut-struct.fixed37
-rw-r--r--tests/ui/self/elision/ref-mut-struct.rs7
-rw-r--r--tests/ui/self/elision/ref-mut-struct.stderr30
-rw-r--r--tests/ui/self/elision/ref-self.fixed61
-rw-r--r--tests/ui/self/elision/ref-self.rs11
-rw-r--r--tests/ui/self/elision/ref-self.stderr42
-rw-r--r--tests/ui/self/elision/ref-struct.fixed37
-rw-r--r--tests/ui/self/elision/ref-struct.rs7
-rw-r--r--tests/ui/self/elision/ref-struct.stderr30
-rw-r--r--tests/ui/simd/intrinsic/generic-arithmetic-2.rs23
-rw-r--r--tests/ui/simd/intrinsic/generic-arithmetic-2.stderr26
-rw-r--r--tests/ui/simd/intrinsic/generic-arithmetic-pass.rs10
-rw-r--r--tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr4
-rw-r--r--tests/ui/span/multispan-import-lint.stderr2
-rw-r--r--tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs (renamed from tests/ui/auxiliary/check_static_recursion_foreign_helper.rs)0
-rw-r--r--tests/ui/statics/check-immutable-mut-slices.rs (renamed from tests/ui/check-static-immutable-mut-slices.rs)0
-rw-r--r--tests/ui/statics/check-immutable-mut-slices.stderr (renamed from tests/ui/check-static-immutable-mut-slices.stderr)2
-rw-r--r--tests/ui/statics/check-recursion-foreign.rs (renamed from tests/ui/check-static-recursion-foreign.rs)0
-rw-r--r--tests/ui/statics/check-values-constraints.rs (renamed from tests/ui/check-static-values-constraints.rs)0
-rw-r--r--tests/ui/statics/check-values-constraints.stderr (renamed from tests/ui/check-static-values-constraints.stderr)34
-rw-r--r--tests/ui/suggestions/dont-suggest-private-trait-method.rs (renamed from tests/ui/dont-suggest-private-trait-method.rs)0
-rw-r--r--tests/ui/suggestions/dont-suggest-private-trait-method.stderr (renamed from tests/ui/dont-suggest-private-trait-method.stderr)0
-rw-r--r--tests/ui/suggestions/suggest-null-ptr.fixed (renamed from tests/ui/suggest-null-ptr.fixed)0
-rw-r--r--tests/ui/suggestions/suggest-null-ptr.rs (renamed from tests/ui/suggest-null-ptr.rs)0
-rw-r--r--tests/ui/suggestions/suggest-null-ptr.stderr (renamed from tests/ui/suggest-null-ptr.stderr)0
-rw-r--r--tests/ui/suggestions/trait-impl-bound-suggestions.fixed (renamed from tests/ui/trait-impl-bound-suggestions.fixed)0
-rw-r--r--tests/ui/suggestions/trait-impl-bound-suggestions.rs (renamed from tests/ui/trait-impl-bound-suggestions.rs)0
-rw-r--r--tests/ui/suggestions/trait-impl-bound-suggestions.stderr (renamed from tests/ui/trait-impl-bound-suggestions.stderr)0
-rw-r--r--tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs1
-rw-r--r--tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr17
-rw-r--r--tests/ui/suggestions/unused-imports.stderr4
-rw-r--r--tests/ui/tool-attributes/tool_lints-fail.rs (renamed from tests/ui/tool_lints-fail.rs)0
-rw-r--r--tests/ui/tool-attributes/tool_lints-fail.stderr (renamed from tests/ui/tool_lints-fail.stderr)0
-rw-r--r--tests/ui/tool-attributes/tool_lints-rpass.rs (renamed from tests/ui/tool_lints-rpass.rs)0
-rw-r--r--tests/ui/tool-attributes/tool_lints.rs (renamed from tests/ui/tool_lints.rs)0
-rw-r--r--tests/ui/tool-attributes/tool_lints.stderr (renamed from tests/ui/tool_lints.stderr)0
-rw-r--r--tests/ui/tool-attributes/tool_lints_2018_preview.rs (renamed from tests/ui/tool_lints_2018_preview.rs)0
-rw-r--r--tests/ui/tool-attributes/unknown-lint-tool-name.rs (renamed from tests/ui/unknown-lint-tool-name.rs)0
-rw-r--r--tests/ui/tool-attributes/unknown-lint-tool-name.stderr (renamed from tests/ui/unknown-lint-tool-name.stderr)0
-rw-r--r--tests/ui/tool-attributes/unknown-tool-name.rs (renamed from tests/ui/unknown-tool-name.rs)0
-rw-r--r--tests/ui/tool-attributes/unknown-tool-name.stderr (renamed from tests/ui/unknown-tool-name.stderr)0
-rw-r--r--tests/ui/traits/method-on-unbounded-type-param.stderr4
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr (renamed from tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr)6
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr26
-rw-r--r--tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-60662.stdout4
-rw-r--r--tests/ui/typeck/issue-81943.stderr26
-rw-r--r--tests/ui/unop/unop-move-semantics.rs (renamed from tests/ui/unop-move-semantics.rs)0
-rw-r--r--tests/ui/unop/unop-move-semantics.stderr (renamed from tests/ui/unop-move-semantics.stderr)0
-rw-r--r--tests/ui/unop/unop-neg-bool.rs (renamed from tests/ui/unop-neg-bool.rs)0
-rw-r--r--tests/ui/unop/unop-neg-bool.stderr (renamed from tests/ui/unop-neg-bool.stderr)0
-rw-r--r--tests/ui/unpretty/bad-literal.stdout4
-rw-r--r--tests/ui/unpretty/box.stdout8
-rw-r--r--tests/ui/unpretty/flattened-format-args.stdout14
-rw-r--r--tests/ui/unpretty/let-else-hir.stdout10
-rw-r--r--tests/ui/use/use-nested-groups-unused-imports.rs2
-rw-r--r--tests/ui/use/use-nested-groups-unused-imports.stderr2
-rw-r--r--tests/ui/wait-forked-but-failed-child.rs3
1044 files changed, 18506 insertions, 9567 deletions
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 00000000000..ca704082a3f
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,10 @@
+<!--
+If this PR is related to an unstable feature or an otherwise tracked effort,
+please link to the relevant tracking issue here. If you don't know of a related
+tracking issue or there are none, feel free to ignore this.
+
+This PR will get automatically assigned to a reviewer. In case you would like
+a specific user to review your work, you can assign it to them by using
+
+    r​? <reviewer name>
+-->
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5364c1e9f46..0551d44649c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -190,7 +190,6 @@ jobs:
         env:
           AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
           AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
-          TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
 
       - name: create github artifacts
         run: src/ci/scripts/create-doc-artifacts.sh
@@ -241,3 +240,5 @@ jobs:
         if: needs.calculate_matrix.outputs.run_type == 'auto'
         env:
           TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
+          TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
+          TOOLSTATE_PUBLISH: 1
diff --git a/.gitmodules b/.gitmodules
index 802d61eea29..9ad207a0d52 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -33,7 +33,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/18.0-2024-02-13
+	branch = rustc/18.1-2024-05-19
 	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
@@ -43,3 +43,7 @@
 	path = library/backtrace
 	url = https://github.com/rust-lang/backtrace-rs.git
 	shallow = true
+[submodule "src/tools/rustc-perf"]
+	path = src/tools/rustc-perf
+	url = https://github.com/rust-lang/rustc-perf.git
+	shallow = true
diff --git a/Cargo.lock b/Cargo.lock
index a9283d03cb3..3a4f028e695 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -74,11 +74,11 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
 
 [[package]]
 name = "ammonia"
-version = "3.3.0"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170"
+checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459"
 dependencies = [
- "html5ever",
+ "html5ever 0.27.0",
  "maplit",
  "once_cell",
  "tendril",
@@ -212,9 +212,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.83"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 dependencies = [
  "backtrace",
 ]
@@ -257,7 +257,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -414,9 +414,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
 
 [[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 dependencies = [
  "serde",
 ]
@@ -571,7 +571,7 @@ dependencies = [
  "anstream",
  "anstyle",
  "clap_lex",
- "strsim 0.11.1",
+ "strsim",
  "terminal_size",
 ]
 
@@ -593,7 +593,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -620,7 +620,7 @@ dependencies = [
  "regex",
  "rustc_tools_util",
  "serde",
- "syn 2.0.62",
+ "syn 2.0.64",
  "tempfile",
  "termize",
  "tokio",
@@ -647,7 +647,7 @@ dependencies = [
  "clap",
  "indoc",
  "itertools 0.12.1",
- "opener",
+ "opener 0.6.1",
  "shell-escape",
  "walkdir",
 ]
@@ -730,7 +730,7 @@ dependencies = [
  "nom",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -826,16 +826,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
 name = "core-foundation-sys"
 version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -957,9 +947,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.20.8"
+version = "0.20.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
+checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -967,27 +957,27 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.20.8"
+version = "0.20.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
+checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
- "strsim 0.10.0",
- "syn 2.0.62",
+ "strsim",
+ "syn 2.0.64",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.20.8"
+version = "0.20.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
+checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -997,12 +987,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
+name = "dbus"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b"
+dependencies = [
+ "libc",
+ "libdbus-sys",
+ "winapi",
+]
+
+[[package]]
 name = "declare_clippy_lint"
 version = "0.1.80"
 dependencies = [
  "itertools 0.12.1",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1043,7 +1044,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1053,7 +1054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
 dependencies = [
  "derive_builder_core",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1076,7 +1077,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1165,7 +1166,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1189,9 +1190,9 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.11.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
 
 [[package]]
 name = "elasticlunr-rs"
@@ -1230,15 +1231,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
-name = "encoding_rs"
-version = "0.8.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
 name = "env_filter"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1389,21 +1381,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
-name = "foreign-types"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-dependencies = [
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-
-[[package]]
 name = "form_urlencoded"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1503,7 +1480,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1627,25 +1604,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "h2"
-version = "0.3.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
 name = "handlebars"
 version = "5.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1735,47 +1693,27 @@ checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
 dependencies = [
  "log",
  "mac",
- "markup5ever",
+ "markup5ever 0.11.0",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
 [[package]]
-name = "http"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "0.4.6"
+name = "html5ever"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
+checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
 dependencies = [
- "bytes",
- "http",
- "pin-project-lite",
+ "log",
+ "mac",
+ "markup5ever 0.12.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.64",
 ]
 
 [[package]]
-name = "httparse"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
-
-[[package]]
-name = "httpdate"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
-
-[[package]]
 name = "humansize"
 version = "2.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1791,43 +1729,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
-name = "hyper"
-version = "0.14.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
-dependencies = [
- "bytes",
- "hyper",
- "native-tls",
- "tokio",
- "tokio-native-tls",
-]
-
-[[package]]
 name = "iana-time-zone"
 version = "0.1.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1941,7 +1842,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -2044,9 +1945,9 @@ dependencies = [
 
 [[package]]
 name = "instant"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
 dependencies = [
  "cfg-if",
 ]
@@ -2071,12 +1972,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "ipnet"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
-
-[[package]]
 name = "is_terminal_polyfill"
 version = "1.70.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2190,14 +2085,24 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
 
 [[package]]
 name = "libc"
-version = "0.2.153"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
+name = "libdbus-sys"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
 name = "libffi"
 version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2258,7 +2163,7 @@ dependencies = [
 name = "linkchecker"
 version = "0.1.0"
 dependencies = [
- "html5ever",
+ "html5ever 0.26.0",
  "regex",
 ]
 
@@ -2273,9 +2178,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "litemap"
@@ -2352,6 +2257,20 @@ dependencies = [
 ]
 
 [[package]]
+name = "markup5ever"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
+dependencies = [
+ "log",
+ "phf 0.11.2",
+ "phf_codegen 0.11.2",
+ "string_cache",
+ "string_cache_codegen",
+ "tendril",
+]
+
+[[package]]
 name = "matchers"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2372,9 +2291,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.37"
+version = "0.4.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c33564061c3c640bed5ace7d6a2a1b65f2c64257d1ac930c15e94ed0fb561d3"
+checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2387,7 +2306,7 @@ dependencies = [
  "log",
  "memchr",
  "once_cell",
- "opener",
+ "opener 0.7.1",
  "pulldown-cmark 0.10.3",
  "regex",
  "serde",
@@ -2470,9 +2389,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
 dependencies = [
  "adler",
  "compiler_builtins",
@@ -2481,17 +2400,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "mio"
-version = "0.8.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
-dependencies = [
- "libc",
- "wasi",
- "windows-sys 0.48.0",
-]
-
-[[package]]
 name = "miow"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2529,24 +2437,6 @@ name = "miropt-test-tools"
 version = "0.1.0"
 
 [[package]]
-name = "native-tls"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
-dependencies = [
- "lazy_static",
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
-[[package]]
 name = "new_debug_unreachable"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2698,29 +2588,15 @@ dependencies = [
 ]
 
 [[package]]
-name = "openssl"
-version = "0.10.64"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
-dependencies = [
- "bitflags 2.5.0",
- "cfg-if",
- "foreign-types",
- "libc",
- "once_cell",
- "openssl-macros",
- "openssl-sys",
-]
-
-[[package]]
-name = "openssl-macros"
-version = "0.1.1"
+name = "opener"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.62",
+ "bstr",
+ "dbus",
+ "normpath",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2756,7 +2632,6 @@ dependencies = [
  "humansize",
  "humantime",
  "log",
- "reqwest",
  "serde",
  "serde_json",
  "sysinfo",
@@ -2764,7 +2639,6 @@ dependencies = [
  "tar",
  "tempfile",
  "xz2",
- "zip",
 ]
 
 [[package]]
@@ -2912,7 +2786,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -3350,46 +3224,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "reqwest"
-version = "0.11.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
-dependencies = [
- "base64",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-tls",
- "ipnet",
- "js-sys",
- "log",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
- "tokio",
- "tokio-native-tls",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "winreg",
-]
-
-[[package]]
 name = "rls"
 version = "2.0.0"
 dependencies = [
@@ -4001,7 +3835,7 @@ dependencies = [
  "fluent-syntax",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "unic-langid",
 ]
 
@@ -4135,7 +3969,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -4282,7 +4116,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -4859,7 +4693,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -4957,7 +4791,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5004,19 +4838,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustls-pemfile"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
-dependencies = [
- "base64",
-]
-
-[[package]]
 name = "rustversion"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
 
 [[package]]
 name = "ruzstd"
@@ -5077,29 +4902,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
-name = "security-framework"
-version = "2.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
-dependencies = [
- "bitflags 2.5.0",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
 name = "self_cell"
 version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5125,22 +4927,22 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.201"
+version = "1.0.202"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
+checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.201"
+version = "1.0.202"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
+checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5157,22 +4959,10 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
 dependencies = [
- "form_urlencoded",
- "itoa",
- "ryu",
  "serde",
 ]
 
@@ -5402,12 +5192,6 @@ dependencies = [
 
 [[package]]
 name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
@@ -5452,9 +5236,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.62"
+version = "2.0.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f660c3bfcefb88c538776b6685a0c472e3128b51e74d48793dc2a488196e8eb"
+checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5462,12 +5246,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
-[[package]]
 name = "synstructure"
 version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5475,7 +5253,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5502,27 +5280,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "system-configuration"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
 name = "tabled"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5626,22 +5383,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b"
 
 [[package]]
 name = "thiserror"
-version = "1.0.60"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.60"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5757,34 +5514,7 @@ checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
 dependencies = [
  "backtrace",
  "bytes",
- "libc",
- "mio",
- "pin-project-lite",
- "socket2",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
  "pin-project-lite",
- "tokio",
 ]
 
 [[package]]
@@ -5810,9 +5540,9 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
 dependencies = [
  "serde",
 ]
@@ -5837,12 +5567,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
 
 [[package]]
-name = "tower-service"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
-
-[[package]]
 name = "tracing"
 version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5862,7 +5586,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5928,12 +5652,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "try-lock"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
-
-[[package]]
 name = "twox-hash"
 version = "1.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6068,7 +5786,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
 dependencies = [
  "proc-macro-hack",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "unic-langid-impl",
 ]
 
@@ -6260,15 +5978,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "want"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
-dependencies = [
- "try-lock",
-]
-
-[[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6300,23 +6009,11 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.42"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6334,7 +6031,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -6365,16 +6062,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "web-sys"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6425,7 +6112,7 @@ dependencies = [
  "rayon",
  "serde",
  "serde_json",
- "syn 2.0.62",
+ "syn 2.0.64",
  "windows-metadata",
 ]
 
@@ -6593,16 +6280,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winreg"
-version = "0.50.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
-dependencies = [
- "cfg-if",
- "windows-sys 0.48.0",
-]
-
-[[package]]
 name = "writeable"
 version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6657,7 +6334,7 @@ checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -6678,7 +6355,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -6698,7 +6375,7 @@ checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -6721,17 +6398,5 @@ checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.62",
-]
-
-[[package]]
-name = "zip"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
-dependencies = [
- "byteorder",
- "crc32fast",
- "crossbeam-utils",
- "flate2",
+ "syn 2.0.64",
 ]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 5d37bbd689f..1a166956075 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2733,6 +2733,13 @@ pub enum UseTreeKind {
     /// `use prefix` or `use prefix as rename`
     Simple(Option<Ident>),
     /// `use prefix::{...}`
+    ///
+    /// The span represents the braces of the nested group and all elements within:
+    ///
+    /// ```text
+    /// use foo::{bar, baz};
+    ///          ^^^^^^^^^^
+    /// ```
     Nested { items: ThinVec<(UseTree, NodeId)>, span: Span },
     /// `use prefix::*`
     Glob,
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0684163617f..d5c9fc960c8 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -13,6 +13,7 @@ use crate::util::literal::escape_string_symbol;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
 use std::iter;
 use std::sync::atomic::{AtomicU32, Ordering};
 use thin_vec::{thin_vec, ThinVec};
@@ -87,10 +88,20 @@ impl Attribute {
             AttrKind::DocComment(..) => None,
         }
     }
+
     pub fn name_or_empty(&self) -> Symbol {
         self.ident().unwrap_or_else(Ident::empty).name
     }
 
+    pub fn path(&self) -> SmallVec<[Symbol; 1]> {
+        match &self.kind {
+            AttrKind::Normal(normal) => {
+                normal.item.path.segments.iter().map(|s| s.ident.name).collect()
+            }
+            AttrKind::DocComment(..) => smallvec![sym::doc],
+        }
+    }
+
     #[inline]
     pub fn has_name(&self, name: Symbol) -> bool {
         match &self.kind {
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index e22a523dbc3..34c539ea16b 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -184,7 +184,7 @@ impl<'a, T> IntoIterator for &'a P<[T]> {
     type Item = &'a T;
     type IntoIter = slice::Iter<'a, T>;
     fn into_iter(self) -> Self::IntoIter {
-        self.ptr.into_iter()
+        self.ptr.iter()
     }
 }
 
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index a3731e94276..31a184fe921 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -55,9 +55,6 @@ ast_passes_const_without_body =
 ast_passes_constraint_on_negative_bound =
     associated type constraints not allowed on negative bounds
 
-ast_passes_deprecated_where_clause_location =
-    where clause not allowed here
-
 ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
     .label = not supported
     .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
@@ -80,8 +77,6 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
     .suggestion = remove the {$remove_descr}
     .label = `extern` block begins here
 
-ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
-
 ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
     .suggestion = remove the attribute
     .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 9d07683f8d6..c57be3cdf35 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -27,7 +27,6 @@ use std::ops::{Deref, DerefMut};
 use thin_vec::thin_vec;
 
 use crate::errors;
-use crate::fluent_generated as fluent;
 
 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
 enum SelfSemantic {
@@ -766,11 +765,10 @@ impl<'a> AstValidator<'a> {
             .span_to_snippet(span)
             .is_ok_and(|snippet| !snippet.starts_with("#["))
         {
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 MISSING_ABI,
                 id,
                 span,
-                fluent::ast_passes_extern_without_abi,
                 BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK),
             )
         }
@@ -1428,17 +1426,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
                 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
                     if let Some(ident) = ident {
-                        let msg = match ctxt {
-                            FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
-                            _ => fluent::ast_passes_pattern_in_bodiless,
-                        };
-                        let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident);
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             PATTERNS_IN_FNS_WITHOUT_BODY,
                             id,
                             span,
-                            msg,
-                            diag,
+                            BuiltinLintDiag::PatternsInFnsWithoutBody {
+                                span,
+                                ident,
+                                is_foreign: matches!(ctxt, FnCtxt::Foreign),
+                            },
                         )
                     }
                 } else {
@@ -1510,12 +1506,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     Some((right, snippet))
                 }
             };
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 DEPRECATED_WHERE_CLAUSE_LOCATION,
                 item.id,
                 err.span,
-                fluent::ast_passes_deprecated_where_clause_location,
-                BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg),
+                BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
             );
         }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 25a125f8393..a95a7bdaf6d 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -669,6 +669,7 @@ pub struct ConstAndCVariadic {
 
 #[derive(Diagnostic)]
 #[diag(ast_passes_pattern_in_foreign, code = E0130)]
+// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
 pub struct PatternInForeign {
     #[primary_span]
     #[label]
@@ -677,6 +678,7 @@ pub struct PatternInForeign {
 
 #[derive(Diagnostic)]
 #[diag(ast_passes_pattern_in_bodiless, code = E0642)]
+// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
 pub struct PatternInBodiless {
     #[primary_span]
     #[label]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 6622caaaab4..a522f04b21d 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(postfix_match, "postfix match is experimental");
     gate_all!(mut_ref, "mutable by-reference bindings are experimental");
     gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
+    gate_all!(global_registration, "global registration is experimental");
 
     if !visitor.features.never_patterns {
         if let Some(spans) = spans.get(&sym::never_patterns) {
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index c08bf287733..5113c5adc8f 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -528,15 +528,10 @@ pub fn cfg_matches(
         try_gate_cfg(cfg.name, cfg.span, sess, features);
         match sess.psess.check_config.expecteds.get(&cfg.name) {
             Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
-                sess.psess.buffer_lint_with_diagnostic(
+                sess.psess.buffer_lint(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
-                    if let Some(value) = cfg.value {
-                        format!("unexpected `cfg` condition value: `{value}`")
-                    } else {
-                        format!("unexpected `cfg` condition value: (none)")
-                    },
                     BuiltinLintDiag::UnexpectedCfgValue(
                         (cfg.name, cfg.name_span),
                         cfg.value.map(|v| (v, cfg.value_span.unwrap())),
@@ -544,11 +539,10 @@ pub fn cfg_matches(
                 );
             }
             None if sess.psess.check_config.exhaustive_names => {
-                sess.psess.buffer_lint_with_diagnostic(
+                sess.psess.buffer_lint(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
-                    format!("unexpected `cfg` condition name: `{}`", cfg.name),
                     BuiltinLintDiag::UnexpectedCfgName(
                         (cfg.name, cfg.name_span),
                         cfg.value.map(|v| (v, cfg.value_span.unwrap())),
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 15050c87b39..2f1b2ce9c4c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -652,7 +652,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     }
 
                     // FIXME: We make sure that this is a normal top-level binding,
-                    // but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern
+                    // but we could suggest `todo!()` for all uninitialized bindings in the pattern
                     if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
                         &ex.kind
                         && let hir::PatKind::Binding(..) = pat.kind
@@ -3343,6 +3343,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 } else if string.starts_with("gen") {
                     // `gen` is 3 chars long
                     Some(3)
+                } else if string.starts_with("static") {
+                    // `static` is 6 chars long
+                    // This is used for `!Unpin` coroutines
+                    Some(6)
                 } else {
                     None
                 };
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 35017b9e6b5..79b48508585 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -992,7 +992,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
         }
 
-        if look_at_return && hir.get_return_block(closure_id).is_some() {
+        if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
             // ...otherwise we are probably in the tail expression of the function, point at the
             // return type.
             match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index e7faec7bbac..51ea59e2092 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -15,8 +15,31 @@ use std::path::Path;
 #[derive(Copy, Clone, Debug)]
 pub struct RustcFacts;
 
+rustc_index::newtype_index! {
+    /// A (kinda) newtype of `RegionVid` so we can implement `Atom` on it.
+    #[orderable]
+    #[debug_format = "'?{}"]
+    pub struct PoloniusRegionVid {}
+}
+
+impl polonius_engine::Atom for PoloniusRegionVid {
+    fn index(self) -> usize {
+        self.as_usize()
+    }
+}
+impl From<RegionVid> for PoloniusRegionVid {
+    fn from(value: RegionVid) -> Self {
+        Self::from_usize(value.as_usize())
+    }
+}
+impl From<PoloniusRegionVid> for RegionVid {
+    fn from(value: PoloniusRegionVid) -> Self {
+        Self::from_usize(value.as_usize())
+    }
+}
+
 impl polonius_engine::FactTypes for RustcFacts {
-    type Origin = RegionVid;
+    type Origin = PoloniusRegionVid;
     type Loan = BorrowIndex;
     type Point = LocationIndex;
     type Variable = Local;
@@ -119,7 +142,7 @@ trait FactRow {
     ) -> Result<(), Box<dyn Error>>;
 }
 
-impl FactRow for RegionVid {
+impl FactRow for PoloniusRegionVid {
     fn write(
         &self,
         out: &mut dyn Write,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index abe57e26af4..1d5801467da 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1312,8 +1312,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 );
             }
 
-            Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
-            | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
+            Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
                 self.consume_operand(location, (operand1, span), flow_state);
                 self.consume_operand(location, (operand2, span), flow_state);
             }
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index a1e59977ede..6979910a02d 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -302,8 +302,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
                 );
             }
 
-            Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
-            | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
+            Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
                 self.consume_operand(location, operand1);
                 self.consume_operand(location, operand2);
             }
diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs
index 40126d50d57..9984f76e6d4 100644
--- a/compiler/rustc_borrowck/src/polonius/mod.rs
+++ b/compiler/rustc_borrowck/src/polonius/mod.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
 
 use crate::borrow_set::BorrowSet;
-use crate::facts::AllFacts;
+use crate::facts::{AllFacts, PoloniusRegionVid};
 use crate::location::LocationTable;
 use crate::type_check::free_region_relations::UniversalRegionRelations;
 use crate::universal_regions::UniversalRegions;
@@ -137,7 +137,9 @@ fn emit_universal_region_facts(
     //   the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
     //   added to the existing number of loans, as if they succeeded them in the set.
     //
-    all_facts.universal_region.extend(universal_regions.universal_regions());
+    all_facts
+        .universal_region
+        .extend(universal_regions.universal_regions().map(PoloniusRegionVid::from));
     let borrow_count = borrow_set.len();
     debug!(
         "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
@@ -148,7 +150,7 @@ fn emit_universal_region_facts(
     for universal_region in universal_regions.universal_regions() {
         let universal_region_idx = universal_region.index();
         let placeholder_loan_idx = borrow_count + universal_region_idx;
-        all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
+        all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
     }
 
     // 2: the universal region relations `outlives` constraints are emitted as
@@ -160,7 +162,7 @@ fn emit_universal_region_facts(
                      fr1={:?}, fr2={:?}",
                 fr1, fr2
             );
-            all_facts.known_placeholder_subset.push((fr1, fr2));
+            all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
         }
     }
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 167ca7ba045..b57cf9066cf 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1506,7 +1506,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         subset_errors.sort();
         subset_errors.dedup();
 
-        for (longer_fr, shorter_fr) in subset_errors.into_iter() {
+        for &(longer_fr, shorter_fr) in subset_errors.into_iter() {
             debug!(
                 "check_polonius_subset_errors: subset_error longer_fr={:?},\
                  shorter_fr={:?}",
@@ -1514,14 +1514,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             );
 
             let propagated = self.try_propagate_universal_region_error(
-                *longer_fr,
-                *shorter_fr,
+                longer_fr.into(),
+                shorter_fr.into(),
                 &mut propagated_outlives_requirements,
             );
             if propagated == RegionRelationCheckResult::Error {
                 errors_buffer.push(RegionErrorKind::RegionError {
-                    longer_fr: *longer_fr,
-                    shorter_fr: *shorter_fr,
+                    longer_fr: longer_fr.into(),
+                    shorter_fr: shorter_fr.into(),
                     fr_origin: NllRegionVariableOrigin::FreeRegion,
                     is_reported: true,
                 });
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 7f530227043..ccfa9f12ef4 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -117,7 +117,7 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
             let universal_regions = &typeck.borrowck_context.universal_regions;
             typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
                 let region_vid = universal_regions.to_region_vid(region);
-                facts.use_of_var_derefs_origin.push((local, region_vid));
+                facts.use_of_var_derefs_origin.push((local, region_vid.into()));
             });
         }
     }
@@ -136,7 +136,7 @@ pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
         let universal_regions = &typeck.borrowck_context.universal_regions;
         typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
             let region_vid = universal_regions.to_region_vid(drop_live_region);
-            facts.drop_of_var_derefs_origin.push((local, region_vid));
+            facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
         });
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 6cf9ac45aa3..4e46a0c62c7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -260,16 +260,14 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
             |constraint: &OutlivesConstraint<'_>| {
                 if let Some(from_location) = constraint.locations.from_location() {
                     Either::Left(iter::once((
-                        constraint.sup,
-                        constraint.sub,
+                        constraint.sup.into(),
+                        constraint.sub.into(),
                         location_table.mid_index(from_location),
                     )))
                 } else {
-                    Either::Right(
-                        location_table
-                            .all_points()
-                            .map(move |location| (constraint.sup, constraint.sub, location)),
-                    )
+                    Either::Right(location_table.all_points().map(move |location| {
+                        (constraint.sup.into(), constraint.sub.into(), location)
+                    }))
                 }
             },
         ));
@@ -2417,8 +2415,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.check_operand(op, location);
             }
 
-            Rvalue::BinaryOp(_, box (left, right))
-            | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+            Rvalue::BinaryOp(_, box (left, right)) => {
                 self.check_operand(left, location);
                 self.check_operand(right, location);
             }
@@ -2445,7 +2442,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | Rvalue::Cast(..)
             | Rvalue::ShallowInitBox(..)
             | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::CopyForDeref(..)
             | Rvalue::UnaryOp(..)
@@ -2547,7 +2543,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             if let Some(borrow_index) = borrow_set.get_index_of(&location) {
                 let region_vid = borrow_region.as_var();
                 all_facts.loan_issued_at.push((
-                    region_vid,
+                    region_vid.into(),
                     borrow_index,
                     location_table.mid_index(location),
                 ));
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 0f158990319..a3d6a1c7360 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -247,5 +247,3 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
     .label = not a trait
     .str_lit = try using `#[derive({$sym})]`
     .other = for example, write `#[derive(Debug)]` for `Debug`
-
-builtin_macros_unnameable_test_items = cannot test inner items
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 49b1b8cf992..1a7961bf70c 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,6 +1,7 @@
 use crate::errors;
 use crate::util::expr_to_spanned_string;
 use ast::token::IdentIsRaw;
+use lint::BuiltinLintDiag;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
@@ -513,7 +514,7 @@ fn expand_preparsed_asm(
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".intel_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    "avoid using `.intel_syntax`, Intel syntax is the default",
+                    BuiltinLintDiag::AvoidUsingIntelSyntax,
                 );
             }
             if template_str.contains(".att_syntax") {
@@ -521,7 +522,7 @@ fn expand_preparsed_asm(
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".att_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
+                    BuiltinLintDiag::AvoidUsingAttSyntax,
                 );
             }
         }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 46949f731aa..217fa5ff9f1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1621,14 +1621,13 @@ impl<'a> TraitDef<'a> {
                         };
 
                         if let Some(ty) = exception {
-                            cx.sess.psess.buffer_lint_with_diagnostic(
+                            cx.sess.psess.buffer_lint(
                                 BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
                                 sp,
                                 ast::CRATE_NODE_ID,
-                                format!(
-                                    "{ty} slice in a packed struct that derives a built-in trait"
-                                ),
-                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive,
+                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
+                                    ty: ty.to_string(),
+                                },
                             );
                         } else {
                             // Wrap the expression in `{...}`, causing a copy.
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index a5fc74f1d66..5cb0407bd59 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -556,7 +556,6 @@ fn make_format_args(
             let arg_name = args.explicit_args()[index].kind.ident().unwrap();
             ecx.buffered_early_lint.push(BufferedEarlyLint {
                 span: arg_name.span.into(),
-                msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
                 node_id: rustc_ast::CRATE_NODE_ID,
                 lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
                 diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 47b2ee975ca..29e991525a9 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -11,6 +11,7 @@ use rustc_expand::base::{
     resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
 };
 use rustc_expand::module::DirOwnership;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::new_parser_from_file;
 use rustc_parse::parser::{ForceCollect, Parser};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
@@ -147,7 +148,7 @@ pub(crate) fn expand_include<'cx>(
                     INCOMPLETE_INCLUDE,
                     self.p.token.span,
                     self.node_id,
-                    "include macro expected single expression in source",
+                    BuiltinLintDiag::IncompleteInclude,
                 );
             }
             Some(expr)
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 8cf431482ff..38ac2f15fe7 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -9,6 +9,7 @@ use rustc_ast::{attr, ModKind};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
 use rustc_session::Session;
 use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
@@ -163,7 +164,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
                 i.id,
-                crate::fluent_generated::builtin_macros_unnameable_test_items,
+                BuiltinLintDiag::UnnameableTestItems,
             );
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 8dc7bc14ec3..652e34268ea 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -5,7 +5,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
 use rustc_expand::expand::AstFragment;
 use rustc_feature::AttributeTemplate;
-use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
+use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag};
 use rustc_parse::{parser, validate_attr};
 use rustc_session::errors::report_lit_error;
 use rustc_span::{BytePos, Span, Symbol};
@@ -46,7 +46,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
                 DUPLICATE_MACRO_ATTRIBUTES,
                 attr.span,
                 ecx.current_expansion.lint_node_id,
-                "duplicated attribute",
+                BuiltinLintDiag::DuplicateMacroAttribute,
             );
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 5846689643f..8d778f736d6 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -609,14 +609,11 @@ fn codegen_stmt<'tcx>(
                     let lhs = codegen_operand(fx, &lhs_rhs.0);
                     let rhs = codegen_operand(fx, &lhs_rhs.1);
 
-                    let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
-                    lval.write_cvalue(fx, res);
-                }
-                Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
-                    let lhs = codegen_operand(fx, &lhs_rhs.0);
-                    let rhs = codegen_operand(fx, &lhs_rhs.1);
-
-                    let res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
+                    let res = if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                        crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
+                    } else {
+                        crate::num::codegen_binop(fx, bin_op, lhs, rhs)
+                    };
                     lval.write_cvalue(fx, res);
                 }
                 Rvalue::UnaryOp(un_op, ref operand) => {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index 4a5ef352151..e16b77648d1 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -70,6 +70,7 @@ pub(crate) fn maybe_codegen<'tcx>(
         }
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
+        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
     }
 }
 
@@ -132,6 +133,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
             Some(out_place.to_cvalue(fx))
         }
         BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
+        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => unreachable!(),
         BinOp::Cmp => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 452b5988dab..b17f191ce26 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -348,6 +348,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
         | sym::simd_bswap
         | sym::simd_bitreverse
         | sym::simd_ctlz
+        | sym::simd_ctpop
         | sym::simd_cttz => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
@@ -367,6 +368,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 (ty::Uint(_) | ty::Int(_), sym::simd_bswap) => fx.bcx.ins().bswap(lane),
                 (ty::Uint(_) | ty::Int(_), sym::simd_bitreverse) => fx.bcx.ins().bitrev(lane),
                 (ty::Uint(_) | ty::Int(_), sym::simd_ctlz) => fx.bcx.ins().clz(lane),
+                (ty::Uint(_) | ty::Int(_), sym::simd_ctpop) => fx.bcx.ins().popcnt(lane),
                 (ty::Uint(_) | ty::Int(_), sym::simd_cttz) => fx.bcx.ins().ctz(lane),
 
                 _ => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 4d96a26ea4f..fb18f45d7dc 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -179,6 +179,9 @@ pub(crate) fn codegen_int_binop<'tcx>(
             }
         }
         BinOp::Offset => unreachable!("Offset is not an integer operation"),
+        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => {
+            unreachable!("Overflow binops handled by `codegen_checked_int_binop`")
+        }
         // Compare binops handles by `codegen_binop`.
         BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
             unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index d4a3e39cef7..c304c0cbd3b 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -200,21 +200,20 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 _ => panic!("unsupported arch {}", sess.target.arch),
             };
             let mut dlltool_cmd = std::process::Command::new(&dlltool);
-            dlltool_cmd.args([
-                "-d",
-                def_file_path.to_str().unwrap(),
-                "-D",
-                lib_name,
-                "-l",
-                output_path.to_str().unwrap(),
-                "-m",
-                dlltool_target_arch,
-                "-f",
-                dlltool_target_bitness,
-                "--no-leading-underscore",
-                "--temp-prefix",
-                temp_prefix.to_str().unwrap(),
-            ]);
+            dlltool_cmd
+                .arg("-d")
+                .arg(def_file_path)
+                .arg("-D")
+                .arg(lib_name)
+                .arg("-l")
+                .arg(&output_path)
+                .arg("-m")
+                .arg(dlltool_target_arch)
+                .arg("-f")
+                .arg(dlltool_target_bitness)
+                .arg("--no-leading-underscore")
+                .arg("--temp-prefix")
+                .arg(temp_prefix);
 
             match dlltool_cmd.output() {
                 Err(e) => {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c0a1208a8c7..80e863af893 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -2336,7 +2336,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     }
 
     // Unary integer intrinsics
-    if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_cttz) {
+    if matches!(
+        name,
+        sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop | sym::simd_cttz
+    ) {
         let vec_ty = bx.cx.type_vector(
             match *in_elem.kind() {
                 ty::Int(i) => bx.cx.type_int_from_ty(i),
@@ -2354,31 +2357,38 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             sym::simd_bswap => "bswap",
             sym::simd_bitreverse => "bitreverse",
             sym::simd_ctlz => "ctlz",
+            sym::simd_ctpop => "ctpop",
             sym::simd_cttz => "cttz",
             _ => unreachable!(),
         };
         let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
         let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,);
 
-        return if name == sym::simd_bswap && int_size == 8 {
+        return match name {
             // byte swap is no-op for i8/u8
-            Ok(args[0].immediate())
-        } else if matches!(name, sym::simd_ctlz | sym::simd_cttz) {
-            let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
-            let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
-            Ok(bx.call(
-                fn_ty,
-                None,
-                None,
-                f,
-                &[args[0].immediate(), bx.const_int(bx.type_i1(), 0)],
-                None,
-                None,
-            ))
-        } else {
-            let fn_ty = bx.type_func(&[vec_ty], vec_ty);
-            let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
-            Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
+            sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()),
+            sym::simd_ctlz | sym::simd_cttz => {
+                // for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison`
+                let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
+                let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0);
+                let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+                Ok(bx.call(
+                    fn_ty,
+                    None,
+                    None,
+                    f,
+                    &[args[0].immediate(), dont_poison_on_zero],
+                    None,
+                    None,
+                ))
+            }
+            sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => {
+                // simple unary argument cases
+                let fn_ty = bx.type_func(&[vec_ty], vec_ty);
+                let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+                Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
+            }
+            _ => unreachable!(),
         };
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 6939674ce9d..37b8f81ad94 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1230,7 +1230,10 @@ fn add_sanitizer_libraries(
     if sanitizer.contains(SanitizerSet::DATAFLOW) {
         link_sanitizer_runtime(sess, flavor, linker, "dfsan");
     }
-    if sanitizer.contains(SanitizerSet::LEAK) {
+    if sanitizer.contains(SanitizerSet::LEAK)
+        && !sanitizer.contains(SanitizerSet::ADDRESS)
+        && !sanitizer.contains(SanitizerSet::HWADDRESS)
+    {
         link_sanitizer_runtime(sess, flavor, linker, "lsan");
     }
     if sanitizer.contains(SanitizerSet::MEMORY) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index ff176a79675..00b28cbd0c6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -576,6 +576,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
+            mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
+                if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
+            {
+                let lhs = self.codegen_operand(bx, lhs);
+                let rhs = self.codegen_operand(bx, rhs);
+                let result = self.codegen_scalar_checked_binop(
+                    bx,
+                    op,
+                    lhs.immediate(),
+                    rhs.immediate(),
+                    lhs.layout.ty,
+                );
+                let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
+                let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
+                OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
+            }
             mir::Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
                 let lhs = self.codegen_operand(bx, lhs);
                 let rhs = self.codegen_operand(bx, rhs);
@@ -604,20 +620,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     layout: bx.cx().layout_of(op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)),
                 }
             }
-            mir::Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
-                let lhs = self.codegen_operand(bx, lhs);
-                let rhs = self.codegen_operand(bx, rhs);
-                let result = self.codegen_scalar_checked_binop(
-                    bx,
-                    op,
-                    lhs.immediate(),
-                    rhs.immediate(),
-                    lhs.layout.ty,
-                );
-                let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
-                let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
-                OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
-            }
 
             mir::Rvalue::UnaryOp(op, ref operand) => {
                 let operand = self.codegen_operand(bx, operand);
@@ -928,6 +930,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
                 }
             }
+            mir::BinOp::AddWithOverflow
+            | mir::BinOp::SubWithOverflow
+            | mir::BinOp::MulWithOverflow => {
+                bug!("{op:?} needs to return a pair, so call codegen_scalar_checked_binop instead")
+            }
         }
     }
 
@@ -1040,7 +1047,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Cast(..) | // (*)
             mir::Rvalue::ShallowInitBox(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
-            mir::Rvalue::CheckedBinaryOp(..) |
             mir::Rvalue::UnaryOp(..) |
             mir::Rvalue::Discriminant(..) |
             mir::Rvalue::NullaryOp(..) |
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index ee415c380de..cb72d55a9ba 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -167,15 +167,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                 let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
                 let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
-                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
-            }
-
-            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
-                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
-                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
-                let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
-                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
-                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
+                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                    self.binop_with_overflow(bin_op, &left, &right, &dest)?;
+                } else {
+                    self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
+                }
             }
 
             UnaryOp(un_op, ref operand) => {
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index a525b838afa..7b293e2b533 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,9 +1,3 @@
-/*!
-
-Rust MIR: a lowered representation of Rust.
-
-*/
-
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![feature(rustdoc_internals)]
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 5edf5bb39dd..c8c54143f61 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -580,7 +580,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 }
             }
 
-            Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
+            Rvalue::BinaryOp(op, box (lhs, rhs)) => {
                 let lhs_ty = lhs.ty(self.body, self.tcx);
                 let rhs_ty = rhs.ty(self.body, self.tcx);
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index eae0e2f27db..7e8a208659b 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -261,7 +261,7 @@ where
         | Rvalue::Cast(_, operand, _)
         | Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
 
-        Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
+        Rvalue::BinaryOp(_, box (lhs, rhs)) => {
             in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
         }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 5ae3ffaaec2..011341472b4 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -200,7 +200,6 @@ where
             | mir::Rvalue::Repeat(..)
             | mir::Rvalue::Len(..)
             | mir::Rvalue::BinaryOp(..)
-            | mir::Rvalue::CheckedBinaryOp(..)
             | mir::Rvalue::NullaryOp(..)
             | mir::Rvalue::UnaryOp(..)
             | mir::Rvalue::Discriminant(..)
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index fdc7f6a69cb..3a2b2c5f300 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -1037,8 +1037,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             )
                         }
                     }
-                    AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
-                    | ShrUnchecked => {
+                    AddUnchecked | AddWithOverflow | SubUnchecked | SubWithOverflow
+                    | MulUnchecked | MulWithOverflow | Shl | ShlUnchecked | Shr | ShrUnchecked => {
                         for x in [a, b] {
                             check_kinds!(
                                 x,
@@ -1067,31 +1067,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                 }
             }
-            Rvalue::CheckedBinaryOp(op, vals) => {
-                use BinOp::*;
-                let a = vals.0.ty(&self.body.local_decls, self.tcx);
-                let b = vals.1.ty(&self.body.local_decls, self.tcx);
-                match op {
-                    Add | Sub | Mul => {
-                        for x in [a, b] {
-                            check_kinds!(
-                                x,
-                                "Cannot perform checked arithmetic on type {:?}",
-                                ty::Uint(..) | ty::Int(..)
-                            )
-                        }
-                        if a != b {
-                            self.fail(
-                                location,
-                                format!(
-                                    "Cannot perform checked arithmetic on unequal types {a:?} and {b:?}"
-                                ),
-                            );
-                        }
-                    }
-                    _ => self.fail(location, format!("There is no checked version of {op:?}")),
-                }
-            }
             Rvalue::UnaryOp(op, operand) => {
                 let a = operand.ty(&self.body.local_decls, self.tcx);
                 match op {
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 0c3b59a0e78..66a1addfb52 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -19,7 +19,9 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
         | BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
-        Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
+        AddWithOverflow | SubWithOverflow | MulWithOverflow | Eq | Ne | Lt | Le | Gt | Ge | Cmp => {
+            false
+        }
     }
 }
 
@@ -29,8 +31,9 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
 pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
     use rustc_middle::mir::BinOp::*;
     match op {
-        Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
-        | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
+        Add | AddUnchecked | AddWithOverflow | Sub | SubUnchecked | SubWithOverflow | Mul
+        | MulUnchecked | MulWithOverflow | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt
+        | Le | Gt | Ge | Cmp => true,
         Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
     }
 }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 4bf7dccab92..662c8a7b8be 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -282,6 +282,12 @@ impl IntoDiagArg for ClosureKind {
     }
 }
 
+impl IntoDiagArg for hir::def::Namespace {
+    fn into_diag_arg(self) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(self.descr()))
+    }
+}
+
 #[derive(Clone)]
 pub struct DiagSymbolList(Vec<Symbol>);
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 12868a66605..91af8758e51 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1364,18 +1364,15 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
                             };
 
                             if crate_matches {
-                                // FIXME: make this translatable
-                                #[allow(rustc::untranslatable_diagnostic)]
-                                sess.psess.buffer_lint_with_diagnostic(
-                                        PROC_MACRO_BACK_COMPAT,
-                                        item.ident.span,
-                                        ast::CRATE_NODE_ID,
-                                        "using an old version of `rental`",
-                                        BuiltinLintDiag::ProcMacroBackCompat(
-                                        "older versions of the `rental` crate will stop compiling in future versions of Rust; \
-                                        please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string()
-                                        )
-                                    );
+                                sess.psess.buffer_lint(
+                                    PROC_MACRO_BACK_COMPAT,
+                                    item.ident.span,
+                                    ast::CRATE_NODE_ID,
+                                    BuiltinLintDiag::ProcMacroBackCompat {
+                                        crate_name: "rental".to_string(),
+                                        fixed_version: "0.5.6".to_string(),
+                                    },
+                                );
                                 return true;
                             }
                         }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 35f0d8abffc..badfa6d3aa3 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -14,6 +14,7 @@ use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::Features;
 use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::validate_attr;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
@@ -248,7 +249,6 @@ impl<'a> StripUnconfigured<'a> {
     /// Gives a compiler warning when the `cfg_attr` contains no attributes and
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
         let Some((cfg_predicate, expanded_attrs)) =
             rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
@@ -262,7 +262,7 @@ impl<'a> StripUnconfigured<'a> {
                 rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
                 attr.span,
                 ast::CRATE_NODE_ID,
-                "`#[cfg_attr]` does not expand to any attributes",
+                BuiltinLintDiag::CfgAttrNoAttributes,
             );
         }
 
@@ -283,7 +283,6 @@ impl<'a> StripUnconfigured<'a> {
         }
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn expand_cfg_attr_item(
         &self,
         attr: &Attribute,
@@ -346,7 +345,7 @@ impl<'a> StripUnconfigured<'a> {
                 rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
                 attr.span,
                 ast::CRATE_NODE_ID,
-                "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
+                BuiltinLintDiag::CrateTypeInCfgAttr,
             );
         }
         if attr.has_name(sym::crate_name) {
@@ -354,7 +353,7 @@ impl<'a> StripUnconfigured<'a> {
                 rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
                 attr.span,
                 ast::CRATE_NODE_ID,
-                "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
+                BuiltinLintDiag::CrateNameInCfgAttr,
             );
         }
         attr
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index a049ac251e1..d8f0f221189 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1799,11 +1799,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             }
 
             if attr.is_doc_comment() {
-                self.cx.sess.psess.buffer_lint_with_diagnostic(
+                self.cx.sess.psess.buffer_lint(
                     UNUSED_DOC_COMMENTS,
                     current_span,
                     self.cx.current_expansion.lint_node_id,
-                    "unused doc comment",
                     BuiltinLintDiag::UnusedDocComment(attr.span),
                 );
             } else if rustc_attr::is_builtin_attr(attr) {
@@ -1811,11 +1810,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 // `#[cfg]` and `#[cfg_attr]` are special - they are
                 // eagerly evaluated.
                 if attr_name != sym::cfg && attr_name != sym::cfg_attr {
-                    self.cx.sess.psess.buffer_lint_with_diagnostic(
+                    self.cx.sess.psess.buffer_lint(
                         UNUSED_ATTRIBUTES,
                         attr.span,
                         self.cx.current_expansion.lint_node_id,
-                        format!("unused attribute `{attr_name}`"),
                         BuiltinLintDiag::UnusedBuiltinAttribute {
                             attr_name,
                             macro_name: pprust::path_to_string(&call.path),
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index dce8e0c36ed..72dbbde54b3 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -110,7 +110,8 @@ use crate::mbe::{KleeneToken, TokenTree};
 use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{DiagMessage, MultiSpan};
+use rustc_errors::MultiSpan;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::kw;
@@ -252,7 +253,7 @@ fn check_binders(
                 // 1. The meta-variable is already bound in the current LHS: This is an error.
                 let mut span = MultiSpan::from_span(span);
                 span.push_span_label(prev_info.span, "previous declaration");
-                buffer_lint(psess, span, node_id, "duplicate matcher binding");
+                buffer_lint(psess, span, node_id, BuiltinLintDiag::DuplicateMatcherBinding);
             } else if get_binder_info(macros, binders, name).is_none() {
                 // 2. The meta-variable is free: This is a binder.
                 binders.insert(name, BinderInfo { span, ops: ops.into() });
@@ -271,7 +272,7 @@ fn check_binders(
                     MISSING_FRAGMENT_SPECIFIER,
                     span,
                     node_id,
-                    "missing fragment specifier",
+                    BuiltinLintDiag::MissingFragmentSpecifier,
                 );
             }
             if !macros.is_empty() {
@@ -595,7 +596,7 @@ fn check_ops_is_prefix(
             return;
         }
     }
-    buffer_lint(psess, span.into(), node_id, format!("unknown macro variable `{name}`"));
+    buffer_lint(psess, span.into(), node_id, BuiltinLintDiag::UnknownMacroVariable(name));
 }
 
 /// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
@@ -628,8 +629,7 @@ fn ops_is_prefix(
         if i >= occurrence_ops.len() {
             let mut span = MultiSpan::from_span(span);
             span.push_span_label(binder.span, "expected repetition");
-            let message = format!("variable '{name}' is still repeating at this depth");
-            buffer_lint(psess, span, node_id, message);
+            buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableStillRepeating(name));
             return;
         }
         let occurrence = &occurrence_ops[i];
@@ -637,21 +637,15 @@ fn ops_is_prefix(
             let mut span = MultiSpan::from_span(span);
             span.push_span_label(binder.span, "expected repetition");
             span.push_span_label(occurrence.span, "conflicting repetition");
-            let message = "meta-variable repeats with different Kleene operator";
-            buffer_lint(psess, span, node_id, message);
+            buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableWrongOperator);
             return;
         }
     }
 }
 
-fn buffer_lint(
-    psess: &ParseSess,
-    span: MultiSpan,
-    node_id: NodeId,
-    message: impl Into<DiagMessage>,
-) {
+fn buffer_lint(psess: &ParseSess, span: MultiSpan, node_id: NodeId, diag: BuiltinLintDiag) {
     // Macros loaded from other crates have dummy node ids.
     if node_id != DUMMY_NODE_ID {
-        psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, message);
+        psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, diag);
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 8f18055f838..d99ecb61085 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -79,11 +79,10 @@ impl<'a> ParserAnyMacro<'a> {
         // but `m!()` is allowed in expression positions (cf. issue #34706).
         if kind == AstFragmentKind::Expr && parser.token == token::Semi {
             if is_local {
-                parser.psess.buffer_lint_with_diagnostic(
+                parser.psess.buffer_lint(
                     SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
                     parser.token.span,
                     lint_node_id,
-                    "trailing semicolon in macro used in expression position",
                     BuiltinLintDiag::TrailingMacro(is_trailing_mac, macro_ident),
                 );
             }
@@ -1154,11 +1153,10 @@ fn check_matcher_core<'tt>(
                             name,
                             Some(NonterminalKind::PatParam { inferred: false }),
                         ));
-                        sess.psess.buffer_lint_with_diagnostic(
+                        sess.psess.buffer_lint(
                             RUST_2021_INCOMPATIBLE_OR_PATTERNS,
                             span,
                             ast::CRATE_NODE_ID,
-                            "the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",
                             BuiltinLintDiag::OrPatternsBackCompat(span, suggestion),
                         );
                     }
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index dbb88e42a3e..0b4a871dd50 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -515,12 +515,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::Yes, experimental!(deprecated_safe),
     ),
 
-    // RFC 2397
-    gated!(
-        do_not_recommend, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::Yes, experimental!(do_not_recommend)
-    ),
-
     // `#[cfi_encoding = ""]`
     gated!(
         cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
@@ -899,10 +893,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "the `#[rustc_main]` attribute is used internally to specify test entry point function",
     ),
     rustc_attr!(
-        rustc_skip_array_during_method_dispatch, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::No,
-        "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
-        from method dispatch when the receiver is an array, for compatibility in editions < 2021."
+        rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
+        EncodeCrossCrate::No,
+        "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
+        from method dispatch when the receiver is of the following type, for compatibility in \
+        editions < 2021 (array) or editions < 2024 (boxed_slice)."
     ),
     rustc_attr!(
         rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index c6fc9de119d..dc4807bab2d 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -489,6 +489,8 @@ declare_features! (
     (incomplete, generic_const_exprs, "1.56.0", Some(76560)),
     /// Allows generic parameters and where-clauses on free & associated const items.
     (incomplete, generic_const_items, "1.73.0", Some(113521)),
+    /// Allows registering static items globally, possibly across crates, to iterate over at runtime.
+    (unstable, global_registration, "CURRENT_RUSTC_VERSION", Some(125119)),
     /// Allows using `..=X` as a patterns in slices.
     (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
     /// Allows `if let` guard in match arms.
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index d829e720d9e..50fe20346cf 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -607,6 +607,7 @@ pub fn check_intrinsic_type(
             | sym::simd_bitreverse
             | sym::simd_ctlz
             | sym::simd_cttz
+            | sym::simd_ctpop
             | sym::simd_fsqrt
             | sym::simd_fsin
             | sym::simd_fcos
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e137aab2109..e8ede804c3f 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
             }
             let gat_generics = tcx.generics_of(gat_def_id);
             // FIXME(jackh726): we can also warn in the more general case
-            if gat_generics.own_params.is_empty() {
+            if gat_generics.is_own_empty() {
                 continue;
             }
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index aa28b2c8e2c..b760b86a7bf 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1117,8 +1117,24 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 
     let is_marker = tcx.has_attr(def_id, sym::marker);
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
-    let skip_array_during_method_dispatch =
-        tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
+
+    // FIXME: We could probably do way better attribute validation here.
+    let mut skip_array_during_method_dispatch = false;
+    let mut skip_boxed_slice_during_method_dispatch = false;
+    for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
+        if let Some(lst) = attr.meta_item_list() {
+            for item in lst {
+                if let Some(ident) = item.ident() {
+                    match ident.as_str() {
+                        "array" => skip_array_during_method_dispatch = true,
+                        "boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
+                        _ => (),
+                    }
+                }
+            }
+        }
+    }
+
     let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
         ty::trait_def::TraitSpecializationKind::Marker
     } else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
@@ -1253,6 +1269,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         is_marker,
         is_coinductive: rustc_coinductive || is_auto,
         skip_array_during_method_dispatch,
+        skip_boxed_slice_during_method_dispatch,
         specialization_kind,
         must_implement_one_of,
         implement_via_object,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index f19492e00b4..00356ece585 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1409,7 +1409,7 @@ fn generics_args_err_extend<'a>(
             // it was done based on the end of assoc segment but that sometimes
             // led to impossible spans and caused issues like #116473
             let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
-            if tcx.generics_of(adt_def.did()).count() == 0 {
+            if tcx.generics_of(adt_def.did()).is_empty() {
                 // FIXME(estebank): we could also verify that the arguments being
                 // work for the `enum`, instead of just looking if it takes *any*.
                 err.span_suggestion_verbose(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 39016d15236..8caeb85204b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -412,7 +412,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // Traits always have `Self` as a generic parameter, which means they will not return early
         // here and so associated type bindings will be handled regardless of whether there are any
         // non-`Self` generic parameters.
-        if generics.own_params.is_empty() {
+        if generics.is_own_empty() {
             return (tcx.mk_args(parent_args), arg_count);
         }
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 654ef4baeb3..d1e50e13894 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -181,7 +181,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
         let def_kind = tcx.def_kind(item_def_id);
         match def_kind {
             DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
-            DefKind::Const if tcx.generics_of(item_def_id).own_params.is_empty() => {
+            DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
                 let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
                 let cid = GlobalId { instance, promoted: None };
                 let param_env = ty::ParamEnv::reveal_all();
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 730e989edae..0c436e21c16 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -99,7 +99,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
         debug!("build_constraints_for_item({})", tcx.def_path_str(def_id));
 
         // Skip items with no generics - there's nothing to infer in them.
-        if tcx.generics_of(def_id).count() == 0 {
+        if tcx.generics_of(def_id).is_empty() {
             return;
         }
 
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index cefd8fb1ac5..1977451f39e 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -41,7 +41,7 @@ fn crate_variances(tcx: TyCtxt<'_>, (): ()) -> CrateVariancesMap<'_> {
 
 fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
     // Skip items with no generics - there's nothing to infer in them.
-    if tcx.generics_of(item_def_id).count() == 0 {
+    if tcx.generics_of(item_def_id).is_empty() {
         return &[];
     }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 29c7e576d2b..488537e81be 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1454,7 +1454,7 @@ impl<'a> State<'a> {
                     self.word_space(":");
                 }
                 // containing cbox, will be closed by print-block at `}`
-                self.cbox(INDENT_UNIT);
+                self.cbox(0);
                 // head-box, will be closed by print-block after `{`
                 self.ibox(0);
                 self.print_block(blk);
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index d81dab2222a..33c24433ca3 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1591,31 +1591,28 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         err.span_label(cause.span, "return type is not `()`");
                     }
                     ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
-                        let parent_id = fcx.tcx.parent_hir_id(blk_id);
                         err = self.report_return_mismatched_types(
                             cause,
                             expected,
                             found,
                             coercion_error,
                             fcx,
-                            parent_id,
+                            blk_id,
                             expression,
-                            Some(blk_id),
                         );
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                     }
-                    ObligationCauseCode::ReturnValue(id) => {
+                    ObligationCauseCode::ReturnValue(return_expr_id) => {
                         err = self.report_return_mismatched_types(
                             cause,
                             expected,
                             found,
                             coercion_error,
                             fcx,
-                            id,
+                            return_expr_id,
                             expression,
-                            None,
                         );
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_definitely_unsized(fcx);
@@ -1809,13 +1806,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         found: Ty<'tcx>,
         ty_err: TypeError<'tcx>,
         fcx: &FnCtxt<'a, 'tcx>,
-        id: hir::HirId,
+        block_or_return_id: hir::HirId,
         expression: Option<&'tcx hir::Expr<'tcx>>,
-        blk_id: Option<hir::HirId>,
     ) -> Diag<'a> {
         let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
 
-        let parent_id = fcx.tcx.parent_hir_id(id);
+        let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
+
+        let parent_id = fcx.tcx.parent_hir_id(block_or_return_id);
         let parent = fcx.tcx.hir_node(parent_id);
         if let Some(expr) = expression
             && let hir::Node::Expr(hir::Expr {
@@ -1829,72 +1827,64 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         // Verify that this is a tail expression of a function, otherwise the
         // label pointing out the cause for the type coercion will be wrong
         // as prior return coercions would not be relevant (#57664).
-        let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
+        if let Some(expr) = expression
+            && due_to_block
+        {
             fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
-            let pointing_at_return_type =
-                fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
-            if let (Some(cond_expr), true, false) = (
-                fcx.tcx.hir().get_if_cause(expr.hir_id),
-                expected.is_unit(),
-                pointing_at_return_type,
-            )
+            let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
+                &mut err,
+                expr,
+                expected,
+                found,
+                block_or_return_id,
+            );
+            if let Some(cond_expr) = fcx.tcx.hir().get_if_cause(expr.hir_id)
+                && expected.is_unit()
+                && !pointing_at_return_type
                 // If the block is from an external macro or try (`?`) desugaring, then
                 // do not suggest adding a semicolon, because there's nowhere to put it.
                 // See issues #81943 and #87051.
                 && matches!(
                     cond_expr.span.desugaring_kind(),
                     None | Some(DesugaringKind::WhileLoop)
-                ) && !in_external_macro(fcx.tcx.sess, cond_expr.span)
-                    && !matches!(
-                        cond_expr.kind,
-                        hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
-                    )
+                )
+                && !in_external_macro(fcx.tcx.sess, cond_expr.span)
+                && !matches!(
+                    cond_expr.kind,
+                    hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
+                )
             {
                 err.span_label(cond_expr.span, "expected this to be `()`");
                 if expr.can_have_side_effects() {
                     fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
                 }
             }
-            fcx.get_node_fn_decl(parent)
-                .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
-        } else {
-            fcx.get_fn_decl(parent_id)
         };
 
-        if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
-            if blk_id.is_none() {
-                fcx.suggest_missing_return_type(
-                    &mut err,
-                    fn_decl,
-                    expected,
-                    found,
-                    can_suggest,
-                    fn_id,
-                );
-            }
-        }
-
-        let mut parent_id = fcx.tcx.hir().get_parent_item(id).def_id;
-        let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id);
-        // When suggesting return, we need to account for closures and async blocks, not just items.
-        for (_, node) in fcx.tcx.hir().parent_iter(id) {
-            match node {
-                hir::Node::Expr(&hir::Expr {
-                    kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }),
-                    ..
-                }) => {
-                    parent_item = node;
-                    parent_id = *def_id;
-                    break;
-                }
-                hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
-                _ => {}
-            }
+        // If this is due to an explicit `return`, suggest adding a return type.
+        if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(parent_id)
+            && !due_to_block
+        {
+            fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
         }
 
-        if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) {
+        // If this is due to a block, then maybe we forgot a `return`/`break`.
+        if due_to_block
+            && let Some(expr) = expression
+            && let Some((parent_fn_decl, parent_id)) = fcx
+                .tcx
+                .hir()
+                .parent_iter(block_or_return_id)
+                .find_map(|(_, node)| Some((node.fn_decl()?, node.associated_body()?.0)))
+        {
             fcx.suggest_missing_break_or_return_expr(
-                &mut err, expr, fn_decl, expected, found, id, parent_id,
+                &mut err,
+                expr,
+                parent_fn_decl,
+                expected,
+                found,
+                block_or_return_id,
+                parent_id,
             );
         }
 
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 5a9eab1ffea..fade943c5ae 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1346,6 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if segment.ident.name != kw::Empty {
                     if let Some(err) = self.report_method_error(
                         span,
+                        Some(rcvr),
                         rcvr_t,
                         segment.ident,
                         SelfSource::MethodCall(rcvr),
@@ -3112,7 +3113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let true_errors = ocx.select_where_possible();
 
-            // Do a leak check -- we can't really report report a useful error here,
+            // Do a leak check -- we can't really report a useful error here,
             // but it at least avoids an ICE when the error has to do with higher-ranked
             // lifetimes.
             self.leak_check(outer_universe, Some(snapshot))?;
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index e456bd7fd4a..e8533c68c79 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -364,41 +364,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
             };
 
             let mut fallback_to = |ty| {
-                let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
-                    let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id);
-                    debug!(?unsafe_infer_vars);
-                    unsafe_infer_vars
-                });
-
-                let affected_unsafe_infer_vars =
-                    graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
-                        .filter_map(|x| unsafe_infer_vars.get(&x).copied())
-                        .collect::<Vec<_>>();
-
-                for (hir_id, span, reason) in affected_unsafe_infer_vars {
-                    self.tcx.emit_node_span_lint(
-                        lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
-                        hir_id,
-                        span,
-                        match reason {
-                            UnsafeUseReason::Call => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Call
-                            }
-                            UnsafeUseReason::Method => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Method
-                            }
-                            UnsafeUseReason::Path => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Path
-                            }
-                            UnsafeUseReason::UnionField => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField
-                            }
-                            UnsafeUseReason::Deref => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Deref
-                            }
-                        },
-                    );
-                }
+                self.lint_never_type_fallback_flowing_into_unsafe_code(
+                    &unsafe_infer_vars,
+                    &coercion_graph,
+                    root_vid,
+                );
 
                 diverging_fallback.insert(diverging_ty, ty);
             };
@@ -464,6 +434,41 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         diverging_fallback
     }
 
+    fn lint_never_type_fallback_flowing_into_unsafe_code(
+        &self,
+        unsafe_infer_vars: &OnceCell<UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>>,
+        coercion_graph: &VecGraph<ty::TyVid, true>,
+        root_vid: ty::TyVid,
+    ) {
+        let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
+            let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id);
+            debug!(?unsafe_infer_vars);
+            unsafe_infer_vars
+        });
+
+        let affected_unsafe_infer_vars =
+            graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
+                .filter_map(|x| unsafe_infer_vars.get(&x).copied())
+                .collect::<Vec<_>>();
+
+        for (hir_id, span, reason) in affected_unsafe_infer_vars {
+            self.tcx.emit_node_span_lint(
+                lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
+                hir_id,
+                span,
+                match reason {
+                    UnsafeUseReason::Call => errors::NeverTypeFallbackFlowingIntoUnsafe::Call,
+                    UnsafeUseReason::Method => errors::NeverTypeFallbackFlowingIntoUnsafe::Method,
+                    UnsafeUseReason::Path => errors::NeverTypeFallbackFlowingIntoUnsafe::Path,
+                    UnsafeUseReason::UnionField => {
+                        errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField
+                    }
+                    UnsafeUseReason::Deref => errors::NeverTypeFallbackFlowingIntoUnsafe::Deref,
+                },
+            );
+        }
+    }
+
     /// Returns a graph whose nodes are (unresolved) inference variables and where
     /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
     fn create_coercion_graph(&self) -> VecGraph<ty::TyVid, true> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 6e8ef044452..77f90c0c131 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -33,7 +33,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -834,6 +834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if item_name.name != kw::Empty {
                     if let Some(e) = self.report_method_error(
                         span,
+                        None,
                         ty.normalized,
                         item_name,
                         SelfSource::QPath(qself),
@@ -866,76 +867,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
-    /// Given a function `Node`, return its  `HirId` and `FnDecl` if it exists. Given a closure
-    /// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
-    /// This may seem confusing at first, but this is used in diagnostics for `async fn`,
-    /// for example, where most of the type checking actually happens within a nested closure,
-    /// but we often want access to the parent function's signature.
-    ///
-    /// Otherwise, return false.
-    pub(crate) fn get_node_fn_decl(
-        &self,
-        node: Node<'tcx>,
-    ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
-        match node {
-            Node::Item(&hir::Item {
-                ident,
-                kind: hir::ItemKind::Fn(ref sig, ..),
-                owner_id,
-                ..
-            }) => {
-                // This is less than ideal, it will not suggest a return type span on any
-                // method called `main`, regardless of whether it is actually the entry point,
-                // but it will still present it as the reason for the expected type.
-                Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
-            }
-            Node::TraitItem(&hir::TraitItem {
-                ident,
-                kind: hir::TraitItemKind::Fn(ref sig, ..),
-                owner_id,
-                ..
-            }) => Some((owner_id.def_id, &sig.decl, ident, true)),
-            Node::ImplItem(&hir::ImplItem {
-                ident,
-                kind: hir::ImplItemKind::Fn(ref sig, ..),
-                owner_id,
-                ..
-            }) => Some((owner_id.def_id, &sig.decl, ident, false)),
-            Node::Expr(&hir::Expr {
-                hir_id,
-                kind:
-                    hir::ExprKind::Closure(hir::Closure {
-                        kind: hir::ClosureKind::Coroutine(..), ..
-                    }),
-                ..
-            }) => {
-                let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
-                    Node::Item(&hir::Item {
-                        ident,
-                        kind: hir::ItemKind::Fn(ref sig, ..),
-                        owner_id,
-                        ..
-                    }) => (ident, sig, owner_id),
-                    Node::TraitItem(&hir::TraitItem {
-                        ident,
-                        kind: hir::TraitItemKind::Fn(ref sig, ..),
-                        owner_id,
-                        ..
-                    }) => (ident, sig, owner_id),
-                    Node::ImplItem(&hir::ImplItem {
-                        ident,
-                        kind: hir::ImplItemKind::Fn(ref sig, ..),
-                        owner_id,
-                        ..
-                    }) => (ident, sig, owner_id),
-                    _ => return None,
-                };
-                Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
-            }
-            _ => None,
-        }
-    }
-
     /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
     /// suggestion can be made, `None` otherwise.
     pub fn get_fn_decl(
@@ -944,10 +875,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
-        self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
-            let parent = self.tcx.hir_node(blk_id);
-            self.get_node_fn_decl(parent)
-                .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
+        self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
+            match self.tcx.hir_node(item_id) {
+                Node::Item(&hir::Item {
+                    ident,
+                    kind: hir::ItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                }) => {
+                    // This is less than ideal, it will not suggest a return type span on any
+                    // method called `main`, regardless of whether it is actually the entry point,
+                    // but it will still present it as the reason for the expected type.
+                    Some((owner_id.def_id, sig.decl, ident.name != sym::main))
+                }
+                Node::TraitItem(&hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                }) => Some((owner_id.def_id, sig.decl, true)),
+                // FIXME: Suggestable if this is not a trait implementation
+                Node::ImplItem(&hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                }) => Some((owner_id.def_id, sig.decl, false)),
+                Node::Expr(&hir::Expr {
+                    hir_id,
+                    kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
+                    ..
+                }) => {
+                    match kind {
+                        hir::ClosureKind::CoroutineClosure(_) => {
+                            // FIXME(async_closures): Implement this.
+                            return None;
+                        }
+                        hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
+                        hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                            _,
+                            hir::CoroutineSource::Fn,
+                        )) => {
+                            let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
+                                Node::Item(&hir::Item {
+                                    ident,
+                                    kind: hir::ItemKind::Fn(ref sig, ..),
+                                    owner_id,
+                                    ..
+                                }) => (ident, sig, owner_id),
+                                Node::TraitItem(&hir::TraitItem {
+                                    ident,
+                                    kind: hir::TraitItemKind::Fn(ref sig, ..),
+                                    owner_id,
+                                    ..
+                                }) => (ident, sig, owner_id),
+                                Node::ImplItem(&hir::ImplItem {
+                                    ident,
+                                    kind: hir::ImplItemKind::Fn(ref sig, ..),
+                                    owner_id,
+                                    ..
+                                }) => (ident, sig, owner_id),
+                                _ => return None,
+                            };
+                            Some((owner_id.def_id, sig.decl, ident.name != sym::main))
+                        }
+                        _ => None,
+                    }
+                }
+                _ => None,
+            }
         })
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index aea34407a2d..b8333d47493 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1774,7 +1774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // that highlight errors inline.
                     let mut sp = blk.span;
                     let mut fn_span = None;
-                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
+                    if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
                         let ret_sp = decl.output.span();
                         if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
                             // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
@@ -1782,7 +1782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // the span we're aiming at correspond to a `fn` body.
                             if block_sp == blk.span {
                                 sp = ret_sp;
-                                fn_span = Some(ident.span);
+                                fn_span = self.tcx.def_ident_span(fn_def_id);
                             }
                         }
                     }
@@ -1897,15 +1897,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         None
     }
 
-    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
-    pub(crate) fn get_parent_fn_decl(
-        &self,
-        blk_id: HirId,
-    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
-        self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
-    }
-
     /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
     /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
     /// when given code like the following:
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 56e13cd679d..cfd4dd4d1dd 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -800,6 +800,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         can_suggest: bool,
         fn_id: LocalDefId,
     ) -> bool {
+        // Can't suggest `->` on a block-like coroutine
+        if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
+            self.tcx.coroutine_kind(fn_id)
+        {
+            return false;
+        }
+
         let found =
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
@@ -1909,7 +1916,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let returned = matches!(
             self.tcx.parent_hir_node(expr.hir_id),
             hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
-        ) || map.get_return_block(expr.hir_id).is_some();
+        ) || map.get_fn_id_for_return_block(expr.hir_id).is_some();
         if returned
             && let ty::Adt(e, args_e) = expected.kind()
             && let ty::Adt(f, args_f) = found.kind()
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 74254058534..9c64f9475cf 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -451,7 +451,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // `foo.bar::<u32>(...)` -- the `Self` type here will be the
         // type of `foo` (possibly adjusted), but we don't want to
         // include that. We want just the `[_, u32]` part.
-        if !args.is_empty() && !generics.own_params.is_empty() {
+        if !args.is_empty() && !generics.is_own_empty() {
             let user_type_annotation = self.probe(|_| {
                 let user_args = UserArgs {
                     args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| {
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index a40fa600c19..4165ccb1b80 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -3,7 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
 
 mod confirm;
-mod prelude2021;
+mod prelude_edition_lints;
 pub mod probe;
 mod suggest;
 
@@ -186,7 +186,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let pick =
             self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
 
-        self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
+        self.lint_edition_dependent_dot_call(
+            self_ty, segment, span, call_expr, self_expr, &pick, args,
+        );
 
         for &import_id in &pick.import_ids {
             debug!("used_trait_import: {:?}", import_id);
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index a305461344d..e9eab6969b3 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -1,12 +1,12 @@
-use crate::{
-    method::probe::{self, Pick},
-    FnCtxt,
-};
+use crate::method::probe::{self, Pick};
+use crate::FnCtxt;
+
 use hir::def_id::DefId;
 use hir::HirId;
 use hir::ItemKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
@@ -17,7 +17,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use std::fmt::Write;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub(super) fn lint_dot_call_from_2018(
+    pub(super) fn lint_edition_dependent_dot_call(
         &self,
         self_ty: Ty<'tcx>,
         segment: &hir::PathSegment<'_>,
@@ -32,22 +32,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             segment.ident, self_ty, call_expr, self_expr
         );
 
-        // Rust 2021 and later is already using the new prelude
-        if span.at_least_rust_2021() {
-            return;
-        }
-
-        let prelude_or_array_lint = match segment.ident.name {
+        let (prelude_or_array_lint, edition) = match segment.ident.name {
             // `try_into` was added to the prelude in Rust 2021.
-            sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
+            sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
             // `into_iter` wasn't added to the prelude,
             // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
             // before Rust 2021, which results in the same problem.
             // It is only a problem for arrays.
-            sym::into_iter if let ty::Array(..) = self_ty.kind() => {
-                // In this case, it wasn't really a prelude addition that was the problem.
-                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
-                rustc_lint::ARRAY_INTO_ITER
+            sym::into_iter => {
+                if let ty::Array(..) = self_ty.kind()
+                    && !span.at_least_rust_2021()
+                {
+                    // In this case, it wasn't really a prelude addition that was the problem.
+                    // Instead, the problem is that the array-into_iter hack will no longer
+                    // apply in Rust 2021.
+                    (ARRAY_INTO_ITER, "2021")
+                } else if self_ty.is_box()
+                    && self_ty.boxed_ty().is_slice()
+                    && !span.at_least_rust_2024()
+                {
+                    // In this case, it wasn't really a prelude addition that was the problem.
+                    // Instead, the problem is that the boxed-slice-into_iter hack will no
+                    // longer apply in Rust 2024.
+                    (BOXED_SLICE_INTO_ITER, "2024")
+                } else {
+                    return;
+                }
             }
             _ => return,
         };
@@ -81,7 +91,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 prelude_or_array_lint,
                 self_expr.hir_id,
                 self_expr.span,
-                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
+                format!(
+                    "trait method `{}` will become ambiguous in Rust {edition}",
+                    segment.ident.name
+                ),
                 |lint| {
                     let sp = self_expr.span;
 
@@ -131,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 prelude_or_array_lint,
                 call_expr.hir_id,
                 call_expr.span,
-                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
+                format!(
+                    "trait method `{}` will become ambiguous in Rust {edition}",
+                    segment.ident.name
+                ),
                 |lint| {
                     let sp = call_expr.span;
                     let trait_name = self.trait_path_or_bare_name(
@@ -279,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if !self_ty_name.contains('<') {
                     if let ty::Adt(def, _) = self_ty.kind() {
                         let generics = self.tcx.generics_of(def.did());
-                        if !generics.own_params.is_empty() {
+                        if !generics.is_own_empty() {
                             let counts = generics.own_counts();
                             self_ty_name += &format!(
                                 "<{}>",
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index fc652490a40..e0a60337c3b 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1444,6 +1444,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                 return ProbeResult::NoMatch;
                             }
                         }
+
+                        // Some trait methods are excluded for boxed slices before 2024.
+                        // (`boxed_slice.into_iter()` wants a slice iterator for compatibility.)
+                        if self_ty.is_box()
+                            && self_ty.boxed_ty().is_slice()
+                            && !method_name.span.at_least_rust_2024()
+                        {
+                            let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
+                            if trait_def.skip_boxed_slice_during_method_dispatch {
+                                return ProbeResult::NoMatch;
+                            }
+                        }
                     }
 
                     let trait_ref = self.instantiate_binder_with_fresh_vars(
@@ -1754,7 +1766,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let generics = self.tcx.generics_of(method);
         assert_eq!(args.len(), generics.parent_count);
 
-        let xform_fn_sig = if generics.own_params.is_empty() {
+        let xform_fn_sig = if generics.is_own_empty() {
             fn_sig.instantiate(self.tcx, args)
         } else {
             let args = GenericArgs::for_item(self.tcx, method, |param, _| {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index db510d44392..54af8354c4c 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -7,6 +7,7 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
 use crate::Expectation;
 use crate::FnCtxt;
 use core::ops::ControlFlow;
+use hir::Expr;
 use rustc_ast::ast::Mutability;
 use rustc_attr::parse_confusables;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -19,7 +20,6 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::PatKind::Binding;
 use rustc_hir::PathSegment;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::{self, RegionVariableOrigin};
@@ -46,7 +46,7 @@ use std::borrow::Cow;
 
 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{self, Visitor};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn report_method_error(
         &self,
         span: Span,
+        rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
@@ -212,6 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             MethodError::NoMatch(mut no_match_data) => {
                 return self.report_no_match_method_error(
                     span,
+                    rcvr_opt,
                     rcvr_ty,
                     item_name,
                     source,
@@ -356,9 +358,197 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err
     }
 
+    pub fn suggest_use_shadowed_binding_with_method(
+        &self,
+        rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
+        method_name: Ident,
+        ty_str_reported: &str,
+        err: &mut Diag<'_>,
+    ) {
+        #[derive(Debug)]
+        struct LetStmt {
+            ty_hir_id_opt: Option<hir::HirId>,
+            binding_id: hir::HirId,
+            span: Span,
+            init_hir_id: hir::HirId,
+        }
+
+        // Used for finding suggest binding.
+        // ```rust
+        // earlier binding for suggesting:
+        // let y = vec![1, 2];
+        // now binding:
+        // if let Some(y) = x {
+        //     y.push(y);
+        // }
+        // ```
+        struct LetVisitor<'a, 'tcx> {
+            // Error binding which don't have `method_name`.
+            binding_name: Symbol,
+            binding_id: hir::HirId,
+            // Used for check if the suggest binding has `method_name`.
+            fcx: &'a FnCtxt<'a, 'tcx>,
+            call_expr: &'tcx Expr<'tcx>,
+            method_name: Ident,
+            // Suggest the binding which is shallowed.
+            sugg_let: Option<LetStmt>,
+        }
+
+        impl<'a, 'tcx> LetVisitor<'a, 'tcx> {
+            // Check scope of binding.
+            fn is_sub_scope(&self, sub_id: hir::ItemLocalId, super_id: hir::ItemLocalId) -> bool {
+                let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_id);
+                if let Some(sub_var_scope) = scope_tree.var_scope(sub_id)
+                    && let Some(super_var_scope) = scope_tree.var_scope(super_id)
+                    && scope_tree.is_subscope_of(sub_var_scope, super_var_scope)
+                {
+                    return true;
+                }
+                false
+            }
+
+            // Check if an earlier shadowed binding make `the receiver` of a MethodCall has the method.
+            // If it does, record the earlier binding for subsequent notes.
+            fn check_and_add_sugg_binding(&mut self, binding: LetStmt) -> bool {
+                if !self.is_sub_scope(self.binding_id.local_id, binding.binding_id.local_id) {
+                    return false;
+                }
+
+                // Get the earlier shadowed binding'ty and use it to check the method.
+                if let Some(ty_hir_id) = binding.ty_hir_id_opt
+                    && let Some(tyck_ty) = self.fcx.node_ty_opt(ty_hir_id)
+                {
+                    if self
+                        .fcx
+                        .lookup_probe_for_diagnostic(
+                            self.method_name,
+                            tyck_ty,
+                            self.call_expr,
+                            ProbeScope::TraitsInScope,
+                            None,
+                        )
+                        .is_ok()
+                    {
+                        self.sugg_let = Some(binding);
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+
+                // If the shadowed binding has an an itializer expression,
+                // use the initializer expression'ty to try to find the method again.
+                // For example like:  `let mut x = Vec::new();`,
+                // `Vec::new()` is the itializer expression.
+                if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
+                    && self
+                        .fcx
+                        .lookup_probe_for_diagnostic(
+                            self.method_name,
+                            self_ty,
+                            self.call_expr,
+                            ProbeScope::TraitsInScope,
+                            None,
+                        )
+                        .is_ok()
+                {
+                    self.sugg_let = Some(binding);
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        impl<'v> Visitor<'v> for LetVisitor<'_, '_> {
+            type Result = ControlFlow<()>;
+            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
+                if let hir::StmtKind::Let(&hir::LetStmt { pat, ty, init, .. }) = ex.kind
+                    && let hir::PatKind::Binding(_, binding_id, binding_name, ..) = pat.kind
+                    && let Some(init) = init
+                    && binding_name.name == self.binding_name
+                    && binding_id != self.binding_id
+                {
+                    if self.check_and_add_sugg_binding(LetStmt {
+                        ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
+                        binding_id: binding_id,
+                        span: pat.span,
+                        init_hir_id: init.hir_id,
+                    }) {
+                        return ControlFlow::Break(());
+                    }
+                    ControlFlow::Continue(())
+                } else {
+                    hir::intravisit::walk_stmt(self, ex)
+                }
+            }
+
+            // Used for find the error binding.
+            // When the visitor reaches this point, all the shadowed bindings
+            // have been found, so the visitor ends.
+            fn visit_pat(&mut self, p: &'v hir::Pat<'v>) -> Self::Result {
+                match p.kind {
+                    hir::PatKind::Binding(_, binding_id, binding_name, _) => {
+                        if binding_name.name == self.binding_name && binding_id == self.binding_id {
+                            return ControlFlow::Break(());
+                        }
+                    }
+                    _ => {
+                        intravisit::walk_pat(self, p);
+                    }
+                }
+                ControlFlow::Continue(())
+            }
+        }
+
+        if let Some(rcvr) = rcvr_opt
+            && let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind
+            && let hir::def::Res::Local(recv_id) = path.res
+            && let Some(segment) = path.segments.first()
+        {
+            let map = self.infcx.tcx.hir();
+            let body_id = self.tcx.hir().body_owned_by(self.body_id);
+            let body = map.body(body_id);
+
+            if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) {
+                let mut let_visitor = LetVisitor {
+                    fcx: self,
+                    call_expr,
+                    binding_name: segment.ident.name,
+                    binding_id: recv_id,
+                    method_name,
+                    sugg_let: None,
+                };
+                let_visitor.visit_body(body);
+                if let Some(sugg_let) = let_visitor.sugg_let
+                    && let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id)
+                {
+                    let _sm = self.infcx.tcx.sess.source_map();
+                    let rcvr_name = segment.ident.name;
+                    let mut span = MultiSpan::from_span(sugg_let.span);
+                    span.push_span_label(sugg_let.span,
+                            format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
+                    span.push_span_label(
+                        self.tcx.hir().span(recv_id),
+                        format!(
+                            "earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
+                        ),
+                    );
+                    err.span_note(
+                        span,
+                        format!(
+                            "there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
+                                    that has method `{method_name}` available"
+                        ),
+                    );
+                }
+            }
+        }
+    }
+
     pub fn report_no_match_method_error(
         &self,
         mut span: Span,
+        rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
@@ -451,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
             self.suggest_missing_writer(rcvr_ty, rcvr_expr)
         } else {
-            tcx.dcx().create_err(NoAssociatedItem {
+            let mut err = tcx.dcx().create_err(NoAssociatedItem {
                 span,
                 item_kind,
                 item_name,
@@ -461,9 +651,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     rcvr_ty.prefix_string(self.tcx)
                 },
-                ty_str: ty_str_reported,
+                ty_str: ty_str_reported.clone(),
                 trait_missing_method,
-            })
+            });
+
+            if is_method {
+                self.suggest_use_shadowed_binding_with_method(
+                    rcvr_opt,
+                    item_name,
+                    &ty_str_reported,
+                    &mut err,
+                );
+            }
+
+            err
         };
         if tcx.sess.source_map().is_multiline(sugg_span) {
             err.span_label(sugg_span.with_hi(span.lo()), "");
@@ -2240,7 +2441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
                     fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
                         if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
-                            && let Binding(_, _, ident, ..) = pat.kind
+                            && let hir::PatKind::Binding(_, _, ident, ..) = pat.kind
                             && ident.name == self.ident_name
                         {
                             ControlFlow::Break(init)
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index 64f52ea7ac1..8f1c4ad462a 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -164,7 +164,10 @@ infer_label_bad = {$bad_kind ->
 infer_lf_bound_not_satisfied = lifetime bound not satisfied
 infer_lifetime_mismatch = lifetime mismatch
 
-infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+infer_lifetime_param_suggestion = consider {$is_reuse ->
+    [true] reusing
+    *[false] introducing
+} a named lifetime parameter{$is_impl ->
     [true] {" "}and update trait if needed
     *[false] {""}
 }
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 2acaeac2439..8bb0dc39143 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,9 +1,11 @@
 use hir::GenericParamKind;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
     MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir as hir;
+use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::FnRetTy;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
@@ -355,31 +357,33 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
         _f: &F,
     ) {
         let mut mk_suggestion = || {
-            let (
-                hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
-                hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
-            ) = (self.ty_sub, self.ty_sup)
-            else {
-                return false;
-            };
-
-            if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
-                return false;
-            };
-
             let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
                 return false;
             };
 
             let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
             let is_impl = matches!(&node, hir::Node::ImplItem(_));
-            let generics = match node {
+            let (generics, parent_generics) = match node {
                 hir::Node::Item(&hir::Item {
                     kind: hir::ItemKind::Fn(_, ref generics, ..),
                     ..
                 })
                 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
+                    generics,
+                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
+                    {
+                        hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
+                            ..
+                        })
+                        | hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
+                            ..
+                        }) => Some(generics),
+                        _ => None,
+                    },
+                ),
                 _ => return false,
             };
 
@@ -390,24 +394,112 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                 .map(|p| p.name.ident().name)
                 .find(|i| *i != kw::UnderscoreLifetime);
             let introduce_new = suggestion_param_name.is_none();
+
+            let mut default = "'a".to_string();
+            if let Some(parent_generics) = parent_generics {
+                let used: FxHashSet<_> = parent_generics
+                    .params
+                    .iter()
+                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                    .map(|p| p.name.ident().name)
+                    .filter(|i| *i != kw::UnderscoreLifetime)
+                    .map(|l| l.to_string())
+                    .collect();
+                if let Some(lt) =
+                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
+                {
+                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
+                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
+                    // likely to be an over-constraining lifetime requirement, so we always add a
+                    // lifetime to the `fn`.
+                    default = lt;
+                }
+            }
             let suggestion_param_name =
-                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
-            debug!(?lifetime_sup.ident.span);
-            debug!(?lifetime_sub.ident.span);
-            let make_suggestion = |ident: Ident| {
-                let sugg = if ident.name == kw::Empty {
-                    format!("{suggestion_param_name}, ")
-                } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
-                    format!("{suggestion_param_name} ")
-                } else {
-                    suggestion_param_name.clone()
-                };
-                (ident.span, sugg)
-            };
-            let mut suggestions =
-                vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
+
+            struct ImplicitLifetimeFinder {
+                suggestions: Vec<(Span, String)>,
+                suggestion_param_name: String,
+            }
 
+            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
+                fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+                    let make_suggestion = |ident: Ident| {
+                        if ident.name == kw::Empty && ident.span.is_empty() {
+                            format!("{}, ", self.suggestion_param_name)
+                        } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
+                            format!("{} ", self.suggestion_param_name)
+                        } else {
+                            self.suggestion_param_name.clone()
+                        }
+                    };
+                    match ty.kind {
+                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
+                            for segment in path.segments {
+                                if let Some(args) = segment.args {
+                                    if args.args.iter().all(|arg| {
+                                        matches!(
+                                            arg,
+                                            hir::GenericArg::Lifetime(lifetime)
+                                            if lifetime.ident.name == kw::Empty
+                                        )
+                                    }) {
+                                        self.suggestions.push((
+                                            segment.ident.span.shrink_to_hi(),
+                                            format!(
+                                                "<{}>",
+                                                args.args
+                                                    .iter()
+                                                    .map(|_| self.suggestion_param_name.clone())
+                                                    .collect::<Vec<_>>()
+                                                    .join(", ")
+                                            ),
+                                        ));
+                                    } else {
+                                        for arg in args.args {
+                                            if let hir::GenericArg::Lifetime(lifetime) = arg
+                                                && lifetime.is_anonymous()
+                                            {
+                                                self.suggestions.push((
+                                                    lifetime.ident.span,
+                                                    make_suggestion(lifetime.ident),
+                                                ));
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
+                            self.suggestions
+                                .push((lifetime.ident.span, make_suggestion(lifetime.ident)));
+                        }
+                        _ => {}
+                    }
+                    walk_ty(self, ty);
+                }
+            }
+            let mut visitor = ImplicitLifetimeFinder {
+                suggestions: vec![],
+                suggestion_param_name: suggestion_param_name.clone(),
+            };
+            if let Some(fn_decl) = node.fn_decl()
+                && let hir::FnRetTy::Return(ty) = fn_decl.output
+            {
+                visitor.visit_ty(ty);
+            }
+            if visitor.suggestions.is_empty() {
+                // Do not suggest constraining the `&self` param, but rather the return type.
+                // If that is wrong (because it is not sufficient), a follow up error will tell the
+                // user to fix it. This way we lower the chances of *over* constraining, but still
+                // get the cake of "correctly" contrained in two steps.
+                visitor.visit_ty(self.ty_sup);
+            }
+            visitor.visit_ty(self.ty_sub);
+            if visitor.suggestions.is_empty() {
+                return false;
+            }
             if introduce_new {
                 let new_param_suggestion = if let Some(first) =
                     generics.params.iter().find(|p| !p.name.ident().span.is_empty())
@@ -417,15 +509,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                     (generics.span, format!("<{suggestion_param_name}>"))
                 };
 
-                suggestions.push(new_param_suggestion);
+                visitor.suggestions.push(new_param_suggestion);
             }
-
-            diag.multipart_suggestion(
+            diag.multipart_suggestion_verbose(
                 fluent::infer_lifetime_param_suggestion,
-                suggestions,
+                visitor.suggestions,
                 Applicability::MaybeIncorrect,
             );
             diag.arg("is_impl", is_impl);
+            diag.arg("is_reuse", !introduce_new);
+
             true
         };
         if mk_suggestion() && self.add_note {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 723f4c81ca5..8d4011421bd 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -369,33 +369,43 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
         }
     }
 
-    fn root_ty_var(&self, vid: TyVid) -> TyVid {
-        self.root_var(vid)
+    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
+        self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
     }
 
-    fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
-        self.probe_ty_var(vid).ok()
+    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
+        self.defining_opaque_types
     }
 
-    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
-        let re = self
-            .inner
-            .borrow_mut()
-            .unwrap_region_constraints()
-            .opportunistic_resolve_var(self.tcx, vid);
-        if *re == ty::ReVar(vid) { None } else { Some(re) }
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
+        match self.probe_ty_var(vid) {
+            Ok(ty) => ty,
+            Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
+        }
     }
 
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
-        self.root_const_var(vid)
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_int_var(vid)
     }
 
-    fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
-        self.probe_const_var(vid).ok()
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_float_var(vid)
     }
 
-    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types
+    fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        match self.probe_const_var(vid) {
+            Ok(ct) => ct,
+            Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty),
+        }
+    }
+
+    fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        match self.probe_effect_var(vid) {
+            Some(ct) => ct,
+            None => {
+                ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty)
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 61b13dd9a54..21ef2e89523 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -173,84 +173,3 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
         }
     }
 }
-
-///////////////////////////////////////////////////////////////////////////
-// EAGER RESOLUTION
-
-/// Resolves ty, region, and const vars to their inferred values or their root vars.
-pub struct EagerResolver<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> EagerResolver<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        EagerResolver { infcx }
-    }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match *t.kind() {
-            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
-                Ok(t) => t.fold_with(self),
-                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
-            },
-            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
-            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
-            _ => {
-                if t.has_infer() {
-                    t.super_fold_with(self)
-                } else {
-                    t
-                }
-            }
-        }
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            ty::ReVar(vid) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .unwrap_region_constraints()
-                .opportunistic_resolve_var(self.infcx.tcx, vid),
-            _ => r,
-        }
-    }
-
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
-                // FIXME: we need to fold the ty too, I think.
-                match self.infcx.probe_const_var(vid) {
-                    Ok(c) => c.fold_with(self),
-                    Err(_) => {
-                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
-                    }
-                }
-            }
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
-                debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
-                self.infcx.probe_effect_var(vid).unwrap_or_else(|| {
-                    ty::Const::new_infer(
-                        self.infcx.tcx,
-                        ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
-                        self.infcx.tcx.types.bool,
-                    )
-                })
-            }
-            _ => {
-                if c.has_infer() {
-                    c.super_fold_with(self)
-                } else {
-                    c
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 55304bbbd92..d43be6cebcb 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -389,6 +389,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
 
     util::run_in_thread_pool_with_globals(
+        &early_dcx,
         config.opts.edition,
         config.opts.unstable_opts.threads,
         SourceMapInputs { file_loader, path_mapping, hash_kind },
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index ce4d3825015..987e48a1a76 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -51,20 +51,38 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
 pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
 pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
 
-fn init_stack_size() -> usize {
+fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize {
     // Obey the environment setting or default
     *STACK_SIZE.get_or_init(|| {
         env::var_os("RUST_MIN_STACK")
-            .map(|os_str| os_str.to_string_lossy().into_owned())
-            // ignore if it is set to nothing
-            .filter(|s| s.trim() != "")
-            .map(|s| s.trim().parse::<usize>().unwrap())
+            .as_ref()
+            .map(|os_str| os_str.to_string_lossy())
+            // if someone finds out `export RUST_MIN_STACK=640000` isn't enough stack
+            // they might try to "unset" it by running `RUST_MIN_STACK=  rustc code.rs`
+            // this is wrong, but std would nonetheless "do what they mean", so let's do likewise
+            .filter(|s| !s.trim().is_empty())
+            // rustc is a batch program, so error early on inputs which are unlikely to be intended
+            // so no one thinks we parsed them setting `RUST_MIN_STACK="64 megabytes"`
+            // FIXME: we could accept `RUST_MIN_STACK=64MB`, perhaps?
+            .map(|s| {
+                let s = s.trim();
+                // FIXME(workingjubilee): add proper diagnostics when we factor out "pre-run" setup
+                #[allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)]
+                s.parse::<usize>().unwrap_or_else(|_| {
+                    let mut err = early_dcx.early_struct_fatal(format!(
+                        r#"`RUST_MIN_STACK` should be a number of bytes, but was "{s}""#,
+                    ));
+                    err.note("you can also unset `RUST_MIN_STACK` to use the default stack size");
+                    err.emit()
+                })
+            })
             // otherwise pick a consistent default
             .unwrap_or(DEFAULT_STACK_SIZE)
     })
 }
 
 fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+    thread_stack_size: usize,
     edition: Edition,
     sm_inputs: SourceMapInputs,
     f: F,
@@ -75,7 +93,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
     // the parallel compiler, in particular to ensure there is no accidental
     // sharing of data between the main thread and the compilation thread
     // (which might cause problems for the parallel compiler).
-    let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
+    let builder = thread::Builder::new().name("rustc".to_string()).stack_size(thread_stack_size);
 
     // We build the session globals and run `f` on the spawned thread, because
     // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
@@ -100,16 +118,19 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
 
 #[cfg(not(parallel_compiler))]
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+    thread_builder_diag: &EarlyDiagCtxt,
     edition: Edition,
     _threads: usize,
     sm_inputs: SourceMapInputs,
     f: F,
 ) -> R {
-    run_in_thread_with_globals(edition, sm_inputs, f)
+    let thread_stack_size = init_stack_size(thread_builder_diag);
+    run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, f)
 }
 
 #[cfg(parallel_compiler)]
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+    thread_builder_diag: &EarlyDiagCtxt,
     edition: Edition,
     threads: usize,
     sm_inputs: SourceMapInputs,
@@ -121,10 +142,12 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
     use rustc_query_system::query::{break_query_cycles, QueryContext};
     use std::process;
 
+    let thread_stack_size = init_stack_size(thread_builder_diag);
+
     let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
     if !sync::is_dyn_thread_safe() {
-        return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
+        return run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, |current_gcx| {
             // Register the thread for use with the `WorkerLocal` type.
             registry.register();
 
@@ -167,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
                 })
                 .unwrap();
         })
-        .stack_size(init_stack_size());
+        .stack_size(thread_stack_size);
 
     // We create the session globals on the main thread, then create the thread
     // pool. Upon creation, each worker thread created gets a copy of the
@@ -376,31 +399,17 @@ pub(crate) fn check_attr_crate_type(
 
                 if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() {
                     let span = spanned.span;
-                    let lev_candidate = find_best_match_for_name(
+                    let candidate = find_best_match_for_name(
                         &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
                         n,
                         None,
                     );
-                    if let Some(candidate) = lev_candidate {
-                        lint_buffer.buffer_lint_with_diagnostic(
-                            lint::builtin::UNKNOWN_CRATE_TYPES,
-                            ast::CRATE_NODE_ID,
-                            span,
-                            "invalid `crate_type` value",
-                            BuiltinLintDiag::UnknownCrateTypes(
-                                span,
-                                "did you mean".to_string(),
-                                format!("\"{candidate}\""),
-                            ),
-                        );
-                    } else {
-                        lint_buffer.buffer_lint(
-                            lint::builtin::UNKNOWN_CRATE_TYPES,
-                            ast::CRATE_NODE_ID,
-                            span,
-                            "invalid `crate_type` value",
-                        );
-                    }
+                    lint_buffer.buffer_lint(
+                        lint::builtin::UNKNOWN_CRATE_TYPES,
+                        ast::CRATE_NODE_ID,
+                        span,
+                        BuiltinLintDiag::UnknownCrateTypes { span, candidate },
+                    );
                 }
             } else {
                 // This is here mainly to check for using a macro, such as
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 5180fce2eb3..6f6480a4964 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -1,13 +1,19 @@
+lint_abs_path_with_module = absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+    .suggestion = use `crate`
+
+lint_ambiguous_glob_reexport = ambiguous glob re-exports
+    .label_first_reexport = the name `{$name}` in the {$namespace} namespace is first re-exported here
+    .label_duplicate_reexport = but the name `{$name}` in the {$namespace} namespace is also re-exported here
+
 lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
     .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
     .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
 
-lint_array_into_iter =
-    this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
-    .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
-    .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
-    .use_explicit_into_iter_suggestion =
-        or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+lint_associated_const_elided_lifetime = {$elided ->
+        [true] `&` without an explicit lifetime name cannot be used here
+        *[false] `'_` cannot be used here
+    }
+    .suggestion = use the `'static` lifetime
 
 lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
     .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
@@ -26,10 +32,19 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order
 lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
     .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
 
+lint_avoid_att_syntax =
+    avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
+
+lint_avoid_intel_syntax =
+    avoid using `.intel_syntax`, Intel syntax is the default
+
 lint_bad_attribute_argument = bad attribute argument
 
 lint_bad_opt_access = {$msg}
 
+lint_break_with_label_and_loop = this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression
+    .suggestion = wrap this expression in parentheses
+
 lint_builtin_allow_internal_unsafe =
     `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
 
@@ -37,6 +52,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be
     .suggestion = try naming the parameter or explicitly ignoring it
 
 lint_builtin_asm_labels = avoid using named labels in inline assembly
+    .help = only local labels of the form `<number>:` should be used in inline asm
+    .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
 
@@ -161,6 +178,12 @@ lint_builtin_unused_doc_comment = unused doc comment
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
+lint_byte_slice_in_packed_struct_with_derive = {$ty} slice in a packed struct that derives a built-in trait
+    .help = consider implementing the trait by hand, or remove the `packed` attribute
+
+lint_cfg_attr_no_attributes =
+    `#[cfg_attr]` does not expand to any attributes
+
 lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
 
 lint_command_line_source = `forbid` lint level was set on command line
@@ -169,12 +192,20 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
     .current_use = this identifier can be confused with `{$existing_sym}`
     .other_use = other identifier used here
 
+lint_crate_name_in_cfg_attr_deprecated =
+    `crate_name` within an `#![cfg_attr]` attribute is deprecated
+
+lint_crate_type_in_cfg_attr_deprecated =
+    `crate_type` within an `#![cfg_attr]` attribute is deprecated
+
 lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .as_ptr_label = this pointer will be invalid
     .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
     .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
     .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
 
+lint_custom_inner_attribute_unstable = custom inner attributes are unstable
+
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
 
@@ -185,6 +216,11 @@ lint_deprecated_lint_name =
     .suggestion = change it to
     .help = change it to {$replace}
 
+lint_deprecated_where_clause_location = where clause not allowed here
+    .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+    .suggestion_move_to_end = move it to the end of the type declaration
+    .suggestion_remove_where = remove this `where`
+
 lint_diag_out_of_impl =
     diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
 
@@ -202,6 +238,11 @@ lint_dropping_references = calls to `std::mem::drop` with a reference instead of
     .label = argument has type `{$arg_ty}`
     .note = use `let _ = ...` to ignore the expression or result
 
+lint_duplicate_macro_attribute =
+    duplicated attribute
+
+lint_duplicate_matcher_binding = duplicate matcher binding
+
 lint_enum_intrinsics_mem_discriminant =
     the return value of `mem::discriminant` is unspecified when called with a non-enum type
     .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum.
@@ -214,6 +255,13 @@ lint_expectation = this lint expectation is unfulfilled
     .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
     .rationale = {$rationale}
 
+lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition
+    .suggestion = convert it to a `use`
+
+lint_extern_without_abi = extern declarations without an explicit ABI are deprecated
+    .label = ABI should be specified here
+    .help = the default ABI is {$default_abi}
+
 lint_for_loops_over_fallibles =
     for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
     .suggestion = consider using `if let` to clear intent
@@ -228,6 +276,12 @@ lint_forgetting_references = calls to `std::mem::forget` with a reference instea
     .label = argument has type `{$arg_ty}`
     .note = use `let _ = ...` to ignore the expression or result
 
+lint_hidden_glob_reexport = private item shadows public glob re-export
+    .note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here
+    .note_private_item = but the private item here shadows it
+
+lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated
+
 lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
     .label = this {$label} contains {$count ->
         [one] an invisible
@@ -269,6 +323,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
 
 lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
 
+lint_ill_formed_attribute_input = {$num_suggestions ->
+        [1] attribute must be of the form {$suggestions}
+        *[other] valid forms for the attribute are {$suggestions}
+    }
+
 lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024
     .note = specifically, {$num_captured ->
         [one] this lifetime is
@@ -339,6 +398,14 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
 lint_improper_ctypes_union_layout_reason = this union has unspecified layout
 lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
 
+lint_incomplete_include =
+    include macro expected single expression in source
+
+lint_inner_macro_attribute_unstable = inner macro attributes are unstable
+
+lint_invalid_crate_type_value = invalid `crate_type` value
+    .suggestion = did you mean
+
 # FIXME: we should ordinalize $valid_up_to when we add support for doing so
 lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error
     .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
@@ -367,9 +434,22 @@ lint_invalid_reference_casting_note_book = for more information, visit <https://
 
 lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
 
+lint_legacy_derive_helpers = derive helper attribute is used before it is introduced
+    .label = the attribute is introduced here
+
 lint_lintpass_by_hand = implementing `LintPass` by hand
     .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
+lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
+    .note = the macro is defined here
+
+lint_macro_is_private = macro `{$ident}` is private
+
+lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used
+
+lint_macro_use_deprecated =
+    deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+
 lint_malformed_attribute = malformed lint attribute input
 
 lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
@@ -379,6 +459,12 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
     .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
     .suggestion = you might have meant to use `Iterator::for_each`
 
+lint_metavariable_still_repeating = variable '{$name}' is still repeating at this depth
+
+lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
+
+lint_missing_fragment_specifier = missing fragment specifier
+
 lint_mixed_script_confusables =
     the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
     .includes_note = the usage includes {$includes}
@@ -386,6 +472,11 @@ lint_mixed_script_confusables =
 
 lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
 
+lint_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name
+    .label_named_arg = this named argument is referred to by position in formatting string
+    .label_position_arg = this formatting argument uses named argument `{$named_arg_name}` by position
+    .suggestion = use the named argument by name to avoid ambiguity
+
 lint_node_source = `forbid` level set here
     .note = {$reason}
 
@@ -497,6 +588,9 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
 
+lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+    .suggestion = use pat_param to preserve semantics
+
 lint_overflowing_bin_hex = literal out of range for `{$ty}`
     .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
     .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`
@@ -526,6 +620,21 @@ lint_path_statement_drop = path statement drops value
 
 lint_path_statement_no_effect = path statement with no effect
 
+lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies
+    .label = pattern not allowed in function without body
+
+lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations
+    .label = pattern not allowed in foreign function
+
+lint_private_extern_crate_reexport =
+    extern crate `{$ident}` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
+
+lint_proc_macro_back_compat = using an old version of `{$crate_name}`
+    .note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
+
+lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope
+    .label = names from parent modules are not accessible without an explicit import
+
 lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false
     .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}`
@@ -547,6 +656,16 @@ lint_reason_must_be_string_literal = reason must be a string literal
 
 lint_reason_must_come_last = reason in lint attribute must come last
 
+lint_redundant_import = the item `{$ident}` is imported redundantly
+    .label_imported_here = the item `{ident}` is already imported here
+    .label_defined_here = the item `{ident}` is already defined here
+    .label_imported_prelude = the item `{ident}` is already imported by the extern prelude
+    .label_defined_prelude = the item `{ident}` is already defined by the extern prelude
+
+lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough
+    .note = the most public imported item is `{$max_vis}`
+    .help = reduce the glob import's visibility or increase visibility of imported items
+
 lint_redundant_semicolons =
     unnecessary trailing {$multiple ->
         [true] semicolons
@@ -557,6 +676,8 @@ lint_redundant_semicolons =
         *[false] this semicolon
     }
 
+lint_remove_mut_from_pattern = remove `mut` from the parameter
+
 lint_removed_lint = lint `{$name}` has been removed: {$reason}
 
 lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
@@ -565,6 +686,22 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
 
 lint_requested_level = requested on the command line with `{$level} {$lint_name}`
 
+lint_reserved_prefix = prefix `{$prefix}` is unknown
+    .label = unknown prefix
+    .suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021
+
+lint_shadowed_into_iter =
+    this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition}
+    .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
+    .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
+    .use_explicit_into_iter_suggestion =
+        or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+
+lint_single_use_lifetime = lifetime parameter `{$ident}` only used once
+    .label_param = this lifetime...
+    .label_use = ...is used only here
+    .suggestion = elide the single-use lifetime
+
 lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
 
 lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
@@ -578,6 +715,10 @@ lint_suspicious_double_ref_clone =
 lint_suspicious_double_ref_deref =
     using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
 
+lint_trailing_semi_macro = trailing semicolon in macro used in expression position
+    .note1 = macro invocations at the end of a block are treated as expressions
+    .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
+
 lint_ty_qualified = usage of qualified `ty::{$ty}`
     .suggestion = try importing it and using it unqualified
 
@@ -591,12 +732,64 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
     .label = argument has type `{$arg_ty}`
     .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
 
+lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
+lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
+lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
+lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}`
+lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml`
+lint_unexpected_cfg_doc_cargo = see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
+lint_unexpected_cfg_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+
+lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}`
+lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more ->
+        [0] {""}
+        *[other] {" "}and {$and_more} more
+    }
+lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities}
+lint_unexpected_cfg_name_similar_name = there is a config with a similar name
+lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
+lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
+lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
+lint_unexpected_cfg_name_with_similar_value = found config with similar value
+
+lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value ->
+        [true] `{$value}`
+        *[false] (none)
+    }
+lint_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml`
+lint_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility ->
+        [true] {"(none), "}
+        *[false] {""}
+    }{$possibilities}{$and_more ->
+        [0] {""}
+        *[other] {" "}and {$and_more} more
+    }
+lint_unexpected_cfg_value_no_expected_value = no expected value for `{$name}`
+lint_unexpected_cfg_value_no_expected_values = no expected values for `{$name}`
+lint_unexpected_cfg_value_remove_condition = remove the condition
+lint_unexpected_cfg_value_remove_value = remove the value
+lint_unexpected_cfg_value_similar_name = there is a expected value with a similar name
+lint_unexpected_cfg_value_specify_value = specify a config value
+
 lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
      .label = this function will not propagate the caller location
 
+lint_unicode_text_flow = unicode codepoint changing visible direction of text present in comment
+    .label = {$num_codepoints ->
+            [1] this comment contains an invisible unicode text flow control codepoint
+            *[other] this comment contains invisible unicode text flow control codepoints
+        }
+    .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+    .suggestion = if their presence wasn't intentional, you can remove them
+    .label_comment_char = {$c_debug}
+
+
 lint_unit_bindings = binding has unit type `()`
     .label = this pattern is inferred to be the unit type `()`
 
+lint_unknown_diagnostic_attribute = unknown diagnostic attribute
+lint_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists
+
 lint_unknown_gated_lint =
     unknown lint: `{$name}`
     .note = the `{$name}` lint is unstable
@@ -612,9 +805,16 @@ lint_unknown_lint =
         *[false] did you mean: `{$replace}`
     }
 
+lint_unknown_macro_variable = unknown macro variable `{$name}`
+
 lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
     .help = add `#![register_tool({$tool_name})]` to the crate root
 
+lint_unnameable_test_items = cannot test inner items
+
+lint_unnecessary_qualification = unnecessary qualification
+    .suggestion = remove the unnecessary path segments
+
 lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
 
 lint_untranslatable_diag = diagnostics should be created using translatable messages
@@ -622,6 +822,9 @@ lint_untranslatable_diag = diagnostics should be created using translatable mess
 lint_unused_allocation = unnecessary allocation, use `&` instead
 lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
 
+lint_unused_builtin_attribute = unused attribute `{$attr_name}`
+    .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`
+
 lint_unused_closure =
     unused {$pre}{$count ->
         [one] closure
@@ -638,14 +841,43 @@ lint_unused_coroutine =
     }{$post} that must be used
     .note = coroutines are lazy and do nothing unless resumed
 
+lint_unused_crate_dependency = external crate `{$extern_crate}` unused in `{$local_crate}`: remove the dependency or add `use {$extern_crate} as _;`
+
 lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
     .suggestion = use `let _ = ...` to ignore the resulting value
 
 lint_unused_delim = unnecessary {$delim} around {$item}
     .suggestion = remove these {$delim}
 
+lint_unused_doc_comment = unused doc comment
+    .label = rustdoc does not generate documentation for macro invocations
+    .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion
+
+lint_unused_extern_crate = unused extern crate
+    .suggestion = remove it
+
 lint_unused_import_braces = braces around {$node} is unnecessary
 
+lint_unused_imports = {$num_snippets ->
+        [one] unused import: {$span_snippets}
+        *[other] unused imports: {$span_snippets}
+    }
+    .suggestion_remove_whole_use = remove the whole `use` item
+    .suggestion_remove_imports = {$num_to_remove ->
+            [one] remove the unused import
+            *[other] remove the unused imports
+        }
+    .help = if this is a test module, consider adding a `#[cfg(test)]` to the containing module
+
+lint_unused_label = unused label
+
+lint_unused_lifetime = lifetime parameter `{$ident}` never used
+    .suggestion = elide the unused lifetime
+
+lint_unused_macro_definition = unused macro definition: `{$name}`
+
+lint_unused_macro_use = unused `#[macro_use]` import
+
 lint_unused_op = unused {$op} that must be used
     .label = the {$op} produces a value
     .suggestion = use `let _ = ...` to ignore the resulting value
@@ -654,3 +886,6 @@ lint_unused_result = unused result of type `{$ty}`
 
 lint_variant_size_differences =
     enum variant is more than three times larger ({$largest} bytes) than the next largest
+
+lint_wasm_c_abi =
+    older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
deleted file mode 100644
index 8f4bae33957..00000000000
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-use crate::{
-    lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub},
-    LateContext, LateLintPass, LintContext,
-};
-use rustc_hir as hir;
-use rustc_middle::bug;
-use rustc_middle::ty;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment};
-use rustc_session::lint::FutureIncompatibilityReason;
-use rustc_session::{declare_lint, impl_lint_pass};
-use rustc_span::edition::Edition;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-
-declare_lint! {
-    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,edition2018
-    /// # #![allow(unused)]
-    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
-    /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
-    /// behave as `(&array).into_iter()`, returning an iterator over
-    /// references, just like in Rust 1.52 and earlier.
-    /// This only applies to the method call syntax `array.into_iter()`, not to
-    /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
-    pub ARRAY_INTO_ITER,
-    Warn,
-    "detects calling `into_iter` on arrays in Rust 2015 and 2018",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
-    };
-}
-
-#[derive(Copy, Clone, Default)]
-pub struct ArrayIntoIter {
-    for_expr_span: Span,
-}
-
-impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
-
-impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        // Save the span of expressions in `for _ in expr` syntax,
-        // so we can give a better suggestion for those later.
-        if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
-            if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
-                if let hir::ExprKind::Path(hir::QPath::LangItem(
-                    hir::LangItem::IntoIterIntoIter,
-                    ..,
-                )) = &path.kind
-                {
-                    self.for_expr_span = arg.span;
-                }
-            }
-        }
-
-        // We only care about method call expressions.
-        if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
-            if call.ident.name != sym::into_iter {
-                return;
-            }
-
-            // Check if the method call actually calls the libcore
-            // `IntoIterator::into_iter`.
-            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-            match cx.tcx.trait_of_item(def_id) {
-                Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
-                _ => return,
-            };
-
-            // As this is a method call expression, we have at least one argument.
-            let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
-            let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
-
-            let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else {
-                return;
-            };
-
-            let types =
-                std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
-
-            let mut found_array = false;
-
-            for ty in types {
-                match ty.kind() {
-                    // If we run into a &[T; N] or &[T] first, there's nothing to warn about.
-                    // It'll resolve to the reference version.
-                    ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
-                    ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
-                    // Found an actual array type without matching a &[T; N] first.
-                    // This is the problematic case.
-                    ty::Array(..) => {
-                        found_array = true;
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-
-            if !found_array {
-                return;
-            }
-
-            // Emit lint diagnostic.
-            let target = match *target.kind() {
-                ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
-                ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
-                // We know the original first argument type is an array type,
-                // we know that the first adjustment was an autoref coercion
-                // and we know that `IntoIterator` is the trait involved. The
-                // array cannot be coerced to something other than a reference
-                // to an array or to a slice.
-                _ => bug!("array type coerced to something other than array or slice"),
-            };
-            let sub = if self.for_expr_span == expr.span {
-                Some(ArrayIntoIterDiagSub::RemoveIntoIter {
-                    span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                })
-            } else if receiver_ty.is_array() {
-                Some(ArrayIntoIterDiagSub::UseExplicitIntoIter {
-                    start_span: expr.span.shrink_to_lo(),
-                    end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                })
-            } else {
-                None
-            };
-            cx.emit_span_lint(
-                ARRAY_INTO_ITER,
-                call.ident.span,
-                ArrayIntoIterDiag { target, suggestion: call.ident.span, sub },
-            );
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6b9f9d1531e..0f059bceae7 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -30,10 +30,10 @@ use crate::{
         BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
         BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
         BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
-        BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
-        BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
-        BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
-        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
+        BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric,
+        BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
+        BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion,
+        BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
         BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
         BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
         BuiltinWhileTrue, SuggestChangingAssocTypes,
@@ -60,7 +60,7 @@ use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
-use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason};
+use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
@@ -2882,16 +2882,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                     let target_spans: MultiSpan =
                         if spans.len() > 0 { spans.into() } else { (*template_span).into() };
 
-                    cx.span_lint_with_diagnostics(
-                            NAMED_ASM_LABELS,
-                            Some(target_spans),
-                            fluent::lint_builtin_asm_labels,
-                            |_| {},
-                            BuiltinLintDiag::NamedAsmLabel(
-                                "only local labels of the form `<number>:` should be used in inline asm"
-                                    .to_string(),
-                            ),
-                        );
+                    cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel);
                 }
             }
         }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 62ba9ef5c11..deeb3ae090c 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -527,30 +527,24 @@ pub struct EarlyContext<'a> {
     pub buffered: LintBuffer,
 }
 
-pub trait LintContext {
-    fn sess(&self) -> &Session;
-
+impl EarlyContext<'_> {
     /// Emit a lint at the appropriate level, with an optional associated span and an existing
     /// diagnostic.
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
     #[rustc_lint_diagnostics]
-    fn span_lint_with_diagnostics(
+    pub fn span_lint_with_diagnostics(
         &self,
         lint: &'static Lint,
-        span: Option<impl Into<MultiSpan>>,
-        msg: impl Into<DiagMessage>,
-        decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
+        span: MultiSpan,
         diagnostic: BuiltinLintDiag,
     ) {
-        // We first generate a blank diagnostic.
-        self.opt_span_lint(lint, span, msg, |db| {
-            // Now, set up surrounding context.
-            diagnostics::builtin(self.sess(), diagnostic, db);
-            // Rewrap `db`, and pass control to the user.
-            decorate(db)
-        });
+        diagnostics::emit_buffered_lint(self, lint, span, diagnostic)
     }
+}
+
+pub trait LintContext {
+    fn sess(&self) -> &Session;
 
     // FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
     // set the span in their `decorate` function (preferably using set_span).
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 5ad3ff71a6d..236eeee6152 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -1,58 +1,57 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use std::borrow::Cow;
+
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
-use rustc_errors::{elided_lifetime_in_path_suggestion, Diag};
-use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_errors::Applicability;
+use rustc_errors::{elided_lifetime_in_path_suggestion, DiagArgValue, MultiSpan};
 use rustc_middle::middle::stability;
-use rustc_session::lint::BuiltinLintDiag;
-use rustc_session::Session;
+use rustc_session::lint::{BuiltinLintDiag, Lint};
 use rustc_span::BytePos;
 
+use crate::{lints, EarlyContext, LintContext as _};
+
 mod check_cfg;
 
-pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) {
+pub(super) fn emit_buffered_lint(
+    ctx: &EarlyContext<'_>,
+    lint: &'static Lint,
+    span: MultiSpan,
+    diagnostic: BuiltinLintDiag,
+) {
+    let sess = ctx.sess();
     match diagnostic {
-        BuiltinLintDiag::UnicodeTextFlow(span, content) => {
+        BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
             let spans: Vec<_> = content
                 .char_indices()
                 .filter_map(|(i, c)| {
                     TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
-                        let lo = span.lo() + BytePos(2 + i as u32);
-                        (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+                        let lo = comment_span.lo() + BytePos(2 + i as u32);
+                        (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
                     })
                 })
                 .collect();
-            let (an, s) = match spans.len() {
-                1 => ("an ", ""),
-                _ => ("", "s"),
-            };
-            diag.span_label(
+            let characters = spans
+                .iter()
+                .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
+                .collect();
+            let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
+                spans: spans.iter().map(|(_c, span)| *span).collect(),
+            });
+            ctx.emit_span_lint(
+                lint,
                 span,
-                format!(
-                    "this comment contains {an}invisible unicode text flow control codepoint{s}",
-                ),
-            );
-            for (c, span) in &spans {
-                diag.span_label(*span, format!("{c:?}"));
-            }
-            diag.note(
-                "these kind of unicode codepoints change the way text flows on \
-                         applications that support them, but can cause confusion because they \
-                         change the order of characters on the screen",
-            );
-            if !spans.is_empty() {
-                diag.multipart_suggestion_with_style(
-                    "if their presence wasn't intentional, you can remove them",
-                    spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(),
-                    Applicability::MachineApplicable,
-                    SuggestionStyle::HideCodeAlways,
-                );
-            }
-        }
-        BuiltinLintDiag::Normal => (),
-        BuiltinLintDiag::AbsPathWithModule(span) => {
-            let (sugg, app) = match sess.source_map().span_to_snippet(span) {
+                lints::UnicodeTextFlow {
+                    comment_span,
+                    characters,
+                    suggestions,
+                    num_codepoints: spans.len(),
+                },
+            )
+        }
+        BuiltinLintDiag::AbsPathWithModule(mod_span) => {
+            let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) {
                 Ok(ref s) => {
                     // FIXME(Manishearth) ideally the emitting code
                     // can tell us whether or not this is global
@@ -62,160 +61,207 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
                 }
                 Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
             };
-            diag.span_suggestion(span, "use `crate`", sugg, app);
-        }
-        BuiltinLintDiag::ProcMacroDeriveResolutionFallback(span) => {
-            diag.span_label(
+            ctx.emit_span_lint(
+                lint,
                 span,
-                "names from parent modules are not accessible without an explicit import",
+                lints::AbsPathWithModule {
+                    sugg: lints::AbsPathWithModuleSugg {
+                        span: mod_span,
+                        applicability,
+                        replacement,
+                    },
+                },
             );
         }
-        BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
-            diag.span_note(span_def, "the macro is defined here");
-        }
+        BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => ctx
+            .emit_span_lint(
+                lint,
+                span,
+                lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident },
+            ),
+        BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => ctx
+            .emit_span_lint(
+                lint,
+                span,
+                lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def },
+            ),
         BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
-            diag.subdiagnostic(
-                sess.dcx(),
-                elided_lifetime_in_path_suggestion(
-                    sess.source_map(),
-                    n,
-                    path_span,
-                    incl_angl_brckt,
-                    insertion_span,
-                ),
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ElidedLifetimesInPaths {
+                    subdiag: elided_lifetime_in_path_suggestion(
+                        sess.source_map(),
+                        n,
+                        path_span,
+                        incl_angl_brckt,
+                        insertion_span,
+                    ),
+                },
             );
         }
-        BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {
-            diag.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect);
-        }
-        BuiltinLintDiag::UnusedImports(message, replaces, in_test_module) => {
-            if !replaces.is_empty() {
-                diag.tool_only_multipart_suggestion(
-                    message,
-                    replaces,
-                    Applicability::MachineApplicable,
-                );
-            }
+        BuiltinLintDiag::UnknownCrateTypes { span, candidate } => {
+            let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate });
+            ctx.emit_span_lint(lint, span, lints::UnknownCrateTypes { sugg });
+        }
+        BuiltinLintDiag::UnusedImports {
+            remove_whole_use,
+            num_to_remove,
+            remove_spans,
+            test_module_span,
+            span_snippets,
+        } => {
+            let sugg = if remove_whole_use {
+                lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
+            } else {
+                lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
+            };
+            let test_module_span =
+                test_module_span.map(|span| sess.source_map().guess_head_span(span));
 
-            if let Some(span) = in_test_module {
-                diag.span_help(
-                    sess.source_map().guess_head_span(span),
-                    "if this is a test module, consider adding a `#[cfg(test)]` to the containing module",
-                );
-            }
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::UnusedImports {
+                    sugg,
+                    test_module_span,
+                    num_snippets: span_snippets.len(),
+                    span_snippets: DiagArgValue::StrListSepByAnd(
+                        span_snippets.into_iter().map(Cow::Owned).collect(),
+                    ),
+                },
+            );
         }
         BuiltinLintDiag::RedundantImport(spans, ident) => {
-            for (span, is_imported) in spans {
-                let introduced = if is_imported { "imported" } else { "defined" };
-                let span_msg = if span.is_dummy() { "by the extern prelude" } else { "here" };
-                diag.span_label(
-                    span,
-                    format!("the item `{ident}` is already {introduced} {span_msg}"),
-                );
-            }
-        }
-        BuiltinLintDiag::DeprecatedMacro(suggestion, span) => {
-            stability::deprecation_suggestion(diag, "macro", suggestion, span)
-        }
-        BuiltinLintDiag::UnusedDocComment(span) => {
-            diag.span_label(span, "rustdoc does not generate documentation for macro invocations");
-            diag.help("to document an item produced by a macro, \
-                                  the macro must produce the documentation as part of its expansion");
-        }
-        BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident) => {
-            diag.span_suggestion(
+            let subs = spans
+                .into_iter()
+                .map(|(span, is_imported)| {
+                    (match (span.is_dummy(), is_imported) {
+                        (false, true) => lints::RedundantImportSub::ImportedHere,
+                        (false, false) => lints::RedundantImportSub::DefinedHere,
+                        (true, true) => lints::RedundantImportSub::ImportedPrelude,
+                        (true, false) => lints::RedundantImportSub::DefinedPrelude,
+                    })(span)
+                })
+                .collect();
+            ctx.emit_span_lint(lint, span, lints::RedundantImport { subs, ident });
+        }
+        BuiltinLintDiag::DeprecatedMacro {
+            suggestion,
+            suggestion_span,
+            note,
+            path,
+            since_kind,
+        } => {
+            let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion {
+                span: suggestion_span,
+                kind: "macro".to_owned(),
+                suggestion,
+            });
+            ctx.emit_span_lint(
+                lint,
                 span,
-                "remove `mut` from the parameter",
-                ident,
-                Applicability::MachineApplicable,
+                stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind },
             );
         }
-        BuiltinLintDiag::MissingAbi(span, default_abi) => {
-            diag.span_label(span, "ABI should be specified here");
-            diag.help(format!("the default ABI is {}", default_abi.name()));
+        BuiltinLintDiag::UnusedDocComment(attr_span) => {
+            ctx.emit_span_lint(lint, span, lints::UnusedDocComment { span: attr_span });
         }
-        BuiltinLintDiag::LegacyDeriveHelpers(span) => {
-            diag.span_label(span, "the attribute is introduced here");
+        BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => {
+            let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span };
+
+            ctx.emit_span_lint(
+                lint,
+                span,
+                if is_foreign {
+                    lints::PatternsInFnsWithoutBody::Foreign { sub }
+                } else {
+                    lints::PatternsInFnsWithoutBody::Bodiless { sub }
+                },
+            );
         }
-        BuiltinLintDiag::ProcMacroBackCompat(note) => {
-            diag.note(note);
+        BuiltinLintDiag::MissingAbi(label_span, default_abi) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::MissingAbi { span: label_span, default_abi: default_abi.name() },
+            );
         }
-        BuiltinLintDiag::OrPatternsBackCompat(span, suggestion) => {
-            diag.span_suggestion(
+        BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
+            ctx.emit_span_lint(lint, span, lints::LegacyDeriveHelpers { span: label_span });
+        }
+        BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => {
+            ctx.emit_span_lint(
+                lint,
                 span,
-                "use pat_param to preserve semantics",
-                suggestion,
-                Applicability::MachineApplicable,
+                lints::ProcMacroBackCompat { crate_name, fixed_version },
+            );
+        }
+        BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::OrPatternsBackCompat { span: suggestion_span, suggestion },
             );
         }
-        BuiltinLintDiag::ReservedPrefix(span) => {
-            diag.span_label(span, "unknown prefix");
-            diag.span_suggestion_verbose(
-                span.shrink_to_hi(),
-                "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
-                " ",
-                Applicability::MachineApplicable,
+        BuiltinLintDiag::ReservedPrefix(label_span, prefix) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ReservedPrefix {
+                    label: label_span,
+                    suggestion: label_span.shrink_to_hi(),
+                    prefix,
+                },
             );
         }
         BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
-            diag.span_note(
-                        invoc_span,
-                        format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
-                    );
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name },
+            );
         }
         BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
-            if is_trailing {
-                diag.note("macro invocations at the end of a block are treated as expressions");
-                diag.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
-            }
-        }
-        BuiltinLintDiag::BreakWithLabelAndLoop(span) => {
-            diag.multipart_suggestion(
-                "wrap this expression in parentheses",
-                vec![
-                    (span.shrink_to_lo(), "(".to_string()),
-                    (span.shrink_to_hi(), ")".to_string()),
-                ],
-                Applicability::MachineApplicable,
-            );
+            ctx.emit_span_lint(lint, span, lints::TrailingMacro { is_trailing, name });
         }
-        BuiltinLintDiag::NamedAsmLabel(help) => {
-            diag.help(help);
-            diag.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
+        BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::BreakWithLabelAndLoop {
+                    sub: lints::BreakWithLabelAndLoopSub {
+                        left: sugg_span.shrink_to_lo(),
+                        right: sugg_span.shrink_to_hi(),
+                    },
+                },
+            );
         }
         BuiltinLintDiag::UnexpectedCfgName(name, value) => {
-            check_cfg::unexpected_cfg_name(sess, diag, name, value)
+            ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_name(sess, name, value));
         }
         BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
-            check_cfg::unexpected_cfg_value(sess, diag, name, value)
-        }
-        BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg) => {
-            let left_sp = diag.span.primary_span().unwrap();
-            match sugg {
-                Some((right_sp, sugg)) => diag.multipart_suggestion(
-                    "move it to the end of the type declaration",
-                    vec![(left_sp, String::new()), (right_sp, sugg)],
-                    Applicability::MachineApplicable,
-                ),
-                None => diag.span_suggestion(
-                    left_sp,
-                    "remove this `where`",
-                    "",
-                    Applicability::MachineApplicable,
-                ),
+            ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_value(sess, name, value));
+        }
+        BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
+            let suggestion = match sugg {
+                Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
+                    left: left_sp,
+                    right: right_sp,
+                    sugg,
+                },
+                None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp },
             };
-            diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information");
+            ctx.emit_span_lint(lint, span, lints::DeprecatedWhereClauseLocation { suggestion });
         }
         BuiltinLintDiag::SingleUseLifetime {
             param_span,
             use_span: Some((use_span, elide)),
             deletion_span,
+            ident,
         } => {
             debug!(?param_span, ?use_span, ?deletion_span);
-            diag.span_label(param_span, "this lifetime...");
-            diag.span_label(use_span, "...is used only here");
-            if let Some(deletion_span) = deletion_span {
-                let msg = "elide the single-use lifetime";
+            let suggestion = if let Some(deletion_span) = deletion_span {
                 let (use_span, replace_lt) = if elide {
                     let use_span = sess.source_map().span_extend_while_whitespace(use_span);
                     (use_span, String::new())
@@ -226,24 +272,22 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
 
                 // issue 107998 for the case such as a wrong function pointer type
                 // `deletion_span` is empty and there is no need to report lifetime uses here
-                let suggestions = if deletion_span.is_empty() {
-                    vec![(use_span, replace_lt)]
-                } else {
-                    vec![(deletion_span, String::new()), (use_span, replace_lt)]
-                };
-                diag.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable);
-            }
+                let deletion_span =
+                    if deletion_span.is_empty() { None } else { Some(deletion_span) };
+                Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
+            } else {
+                None
+            };
+
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::SingleUseLifetime { suggestion, param_span, use_span, ident },
+            );
         }
-        BuiltinLintDiag::SingleUseLifetime { param_span: _, use_span: None, deletion_span } => {
+        BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => {
             debug!(?deletion_span);
-            if let Some(deletion_span) = deletion_span {
-                diag.span_suggestion(
-                    deletion_span,
-                    "elide the unused lifetime",
-                    "",
-                    Applicability::MachineApplicable,
-                );
-            }
+            ctx.emit_span_lint(lint, span, lints::UnusedLifetime { deletion_span, ident });
         }
         BuiltinLintDiag::NamedArgumentUsedPositionally {
             position_sp_to_replace,
@@ -252,19 +296,12 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
             named_arg_name,
             is_formatting_arg,
         } => {
-            diag.span_label(
-                named_arg_sp,
-                "this named argument is referred to by position in formatting string",
-            );
-            if let Some(positional_arg_for_msg) = position_sp_for_msg {
-                let msg = format!(
-                    "this formatting argument uses named argument `{named_arg_name}` by position"
-                );
-                diag.span_label(positional_arg_for_msg, msg);
-            }
-
-            if let Some(positional_arg_to_replace) = position_sp_to_replace {
-                let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+            let (suggestion, name) = if let Some(positional_arg_to_replace) = position_sp_to_replace
+            {
+                let mut name = named_arg_name.clone();
+                if is_formatting_arg {
+                    name.push('$')
+                };
                 let span_to_replace = if let Ok(positional_arg_content) =
                     sess.source_map().span_to_snippet(positional_arg_to_replace)
                     && positional_arg_content.starts_with(':')
@@ -273,31 +310,40 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
                 } else {
                     positional_arg_to_replace
                 };
-                diag.span_suggestion_verbose(
-                    span_to_replace,
-                    "use the named argument by name to avoid ambiguity",
+                (Some(span_to_replace), name)
+            } else {
+                (None, String::new())
+            };
+
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::NamedArgumentUsedPositionally {
+                    named_arg_sp,
+                    position_label_sp: position_sp_for_msg,
+                    suggestion,
                     name,
-                    Applicability::MaybeIncorrect,
-                );
-            }
+                    named_arg_name,
+                },
+            )
         }
-        BuiltinLintDiag::ByteSliceInPackedStructWithDerive => {
-            diag.help("consider implementing the trait by hand, or remove the `packed` attribute");
+        BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => {
+            ctx.emit_span_lint(lint, span, lints::ByteSliceInPackedStructWithDerive { ty })
         }
         BuiltinLintDiag::UnusedExternCrate { removal_span } => {
-            diag.span_suggestion(removal_span, "remove it", "", Applicability::MachineApplicable);
+            ctx.emit_span_lint(lint, span, lints::UnusedExternCrate { removal_span })
         }
         BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => {
             let suggestion_span = vis_span.between(ident_span);
-            diag.span_suggestion_verbose(
-                suggestion_span,
-                "convert it to a `use`",
-                if vis_span.is_empty() { "use " } else { " use " },
-                Applicability::MachineApplicable,
+            let code = if vis_span.is_empty() { "use " } else { " use " };
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ExternCrateNotIdiomatic { span: suggestion_span, code },
             );
         }
         BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => {
-            rustc_errors::report_ambiguity_error(diag, ambiguity);
+            ctx.emit_span_lint(lint, span, lints::AmbiguousGlobImports { ambiguity });
         }
         BuiltinLintDiag::AmbiguousGlobReexports {
             name,
@@ -305,15 +351,15 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
             first_reexport_span,
             duplicate_reexport_span,
         } => {
-            diag.span_label(
-                first_reexport_span,
-                format!("the name `{name}` in the {namespace} namespace is first re-exported here"),
-            );
-            diag.span_label(
-                duplicate_reexport_span,
-                format!(
-                    "but the name `{name}` in the {namespace} namespace is also re-exported here"
-                ),
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::AmbiguousGlobReexports {
+                    first_reexport: first_reexport_span,
+                    duplicate_reexport: duplicate_reexport_span,
+                    name,
+                    namespace,
+                },
             );
         }
         BuiltinLintDiag::HiddenGlobReexports {
@@ -322,38 +368,127 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
             glob_reexport_span,
             private_item_span,
         } => {
-            diag.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here"));
-            diag.span_note(private_item_span, "but the private item here shadows it".to_owned());
-        }
-        BuiltinLintDiag::UnusedQualifications { removal_span } => {
-            diag.span_suggestion_verbose(
-                removal_span,
-                "remove the unnecessary path segments",
-                "",
-                Applicability::MachineApplicable,
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::HiddenGlobReexports {
+                    glob_reexport: glob_reexport_span,
+                    private_item: private_item_span,
+
+                    name,
+                    namespace,
+                },
             );
         }
-        BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span } => {
-            diag.span_suggestion_verbose(
-                if elided { span.shrink_to_hi() } else { span },
-                "use the `'static` lifetime",
-                if elided { "'static " } else { "'static" },
-                Applicability::MachineApplicable,
-            );
+        BuiltinLintDiag::UnusedQualifications { removal_span } => {
+            ctx.emit_span_lint(lint, span, lints::UnusedQualifications { removal_span });
         }
-        BuiltinLintDiag::RedundantImportVisibility { max_vis, span } => {
-            diag.span_note(span, format!("the most public imported item is `{max_vis}`"));
-            diag.help(
-                "reduce the glob import's visibility or increase visibility of imported items",
+        BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => {
+            let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span };
+            let code = if elided { "'static " } else { "'static" };
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::AssociatedConstElidedLifetime { span: lt_span, code, elided },
             );
         }
-        BuiltinLintDiag::MaybeTypo { span, name } => {
-            diag.span_suggestion_verbose(
+        BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => {
+            ctx.emit_span_lint(
+                lint,
                 span,
-                "an attribute with a similar name exists",
-                name,
-                Applicability::MachineApplicable,
+                lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis },
             );
         }
+        BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => {
+            let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg {
+                span: typo_span,
+                typo_name,
+            });
+            ctx.emit_span_lint(lint, span, lints::UnknownDiagnosticAttribute { typo });
+        }
+        BuiltinLintDiag::MacroUseDeprecated => {
+            ctx.emit_span_lint(lint, span, lints::MacroUseDeprecated)
+        }
+        BuiltinLintDiag::UnusedMacroUse => ctx.emit_span_lint(lint, span, lints::UnusedMacroUse),
+        BuiltinLintDiag::PrivateExternCrateReexport(ident) => {
+            ctx.emit_span_lint(lint, span, lints::PrivateExternCrateReexport { ident })
+        }
+        BuiltinLintDiag::UnusedLabel => ctx.emit_span_lint(lint, span, lints::UnusedLabel),
+        BuiltinLintDiag::MacroIsPrivate(ident) => {
+            ctx.emit_span_lint(lint, span, lints::MacroIsPrivate { ident })
+        }
+        BuiltinLintDiag::UnusedMacroDefinition(name) => {
+            ctx.emit_span_lint(lint, span, lints::UnusedMacroDefinition { name })
+        }
+        BuiltinLintDiag::MacroRuleNeverUsed(n, name) => {
+            ctx.emit_span_lint(lint, span, lints::MacroRuleNeverUsed { n: n + 1, name })
+        }
+        BuiltinLintDiag::UnstableFeature(msg) => {
+            ctx.emit_span_lint(lint, span, lints::UnstableFeature { msg })
+        }
+        BuiltinLintDiag::AvoidUsingIntelSyntax => {
+            ctx.emit_span_lint(lint, span, lints::AvoidIntelSyntax)
+        }
+        BuiltinLintDiag::AvoidUsingAttSyntax => {
+            ctx.emit_span_lint(lint, span, lints::AvoidAttSyntax)
+        }
+        BuiltinLintDiag::IncompleteInclude => {
+            ctx.emit_span_lint(lint, span, lints::IncompleteInclude)
+        }
+        BuiltinLintDiag::UnnameableTestItems => {
+            ctx.emit_span_lint(lint, span, lints::UnnameableTestItems)
+        }
+        BuiltinLintDiag::DuplicateMacroAttribute => {
+            ctx.emit_span_lint(lint, span, lints::DuplicateMacroAttribute)
+        }
+        BuiltinLintDiag::CfgAttrNoAttributes => {
+            ctx.emit_span_lint(lint, span, lints::CfgAttrNoAttributes)
+        }
+        BuiltinLintDiag::CrateTypeInCfgAttr => {
+            ctx.emit_span_lint(lint, span, lints::CrateTypeInCfgAttr)
+        }
+        BuiltinLintDiag::CrateNameInCfgAttr => {
+            ctx.emit_span_lint(lint, span, lints::CrateNameInCfgAttr)
+        }
+        BuiltinLintDiag::MissingFragmentSpecifier => {
+            ctx.emit_span_lint(lint, span, lints::MissingFragmentSpecifier)
+        }
+        BuiltinLintDiag::MetaVariableStillRepeating(name) => {
+            ctx.emit_span_lint(lint, span, lints::MetaVariableStillRepeating { name })
+        }
+        BuiltinLintDiag::MetaVariableWrongOperator => {
+            ctx.emit_span_lint(lint, span, lints::MetaVariableWrongOperator)
+        }
+        BuiltinLintDiag::DuplicateMatcherBinding => {
+            ctx.emit_span_lint(lint, span, lints::DuplicateMatcherBinding)
+        }
+        BuiltinLintDiag::UnknownMacroVariable(name) => {
+            ctx.emit_span_lint(lint, span, lints::UnknownMacroVariable { name })
+        }
+        BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => ctx.emit_span_lint(
+            lint,
+            span,
+            lints::UnusedCrateDependency { extern_crate, local_crate },
+        ),
+        BuiltinLintDiag::WasmCAbi => ctx.emit_span_lint(lint, span, lints::WasmCAbi),
+        BuiltinLintDiag::IllFormedAttributeInput { suggestions } => ctx.emit_span_lint(
+            lint,
+            span,
+            lints::IllFormedAttributeInput {
+                num_suggestions: suggestions.len(),
+                suggestions: DiagArgValue::StrListSepByAnd(
+                    suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                ),
+            },
+        ),
+        BuiltinLintDiag::InnerAttributeUnstable { is_macro } => ctx.emit_span_lint(
+            lint,
+            span,
+            if is_macro {
+                lints::InnerAttributeUnstable::InnerMacroAttribute
+            } else {
+                lints::InnerAttributeUnstable::CustomInnerAttribute
+            },
+        ),
     }
 }
diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
index 3c423b4e2aa..020ca1753cf 100644
--- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
@@ -1,52 +1,52 @@
-use rustc_errors::{Applicability, Diag};
 use rustc_middle::bug;
 use rustc_session::{config::ExpectedValues, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{sym, Span, Symbol};
 
+use crate::lints;
+
 const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
 
-fn check_cfg_expected_note(
+fn sort_and_truncate_possibilities(
     sess: &Session,
-    possibilities: &[Symbol],
-    type_: &str,
-    name: Option<Symbol>,
-    suffix: &str,
-) -> String {
-    use std::fmt::Write;
-
+    mut possibilities: Vec<Symbol>,
+) -> (Vec<Symbol>, usize) {
     let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
         possibilities.len()
     } else {
         std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
     };
 
-    let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
-    possibilities.sort();
+    possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
 
     let and_more = possibilities.len().saturating_sub(n_possibilities);
-    let possibilities = possibilities[..n_possibilities].join("`, `");
+    possibilities.truncate(n_possibilities);
+    (possibilities, and_more)
+}
 
-    let mut note = String::with_capacity(50 + possibilities.len());
+enum EscapeQuotes {
+    Yes,
+    No,
+}
 
-    write!(&mut note, "expected {type_}").unwrap();
-    if let Some(name) = name {
-        write!(&mut note, " for `{name}`").unwrap();
-    }
-    write!(&mut note, " are: {suffix}`{possibilities}`").unwrap();
-    if and_more > 0 {
-        write!(&mut note, " and {and_more} more").unwrap();
+fn to_check_cfg_arg(name: Symbol, value: Option<Symbol>, quotes: EscapeQuotes) -> String {
+    if let Some(value) = value {
+        let value = str::escape_debug(value.as_str()).to_string();
+        let values = match quotes {
+            EscapeQuotes::Yes => format!("\\\"{}\\\"", value.replace("\"", "\\\\\\\\\"")),
+            EscapeQuotes::No => format!("\"{value}\""),
+        };
+        format!("cfg({name}, values({values}))")
+    } else {
+        format!("cfg({name})")
     }
-
-    note
 }
 
 pub(super) fn unexpected_cfg_name(
     sess: &Session,
-    diag: &mut Diag<'_, ()>,
     (name, name_span): (Symbol, Span),
     value: Option<(Symbol, Span)>,
-) {
+) -> lints::UnexpectedCfgName {
     #[allow(rustc::potential_query_instability)]
     let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect();
 
@@ -69,116 +69,122 @@ pub(super) fn unexpected_cfg_name(
     let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
     let mut is_feature_cfg = name == sym::feature;
 
-    if is_feature_cfg && is_from_cargo {
-        diag.help("consider defining some features in `Cargo.toml`");
+    let code_sugg = if is_feature_cfg && is_from_cargo {
+        lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
     // Suggest the most probable if we found one
     } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
+        is_feature_cfg |= best_match == sym::feature;
+
         if let Some(ExpectedValues::Some(best_match_values)) =
             sess.psess.check_config.expecteds.get(&best_match)
         {
             // We will soon sort, so the initial order does not matter.
             #[allow(rustc::potential_query_instability)]
-            let mut possibilities =
-                best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>();
-            possibilities.sort();
+            let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>();
+            possibilities.sort_by_key(|s| s.as_str());
+
+            let get_possibilities_sub = || {
+                if !possibilities.is_empty() {
+                    let possibilities =
+                        possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
+                    Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
+                } else {
+                    None
+                }
+            };
 
-            let mut should_print_possibilities = true;
             if let Some((value, value_span)) = value {
                 if best_match_values.contains(&Some(value)) {
-                    diag.span_suggestion(
-                        name_span,
-                        "there is a config with a similar name and value",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                    should_print_possibilities = false;
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
+                        span: name_span,
+                        code: best_match.to_string(),
+                    }
                 } else if best_match_values.contains(&None) {
-                    diag.span_suggestion(
-                        name_span.to(value_span),
-                        "there is a config with a similar name and no value",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                    should_print_possibilities = false;
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
+                        span: name_span.to(value_span),
+                        code: best_match.to_string(),
+                    }
                 } else if let Some(first_value) = possibilities.first() {
-                    diag.span_suggestion(
-                        name_span.to(value_span),
-                        "there is a config with a similar name and different values",
-                        format!("{best_match} = \"{first_value}\""),
-                        Applicability::MaybeIncorrect,
-                    );
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
+                        span: name_span.to(value_span),
+                        code: format!("{best_match} = \"{first_value}\""),
+                        expected: get_possibilities_sub(),
+                    }
                 } else {
-                    diag.span_suggestion(
-                        name_span.to(value_span),
-                        "there is a config with a similar name and different values",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                };
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
+                        span: name_span.to(value_span),
+                        code: best_match.to_string(),
+                        expected: get_possibilities_sub(),
+                    }
+                }
             } else {
-                diag.span_suggestion(
-                    name_span,
-                    "there is a config with a similar name",
-                    best_match,
-                    Applicability::MaybeIncorrect,
-                );
-            }
-
-            if !possibilities.is_empty() && should_print_possibilities {
-                let possibilities = possibilities.join("`, `");
-                diag.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+                lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
+                    span: name_span,
+                    code: best_match.to_string(),
+                    expected: get_possibilities_sub(),
+                }
             }
         } else {
-            diag.span_suggestion(
-                name_span,
-                "there is a config with a similar name",
-                best_match,
-                Applicability::MaybeIncorrect,
-            );
+            lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
+                span: name_span,
+                code: best_match.to_string(),
+                expected: None,
+            }
         }
-
-        is_feature_cfg |= best_match == sym::feature;
     } else {
-        if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
+        let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
             names_possibilities.sort();
-            for cfg_name in names_possibilities.iter() {
-                diag.span_suggestion(
-                    name_span,
-                    "found config with similar value",
-                    format!("{cfg_name} = \"{name}\""),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        }
-        if !possibilities.is_empty() {
-            diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, ""));
+            names_possibilities
+                .iter()
+                .map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue {
+                    span: name_span,
+                    code: format!("{cfg_name} = \"{name}\""),
+                })
+                .collect()
+        } else {
+            vec![]
+        };
+        let expected_names = if !possibilities.is_empty() {
+            let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
+            Some(lints::unexpected_cfg_name::ExpectedNames {
+                possibilities: possibilities.into(),
+                and_more,
+            })
+        } else {
+            None
+        };
+        lints::unexpected_cfg_name::CodeSuggestion::SimilarValues {
+            with_similar_values: similar_values,
+            expected_names,
         }
-    }
+    };
+
+    let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
 
-    let inst = if let Some((value, _value_span)) = value {
-        let pre = if is_from_cargo { "\\" } else { "" };
-        format!("cfg({name}, values({pre}\"{value}{pre}\"))")
+    let invocation_help = if is_from_cargo {
+        let sub = if !is_feature_cfg {
+            Some(lints::UnexpectedCfgCargoHelp::new(
+                &inst(EscapeQuotes::No),
+                &inst(EscapeQuotes::Yes),
+            ))
+        } else {
+            None
+        };
+        lints::unexpected_cfg_name::InvocationHelp::Cargo { sub }
     } else {
-        format!("cfg({name})")
+        lints::unexpected_cfg_name::InvocationHelp::Rustc(lints::UnexpectedCfgRustcHelp::new(
+            &inst(EscapeQuotes::No),
+        ))
     };
 
-    if is_from_cargo {
-        if !is_feature_cfg {
-            diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
-        }
-        diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration");
-    } else {
-        diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
-        diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
-    }
+    lints::UnexpectedCfgName { code_sugg, invocation_help, name }
 }
 
 pub(super) fn unexpected_cfg_value(
     sess: &Session,
-    diag: &mut Diag<'_, ()>,
     (name, name_span): (Symbol, Span),
     value: Option<(Symbol, Span)>,
-) {
+) -> lints::UnexpectedCfgValue {
     let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else {
         bug!(
             "it shouldn't be possible to have a diagnostic on a value whose name is not in values"
@@ -198,81 +204,90 @@ pub(super) fn unexpected_cfg_value(
 
     // Show the full list if all possible values for a given name, but don't do it
     // for names as the possibilities could be very long
-    if !possibilities.is_empty() {
-        diag.note(check_cfg_expected_note(
-            sess,
-            &possibilities,
-            "values",
-            Some(name),
-            if have_none_possibility { "(none), " } else { "" },
-        ));
+    let code_sugg = if !possibilities.is_empty() {
+        let expected_values = {
+            let (possibilities, and_more) =
+                sort_and_truncate_possibilities(sess, possibilities.clone());
+            lints::unexpected_cfg_value::ExpectedValues {
+                name,
+                have_none_possibility,
+                possibilities: possibilities.into(),
+                and_more,
+            }
+        };
 
-        if let Some((value, value_span)) = value {
+        let suggestion = if let Some((value, value_span)) = value {
             // Suggest the most probable if we found one
             if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
-                diag.span_suggestion(
-                    value_span,
-                    "there is a expected value with a similar name",
-                    format!("\"{best_match}\""),
-                    Applicability::MaybeIncorrect,
-                );
+                Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
+                    span: value_span,
+                    best_match,
+                })
+            } else {
+                None
             }
         } else if let &[first_possibility] = &possibilities[..] {
-            diag.span_suggestion(
-                name_span.shrink_to_hi(),
-                "specify a config value",
-                format!(" = \"{first_possibility}\""),
-                Applicability::MaybeIncorrect,
-            );
-        }
+            Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
+                span: name_span.shrink_to_hi(),
+                first_possibility,
+            })
+        } else {
+            None
+        };
+
+        lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
     } else if have_none_possibility {
-        diag.note(format!("no expected value for `{name}`"));
-        if let Some((_value, value_span)) = value {
-            diag.span_suggestion(
-                name_span.shrink_to_hi().to(value_span),
-                "remove the value",
-                "",
-                Applicability::MaybeIncorrect,
-            );
-        }
+        let suggestion =
+            value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion {
+                span: name_span.shrink_to_hi().to(value_span),
+            });
+        lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
     } else {
-        diag.note(format!("no expected values for `{name}`"));
-
-        let sp = if let Some((_value, value_span)) = value {
+        let span = if let Some((_value, value_span)) = value {
             name_span.to(value_span)
         } else {
             name_span
         };
-        diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
-    }
+        let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span };
+        lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
+    };
 
     // We don't want to suggest adding values to well known names
     // since those are defined by rustc it-self. Users can still
     // do it if they want, but should not encourage them.
     let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
 
-    let inst = if let Some((value, _value_span)) = value {
-        let pre = if is_from_cargo { "\\" } else { "" };
-        format!("cfg({name}, values({pre}\"{value}{pre}\"))")
-    } else {
-        format!("cfg({name})")
-    };
+    let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
 
-    if is_from_cargo {
-        if name == sym::feature {
+    let invocation_help = if is_from_cargo {
+        let help = if name == sym::feature {
             if let Some((value, _value_span)) = value {
-                diag.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
+                Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value })
             } else {
-                diag.help("consider defining some features in `Cargo.toml`");
+                Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
             }
         } else if !is_cfg_a_well_know_name {
-            diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
-        }
-        diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration");
+            Some(lints::unexpected_cfg_value::CargoHelp::Other(lints::UnexpectedCfgCargoHelp::new(
+                &inst(EscapeQuotes::No),
+                &inst(EscapeQuotes::Yes),
+            )))
+        } else {
+            None
+        };
+        lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
     } else {
-        if !is_cfg_a_well_know_name {
-            diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
-        }
-        diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
+        let help = if !is_cfg_a_well_know_name {
+            Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
+        } else {
+            None
+        };
+        lints::unexpected_cfg_value::InvocationHelp::Rustc(help)
+    };
+
+    lints::UnexpectedCfgValue {
+        code_sugg,
+        invocation_help,
+        has_value: value.is_some(),
+        value: value.map_or_else(String::new, |(v, _span)| v.to_string()),
     }
 }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 3f627baf770..736c7a11069 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -14,7 +14,7 @@
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use crate::context::{EarlyContext, LintContext, LintStore};
+use crate::context::{EarlyContext, LintStore};
 use crate::passes::{EarlyLintPass, EarlyLintPassObject};
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self as ast_visit, walk_list, Visitor};
@@ -44,14 +44,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     fn inlined_check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.context.buffered.take(id) {
-            let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
-            self.context.span_lint_with_diagnostics(
-                lint_id.lint,
-                Some(span),
-                msg,
-                |_| {},
-                diagnostic,
-            );
+            let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
+            self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
         }
     }
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index d93edadcfbc..64fcc7e46e0 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -42,7 +42,6 @@
 #[macro_use]
 extern crate tracing;
 
-mod array_into_iter;
 mod async_fn_in_trait;
 pub mod builtin;
 mod context;
@@ -76,18 +75,18 @@ mod passes;
 mod ptr_nulls;
 mod redundant_semicolon;
 mod reference_casting;
+mod shadowed_into_iter;
 mod traits;
 mod types;
 mod unit_bindings;
 mod unused;
 
-pub use array_into_iter::ARRAY_INTO_ITER;
+pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 
 use rustc_hir::def_id::LocalModDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 
-use array_into_iter::ArrayIntoIter;
 use async_fn_in_trait::AsyncFnInTrait;
 use builtin::*;
 use deref_into_dyn_supertrait::*;
@@ -112,6 +111,7 @@ use pass_by_value::*;
 use ptr_nulls::*;
 use redundant_semicolon::*;
 use reference_casting::*;
+use shadowed_into_iter::ShadowedIntoIter;
 use traits::*;
 use types::*;
 use unit_bindings::*;
@@ -215,7 +215,7 @@ late_lint_methods!(
             DerefNullPtr: DerefNullPtr,
             UnstableFeatures: UnstableFeatures,
             UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
-            ArrayIntoIter: ArrayIntoIter::default(),
+            ShadowedIntoIter: ShadowedIntoIter,
             DropTraitConstraints: DropTraitConstraints,
             TemporaryCStringAsPtr: TemporaryCStringAsPtr,
             NonPanicFmt: NonPanicFmt,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7efa5245baa..3bd6faca379 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -5,16 +5,22 @@ use std::num::NonZero;
 use crate::errors::RequestedLevel;
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee,
-    LintDiagnostic, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
+    codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
+    ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp,
+    Subdiagnostic, SuggestionStyle,
 };
-use rustc_hir::def_id::DefId;
+use rustc_hir::{def::Namespace, def_id::DefId};
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{
     inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
 };
-use rustc_session::Session;
-use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
+use rustc_session::{lint::AmbiguityErrorDiag, Session};
+use rustc_span::{
+    edition::Edition,
+    sym,
+    symbol::{Ident, MacroRulesNormalizedIdent},
+    Span, Symbol,
+};
 
 use crate::{
     builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext,
@@ -22,17 +28,18 @@ use crate::{
 
 // array_into_iter.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_array_into_iter)]
-pub struct ArrayIntoIterDiag<'a> {
-    pub target: &'a str,
+#[diag(lint_shadowed_into_iter)]
+pub struct ShadowedIntoIterDiag {
+    pub target: &'static str,
+    pub edition: &'static str,
     #[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
     pub suggestion: Span,
     #[subdiagnostic]
-    pub sub: Option<ArrayIntoIterDiagSub>,
+    pub sub: Option<ShadowedIntoIterDiagSub>,
 }
 
 #[derive(Subdiagnostic)]
-pub enum ArrayIntoIterDiagSub {
+pub enum ShadowedIntoIterDiagSub {
     #[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
     RemoveIntoIter {
         #[primary_span]
@@ -1946,3 +1953,837 @@ pub struct UnitBindingsDiag {
     #[label]
     pub label: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_asm_labels)]
+#[help]
+#[note]
+pub struct BuiltinNamedAsmLabel;
+
+#[derive(Subdiagnostic)]
+#[help(lint_unexpected_cfg_add_cargo_feature)]
+#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
+#[help(lint_unexpected_cfg_add_build_rs_println)]
+pub struct UnexpectedCfgCargoHelp {
+    pub build_rs_println: String,
+    pub cargo_toml_lint_cfg: String,
+}
+
+impl UnexpectedCfgCargoHelp {
+    pub fn new(unescaped: &str, escaped: &str) -> Self {
+        Self {
+            cargo_toml_lint_cfg: format!(
+                "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}",
+            ),
+            build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");",),
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[help(lint_unexpected_cfg_add_cmdline_arg)]
+pub struct UnexpectedCfgRustcHelp {
+    pub cmdline_arg: String,
+}
+
+impl UnexpectedCfgRustcHelp {
+    pub fn new(unescaped: &str) -> Self {
+        Self { cmdline_arg: format!("--check-cfg={unescaped}") }
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unexpected_cfg_name)]
+pub struct UnexpectedCfgName {
+    #[subdiagnostic]
+    pub code_sugg: unexpected_cfg_name::CodeSuggestion,
+    #[subdiagnostic]
+    pub invocation_help: unexpected_cfg_name::InvocationHelp,
+
+    pub name: Symbol,
+}
+
+pub mod unexpected_cfg_name {
+    use rustc_errors::DiagSymbolList;
+    use rustc_macros::Subdiagnostic;
+    use rustc_span::{Span, Symbol};
+
+    #[derive(Subdiagnostic)]
+    pub enum CodeSuggestion {
+        #[help(lint_unexpected_cfg_define_features)]
+        DefineFeatures,
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name_value,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarNameAndValue {
+            #[primary_span]
+            span: Span,
+            code: String,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name_no_value,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarNameNoValue {
+            #[primary_span]
+            span: Span,
+            code: String,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name_different_values,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarNameDifferentValues {
+            #[primary_span]
+            span: Span,
+            code: String,
+            #[subdiagnostic]
+            expected: Option<ExpectedValues>,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarName {
+            #[primary_span]
+            span: Span,
+            code: String,
+            #[subdiagnostic]
+            expected: Option<ExpectedValues>,
+        },
+        SimilarValues {
+            #[subdiagnostic]
+            with_similar_values: Vec<FoundWithSimilarValue>,
+            #[subdiagnostic]
+            expected_names: Option<ExpectedNames>,
+        },
+    }
+
+    #[derive(Subdiagnostic)]
+    #[help(lint_unexpected_cfg_name_expected_values)]
+    pub struct ExpectedValues {
+        pub best_match: Symbol,
+        pub possibilities: DiagSymbolList,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[suggestion(
+        lint_unexpected_cfg_name_with_similar_value,
+        applicability = "maybe-incorrect",
+        code = "{code}"
+    )]
+    pub struct FoundWithSimilarValue {
+        #[primary_span]
+        pub span: Span,
+        pub code: String,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[help_once(lint_unexpected_cfg_name_expected_names)]
+    pub struct ExpectedNames {
+        pub possibilities: DiagSymbolList,
+        pub and_more: usize,
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum InvocationHelp {
+        #[note(lint_unexpected_cfg_doc_cargo)]
+        Cargo {
+            #[subdiagnostic]
+            sub: Option<super::UnexpectedCfgCargoHelp>,
+        },
+        #[note(lint_unexpected_cfg_doc_rustc)]
+        Rustc(#[subdiagnostic] super::UnexpectedCfgRustcHelp),
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unexpected_cfg_value)]
+pub struct UnexpectedCfgValue {
+    #[subdiagnostic]
+    pub code_sugg: unexpected_cfg_value::CodeSuggestion,
+    #[subdiagnostic]
+    pub invocation_help: unexpected_cfg_value::InvocationHelp,
+
+    pub has_value: bool,
+    pub value: String,
+}
+
+pub mod unexpected_cfg_value {
+    use rustc_errors::DiagSymbolList;
+    use rustc_macros::Subdiagnostic;
+    use rustc_span::{Span, Symbol};
+
+    #[derive(Subdiagnostic)]
+    pub enum CodeSuggestion {
+        ChangeValue {
+            #[subdiagnostic]
+            expected_values: ExpectedValues,
+            #[subdiagnostic]
+            suggestion: Option<ChangeValueSuggestion>,
+        },
+        #[note(lint_unexpected_cfg_value_no_expected_value)]
+        RemoveValue {
+            #[subdiagnostic]
+            suggestion: Option<RemoveValueSuggestion>,
+
+            name: Symbol,
+        },
+        #[note(lint_unexpected_cfg_value_no_expected_values)]
+        RemoveCondition {
+            #[subdiagnostic]
+            suggestion: RemoveConditionSuggestion,
+
+            name: Symbol,
+        },
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum ChangeValueSuggestion {
+        #[suggestion(
+            lint_unexpected_cfg_value_similar_name,
+            code = r#""{best_match}""#,
+            applicability = "maybe-incorrect"
+        )]
+        SimilarName {
+            #[primary_span]
+            span: Span,
+            best_match: Symbol,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_value_specify_value,
+            code = r#" = "{first_possibility}""#,
+            applicability = "maybe-incorrect"
+        )]
+        SpecifyValue {
+            #[primary_span]
+            span: Span,
+            first_possibility: Symbol,
+        },
+    }
+
+    #[derive(Subdiagnostic)]
+    #[suggestion(
+        lint_unexpected_cfg_value_remove_value,
+        code = "",
+        applicability = "maybe-incorrect"
+    )]
+    pub struct RemoveValueSuggestion {
+        #[primary_span]
+        pub span: Span,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[suggestion(
+        lint_unexpected_cfg_value_remove_condition,
+        code = "",
+        applicability = "maybe-incorrect"
+    )]
+    pub struct RemoveConditionSuggestion {
+        #[primary_span]
+        pub span: Span,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[note(lint_unexpected_cfg_value_expected_values)]
+    pub struct ExpectedValues {
+        pub name: Symbol,
+        pub have_none_possibility: bool,
+        pub possibilities: DiagSymbolList,
+        pub and_more: usize,
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum InvocationHelp {
+        #[note(lint_unexpected_cfg_doc_cargo)]
+        Cargo(#[subdiagnostic] Option<CargoHelp>),
+        #[note(lint_unexpected_cfg_doc_rustc)]
+        Rustc(#[subdiagnostic] Option<super::UnexpectedCfgRustcHelp>),
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum CargoHelp {
+        #[help(lint_unexpected_cfg_value_add_feature)]
+        AddFeature {
+            value: Symbol,
+        },
+        #[help(lint_unexpected_cfg_define_features)]
+        DefineFeatures,
+        Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_use_deprecated)]
+pub struct MacroUseDeprecated;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_macro_use)]
+pub struct UnusedMacroUse;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_private_extern_crate_reexport)]
+pub struct PrivateExternCrateReexport {
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_label)]
+pub struct UnusedLabel;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_is_private)]
+pub struct MacroIsPrivate {
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_macro_definition)]
+pub struct UnusedMacroDefinition {
+    pub name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_rule_never_used)]
+pub struct MacroRuleNeverUsed {
+    pub n: usize,
+    pub name: Symbol,
+}
+
+pub struct UnstableFeature {
+    pub msg: DiagMessage,
+}
+
+impl<'a> LintDiagnostic<'a, ()> for UnstableFeature {
+    fn decorate_lint<'b>(self, _diag: &'b mut Diag<'a, ()>) {}
+
+    fn msg(&self) -> DiagMessage {
+        self.msg.clone()
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_avoid_intel_syntax)]
+pub struct AvoidIntelSyntax;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_avoid_att_syntax)]
+pub struct AvoidAttSyntax;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_incomplete_include)]
+pub struct IncompleteInclude;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unnameable_test_items)]
+pub struct UnnameableTestItems;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_duplicate_macro_attribute)]
+pub struct DuplicateMacroAttribute;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_cfg_attr_no_attributes)]
+pub struct CfgAttrNoAttributes;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_crate_type_in_cfg_attr_deprecated)]
+pub struct CrateTypeInCfgAttr;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_crate_name_in_cfg_attr_deprecated)]
+pub struct CrateNameInCfgAttr;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_missing_fragment_specifier)]
+pub struct MissingFragmentSpecifier;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_metavariable_still_repeating)]
+pub struct MetaVariableStillRepeating {
+    pub name: MacroRulesNormalizedIdent,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_metavariable_wrong_operator)]
+pub struct MetaVariableWrongOperator;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_duplicate_matcher_binding)]
+pub struct DuplicateMatcherBinding;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_macro_variable)]
+pub struct UnknownMacroVariable {
+    pub name: MacroRulesNormalizedIdent,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_crate_dependency)]
+pub struct UnusedCrateDependency {
+    pub extern_crate: Symbol,
+    pub local_crate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_wasm_c_abi)]
+pub struct WasmCAbi;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_ill_formed_attribute_input)]
+pub struct IllFormedAttributeInput {
+    pub num_suggestions: usize,
+    pub suggestions: DiagArgValue,
+}
+
+#[derive(LintDiagnostic)]
+pub enum InnerAttributeUnstable {
+    #[diag(lint_inner_macro_attribute_unstable)]
+    InnerMacroAttribute,
+    #[diag(lint_custom_inner_attribute_unstable)]
+    CustomInnerAttribute,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_diagnostic_attribute)]
+pub struct UnknownDiagnosticAttribute {
+    #[subdiagnostic]
+    pub typo: Option<UnknownDiagnosticAttributeTypoSugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    lint_unknown_diagnostic_attribute_typo_sugg,
+    style = "verbose",
+    code = "{typo_name}",
+    applicability = "machine-applicable"
+)]
+pub struct UnknownDiagnosticAttributeTypoSugg {
+    #[primary_span]
+    pub span: Span,
+    pub typo_name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unicode_text_flow)]
+#[note]
+pub struct UnicodeTextFlow {
+    #[label]
+    pub comment_span: Span,
+    #[subdiagnostic]
+    pub characters: Vec<UnicodeCharNoteSub>,
+    #[subdiagnostic]
+    pub suggestions: Option<UnicodeTextFlowSuggestion>,
+
+    pub num_codepoints: usize,
+}
+
+#[derive(Subdiagnostic)]
+#[label(lint_label_comment_char)]
+pub struct UnicodeCharNoteSub {
+    #[primary_span]
+    pub span: Span,
+    pub c_debug: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable", style = "hidden")]
+pub struct UnicodeTextFlowSuggestion {
+    #[suggestion_part(code = "")]
+    pub spans: Vec<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_abs_path_with_module)]
+pub struct AbsPathWithModule {
+    #[subdiagnostic]
+    pub sugg: AbsPathWithModuleSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_suggestion, code = "{replacement}")]
+pub struct AbsPathWithModuleSugg {
+    #[primary_span]
+    pub span: Span,
+    #[applicability]
+    pub applicability: Applicability,
+    pub replacement: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_proc_macro_derive_resolution_fallback)]
+pub struct ProcMacroDeriveResolutionFallback {
+    #[label]
+    pub span: Span,
+    pub ns: Namespace,
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)]
+pub struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
+    #[note]
+    pub definition: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_hidden_lifetime_parameters)]
+pub struct ElidedLifetimesInPaths {
+    #[subdiagnostic]
+    pub subdiag: ElidedLifetimeInPathSubdiag,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_invalid_crate_type_value)]
+pub struct UnknownCrateTypes {
+    #[subdiagnostic]
+    pub sugg: Option<UnknownCrateTypesSub>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")]
+pub struct UnknownCrateTypesSub {
+    #[primary_span]
+    pub span: Span,
+    pub candidate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_imports)]
+pub struct UnusedImports {
+    #[subdiagnostic]
+    pub sugg: UnusedImportsSugg,
+    #[help]
+    pub test_module_span: Option<Span>,
+
+    pub span_snippets: DiagArgValue,
+    pub num_snippets: usize,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnusedImportsSugg {
+    #[suggestion(
+        lint_suggestion_remove_whole_use,
+        applicability = "machine-applicable",
+        code = "",
+        style = "tool-only"
+    )]
+    RemoveWholeUse {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(
+        lint_suggestion_remove_imports,
+        applicability = "machine-applicable",
+        style = "tool-only"
+    )]
+    RemoveImports {
+        #[suggestion_part(code = "")]
+        remove_spans: Vec<Span>,
+        num_to_remove: usize,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_redundant_import)]
+pub struct RedundantImport {
+    #[subdiagnostic]
+    pub subs: Vec<RedundantImportSub>,
+
+    pub ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
+pub enum RedundantImportSub {
+    #[label(lint_label_imported_here)]
+    ImportedHere(#[primary_span] Span),
+    #[label(lint_label_defined_here)]
+    DefinedHere(#[primary_span] Span),
+    #[label(lint_label_imported_prelude)]
+    ImportedPrelude(#[primary_span] Span),
+    #[label(lint_label_defined_prelude)]
+    DefinedPrelude(#[primary_span] Span),
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_doc_comment)]
+#[help]
+pub struct UnusedDocComment {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+pub enum PatternsInFnsWithoutBody {
+    #[diag(lint_pattern_in_foreign)]
+    Foreign {
+        #[subdiagnostic]
+        sub: PatternsInFnsWithoutBodySub,
+    },
+    #[diag(lint_pattern_in_bodiless)]
+    Bodiless {
+        #[subdiagnostic]
+        sub: PatternsInFnsWithoutBodySub,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_remove_mut_from_pattern, code = "{ident}", applicability = "machine-applicable")]
+pub struct PatternsInFnsWithoutBodySub {
+    #[primary_span]
+    pub span: Span,
+
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_extern_without_abi)]
+#[help]
+pub struct MissingAbi {
+    #[label]
+    pub span: Span,
+
+    pub default_abi: &'static str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_legacy_derive_helpers)]
+pub struct LegacyDeriveHelpers {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_proc_macro_back_compat)]
+#[note]
+pub struct ProcMacroBackCompat {
+    pub crate_name: String,
+    pub fixed_version: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_or_patterns_back_compat)]
+pub struct OrPatternsBackCompat {
+    #[suggestion(code = "{suggestion}", applicability = "machine-applicable")]
+    pub span: Span,
+    pub suggestion: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_reserved_prefix)]
+pub struct ReservedPrefix {
+    #[label]
+    pub label: Span,
+    #[suggestion(code = " ", applicability = "machine-applicable")]
+    pub suggestion: Span,
+
+    pub prefix: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_builtin_attribute)]
+pub struct UnusedBuiltinAttribute {
+    #[note]
+    pub invoc_span: Span,
+
+    pub attr_name: Symbol,
+    pub macro_name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_trailing_semi_macro)]
+pub struct TrailingMacro {
+    #[note(lint_note1)]
+    #[note(lint_note2)]
+    pub is_trailing: bool,
+
+    pub name: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_break_with_label_and_loop)]
+pub struct BreakWithLabelAndLoop {
+    #[subdiagnostic]
+    pub sub: BreakWithLabelAndLoopSub,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
+pub struct BreakWithLabelAndLoopSub {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_deprecated_where_clause_location)]
+#[note]
+pub struct DeprecatedWhereClauseLocation {
+    #[subdiagnostic]
+    pub suggestion: DeprecatedWhereClauseLocationSugg,
+}
+
+#[derive(Subdiagnostic)]
+pub enum DeprecatedWhereClauseLocationSugg {
+    #[multipart_suggestion(lint_suggestion_move_to_end, applicability = "machine-applicable")]
+    MoveToEnd {
+        #[suggestion_part(code = "")]
+        left: Span,
+        #[suggestion_part(code = "{sugg}")]
+        right: Span,
+
+        sugg: String,
+    },
+    #[suggestion(lint_suggestion_remove_where, code = "", applicability = "machine-applicable")]
+    RemoveWhere {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_single_use_lifetime)]
+pub struct SingleUseLifetime {
+    #[label(lint_label_param)]
+    pub param_span: Span,
+    #[label(lint_label_use)]
+    pub use_span: Span,
+    #[subdiagnostic]
+    pub suggestion: Option<SingleUseLifetimeSugg>,
+
+    pub ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
+pub struct SingleUseLifetimeSugg {
+    #[suggestion_part(code = "")]
+    pub deletion_span: Option<Span>,
+    #[suggestion_part(code = "{replace_lt}")]
+    pub use_span: Span,
+
+    pub replace_lt: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_lifetime)]
+pub struct UnusedLifetime {
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub deletion_span: Option<Span>,
+
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_named_argument_used_positionally)]
+pub struct NamedArgumentUsedPositionally {
+    #[label(lint_label_named_arg)]
+    pub named_arg_sp: Span,
+    #[label(lint_label_position_arg)]
+    pub position_label_sp: Option<Span>,
+    #[suggestion(style = "verbose", code = "{name}", applicability = "maybe-incorrect")]
+    pub suggestion: Option<Span>,
+
+    pub name: String,
+    pub named_arg_name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_byte_slice_in_packed_struct_with_derive)]
+#[help]
+pub struct ByteSliceInPackedStructWithDerive {
+    // FIXME: make this translatable
+    pub ty: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_extern_crate)]
+pub struct UnusedExternCrate {
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub removal_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_extern_crate_not_idiomatic)]
+pub struct ExternCrateNotIdiomatic {
+    #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
+    pub span: Span,
+
+    pub code: &'static str,
+}
+
+// FIXME: make this translatable
+pub struct AmbiguousGlobImports {
+    pub ambiguity: AmbiguityErrorDiag,
+}
+
+impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports {
+    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
+        rustc_errors::report_ambiguity_error(diag, self.ambiguity);
+    }
+
+    fn msg(&self) -> DiagMessage {
+        DiagMessage::Str(self.ambiguity.msg.clone().into())
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_ambiguous_glob_reexport)]
+pub struct AmbiguousGlobReexports {
+    #[label(lint_label_first_reexport)]
+    pub first_reexport: Span,
+    #[label(lint_label_duplicate_reexport)]
+    pub duplicate_reexport: Span,
+
+    pub name: String,
+    // FIXME: make this translatable
+    pub namespace: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_hidden_glob_reexport)]
+pub struct HiddenGlobReexports {
+    #[note(lint_note_glob_reexport)]
+    pub glob_reexport: Span,
+    #[note(lint_note_private_item)]
+    pub private_item: Span,
+
+    pub name: String,
+    // FIXME: make this translatable
+    pub namespace: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unnecessary_qualification)]
+pub struct UnusedQualifications {
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
+    pub removal_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_associated_const_elided_lifetime)]
+pub struct AssociatedConstElidedLifetime {
+    #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
+    pub span: Span,
+
+    pub code: &'static str,
+    pub elided: bool,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_redundant_import_visibility)]
+pub struct RedundantImportVisibility {
+    #[note]
+    pub span: Span,
+    #[help]
+    pub help: (),
+
+    pub import_vis: String,
+    pub max_vis: String,
+}
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 885c0bb3a89..b3e93748a16 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -38,7 +38,7 @@ declare_lint! {
     ///
     /// Creating non-local definitions go against expectation and can create discrepancies
     /// in tooling. It should be avoided. It may become deny-by-default in edition 2024
-    /// and higher, see see the tracking issue <https://github.com/rust-lang/rust/issues/120363>.
+    /// and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>.
     ///
     /// An `impl` definition is non-local if it is nested inside an item and neither
     /// the type nor the trait are at the same nesting level as the `impl` block.
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
new file mode 100644
index 00000000000..41ec84faa78
--- /dev/null
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -0,0 +1,157 @@
+use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub};
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_hir as hir;
+use rustc_middle::ty::{self, Ty};
+use rustc_session::lint::FutureIncompatibilityReason;
+use rustc_session::{declare_lint, impl_lint_pass};
+use rustc_span::edition::Edition;
+
+declare_lint! {
+    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2018
+    /// # #![allow(unused)]
+    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
+    /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
+    /// behave as `(&array).into_iter()`, returning an iterator over
+    /// references, just like in Rust 1.52 and earlier.
+    /// This only applies to the method call syntax `array.into_iter()`, not to
+    /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
+    pub ARRAY_INTO_ITER,
+    Warn,
+    "detects calling `into_iter` on arrays in Rust 2015 and 2018",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
+    };
+}
+
+declare_lint! {
+    /// The `boxed_slice_into_iter` lint detects calling `into_iter` on boxed slices.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2021
+    /// # #![allow(unused)]
+    /// vec![1, 2, 3].into_boxed_slice().into_iter().for_each(|n| { *n; });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Since Rust CURRENT_RUSTC_VERSION, boxed slices implement `IntoIterator`. However, to avoid
+    /// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still
+    /// behave as `(&boxed_slice).into_iter()`, returning an iterator over
+    /// references, just like in Rust CURRENT_RUSTC_VERSION and earlier.
+    /// This only applies to the method call syntax `boxed_slice.into_iter()`, not to
+    /// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`.
+    pub BOXED_SLICE_INTO_ITER,
+    Warn,
+    "detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+    };
+}
+
+#[derive(Copy, Clone)]
+pub struct ShadowedIntoIter;
+
+impl_lint_pass!(ShadowedIntoIter => [ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER]);
+
+impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind else {
+            return;
+        };
+
+        // Check if the method call actually calls the libcore
+        // `IntoIterator::into_iter`.
+        let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
+            return;
+        };
+        if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() {
+            return;
+        }
+
+        // As this is a method call expression, we have at least one argument.
+        let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
+        let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
+
+        let adjusted_receiver_tys: Vec<_> =
+            [receiver_ty].into_iter().chain(adjustments.iter().map(|adj| adj.target)).collect();
+
+        fn is_ref_to_array(ty: Ty<'_>) -> bool {
+            if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false }
+        }
+        fn is_boxed_slice(ty: Ty<'_>) -> bool {
+            ty.is_box() && ty.boxed_ty().is_slice()
+        }
+        fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool {
+            if let ty::Ref(_, pointee_ty, _) = *ty.kind() {
+                is_boxed_slice(pointee_ty)
+            } else {
+                false
+            }
+        }
+
+        let (lint, target, edition, can_suggest_ufcs) =
+            if is_ref_to_array(*adjusted_receiver_tys.last().unwrap())
+                && let Some(idx) = adjusted_receiver_tys
+                    .iter()
+                    .copied()
+                    .take_while(|ty| !is_ref_to_array(*ty))
+                    .position(|ty| ty.is_array())
+            {
+                (ARRAY_INTO_ITER, "[T; N]", "2021", idx == 0)
+            } else if is_ref_to_boxed_slice(*adjusted_receiver_tys.last().unwrap())
+                && let Some(idx) = adjusted_receiver_tys
+                    .iter()
+                    .copied()
+                    .take_while(|ty| !is_ref_to_boxed_slice(*ty))
+                    .position(|ty| is_boxed_slice(ty))
+            {
+                (BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0)
+            } else {
+                return;
+            };
+
+        // If this expression comes from the `IntoIter::into_iter` inside of a for loop,
+        // we should just suggest removing the `.into_iter()` or changing it to `.iter()`
+        // to disambiguate if we want to iterate by-value or by-ref.
+        let sub = if let Some((_, hir::Node::Expr(parent_expr))) =
+            cx.tcx.hir().parent_iter(expr.hir_id).nth(1)
+            && let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) =
+                &parent_expr.kind
+            && let hir::ExprKind::Call(path, [_]) = &arg.kind
+            && let hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoIterIntoIter, ..)) =
+                &path.kind
+        {
+            Some(ShadowedIntoIterDiagSub::RemoveIntoIter {
+                span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+            })
+        } else if can_suggest_ufcs {
+            Some(ShadowedIntoIterDiagSub::UseExplicitIntoIter {
+                start_span: expr.span.shrink_to_lo(),
+                end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+            })
+        } else {
+            None
+        };
+
+        cx.emit_span_lint(
+            lint,
+            call.ident.span,
+            ShadowedIntoIterDiag { target, edition, suggestion: call.ident.span, sub },
+        );
+    }
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 53694545772..82f16b31a66 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3339,11 +3339,14 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// This lint is only active when `--check-cfg` arguments are being passed
-    /// to the compiler and triggers whenever an unexpected condition name or value is used.
+    /// This lint is only active when [`--check-cfg`][check-cfg] arguments are being
+    /// passed to the compiler and triggers whenever an unexpected condition name or value is
+    /// used.
+    ///
+    /// See the [Checking Conditional Configurations][check-cfg] section for more
+    /// details.
     ///
-    /// The known condition include names or values passed in `--check-cfg`, and some
-    /// well-knows names and values built into the compiler.
+    /// [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
     pub UNEXPECTED_CFGS,
     Warn,
     "detects unexpected names and values in `#[cfg]` conditions",
@@ -4263,8 +4266,7 @@ declare_lint! {
     ///
     /// // where absurd is a function with the following signature
     /// // (it's sound, because `!` always marks unreachable code):
-    /// fn absurd<T>(_: !) -> T { ... }
-    // FIXME: use `core::convert::absurd` here instead, once it's merged
+    /// fn absurd<T>(never: !) -> T { ... }
     /// ```
     ///
     /// While it's convenient to be able to use non-diverging code in one of the branches (like
@@ -4321,7 +4323,12 @@ declare_lint! {
     /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html
     pub NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
     Warn,
-    "never type fallback affecting unsafe function calls"
+    "never type fallback affecting unsafe function calls",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
+        reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
+    };
+    report_in_external_macro
 }
 
 declare_lint! {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index e06e3e9b805..1941b0b1264 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -6,10 +6,12 @@ use rustc_data_structures::stable_hasher::{
     HashStable, StableCompare, StableHasher, ToStableHashKey,
 };
 use rustc_error_messages::{DiagMessage, MultiSpan};
+use rustc_hir::def::Namespace;
 use rustc_hir::HashStableContext;
 use rustc_hir::HirId;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::edition::Edition;
+use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::{sym, symbol::Ident, Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -565,19 +567,44 @@ pub struct AmbiguityErrorDiag {
     pub b2_help_msgs: Vec<String>,
 }
 
+#[derive(Debug, Clone)]
+pub enum DeprecatedSinceKind {
+    InEffect,
+    InFuture,
+    InVersion(String),
+}
+
 // This could be a closure, but then implementing derive trait
 // becomes hacky (and it gets allocated).
 #[derive(Debug)]
 pub enum BuiltinLintDiag {
-    Normal,
     AbsPathWithModule(Span),
-    ProcMacroDeriveResolutionFallback(Span),
+    ProcMacroDeriveResolutionFallback {
+        span: Span,
+        ns: Namespace,
+        ident: Ident,
+    },
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
     ElidedLifetimesInPaths(usize, Span, bool, Span),
-    UnknownCrateTypes(Span, String, String),
-    UnusedImports(String, Vec<(Span, String)>, Option<Span>),
+    UnknownCrateTypes {
+        span: Span,
+        candidate: Option<Symbol>,
+    },
+    UnusedImports {
+        remove_whole_use: bool,
+        num_to_remove: usize,
+        remove_spans: Vec<Span>,
+        test_module_span: Option<Span>,
+        span_snippets: Vec<String>,
+    },
     RedundantImport(Vec<(Span, bool)>, Ident),
-    DeprecatedMacro(Option<Symbol>, Span),
+    DeprecatedMacro {
+        suggestion: Option<Symbol>,
+        suggestion_span: Span,
+        note: Option<Symbol>,
+        path: String,
+        since_kind: DeprecatedSinceKind,
+    },
     MissingAbi(Span, Abi),
     UnusedDocComment(Span),
     UnusedBuiltinAttribute {
@@ -585,18 +612,24 @@ pub enum BuiltinLintDiag {
         macro_name: String,
         invoc_span: Span,
     },
-    PatternsInFnsWithoutBody(Span, Ident),
+    PatternsInFnsWithoutBody {
+        span: Span,
+        ident: Ident,
+        is_foreign: bool,
+    },
     LegacyDeriveHelpers(Span),
-    ProcMacroBackCompat(String),
+    ProcMacroBackCompat {
+        crate_name: String,
+        fixed_version: String,
+    },
     OrPatternsBackCompat(Span, String),
-    ReservedPrefix(Span),
+    ReservedPrefix(Span, String),
     TrailingMacro(bool, Ident),
     BreakWithLabelAndLoop(Span),
-    NamedAsmLabel(String),
     UnicodeTextFlow(Span, String),
     UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
     UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
-    DeprecatedWhereclauseLocation(Option<(Span, String)>),
+    DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
         param_span: Span,
@@ -606,6 +639,7 @@ pub enum BuiltinLintDiag {
         /// Span of the single use, or None if the lifetime is never used.
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
+        ident: Ident,
     },
     NamedArgumentUsedPositionally {
         /// Span where the named argument is used by position and will be replaced with the named
@@ -620,7 +654,10 @@ pub enum BuiltinLintDiag {
         /// Indicates if the named argument is used as a width/precision for formatting
         is_formatting_arg: bool,
     },
-    ByteSliceInPackedStructWithDerive,
+    ByteSliceInPackedStructWithDerive {
+        // FIXME: enum of byte/string
+        ty: String,
+    },
     UnusedExternCrate {
         removal_span: Span,
     },
@@ -662,10 +699,43 @@ pub enum BuiltinLintDiag {
     RedundantImportVisibility {
         span: Span,
         max_vis: String,
+        import_vis: String,
     },
-    MaybeTypo {
+    UnknownDiagnosticAttribute {
         span: Span,
-        name: Symbol,
+        typo_name: Option<Symbol>,
+    },
+    MacroUseDeprecated,
+    UnusedMacroUse,
+    PrivateExternCrateReexport(Ident),
+    UnusedLabel,
+    MacroIsPrivate(Ident),
+    UnusedMacroDefinition(Symbol),
+    MacroRuleNeverUsed(usize, Symbol),
+    UnstableFeature(DiagMessage),
+    AvoidUsingIntelSyntax,
+    AvoidUsingAttSyntax,
+    IncompleteInclude,
+    UnnameableTestItems,
+    DuplicateMacroAttribute,
+    CfgAttrNoAttributes,
+    CrateTypeInCfgAttr,
+    CrateNameInCfgAttr,
+    MissingFragmentSpecifier,
+    MetaVariableStillRepeating(MacroRulesNormalizedIdent),
+    MetaVariableWrongOperator,
+    DuplicateMatcherBinding,
+    UnknownMacroVariable(MacroRulesNormalizedIdent),
+    UnusedCrateDependency {
+        extern_crate: Symbol,
+        local_crate: Symbol,
+    },
+    WasmCAbi,
+    IllFormedAttributeInput {
+        suggestions: Vec<String>,
+    },
+    InnerAttributeUnstable {
+        is_macro: bool,
     },
 }
 
@@ -676,9 +746,6 @@ pub struct BufferedEarlyLint {
     /// The span of code that we are linting on.
     pub span: MultiSpan,
 
-    /// The lint message.
-    pub msg: DiagMessage,
-
     /// The `NodeId` of the AST node that generated the lint.
     pub node_id: NodeId,
 
@@ -706,12 +773,10 @@ impl LintBuffer {
         lint: &'static Lint,
         node_id: NodeId,
         span: MultiSpan,
-        msg: impl Into<DiagMessage>,
         diagnostic: BuiltinLintDiag,
     ) {
         let lint_id = LintId::of(lint);
-        let msg = msg.into();
-        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
+        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, diagnostic });
     }
 
     pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
@@ -724,20 +789,9 @@ impl LintBuffer {
         lint: &'static Lint,
         id: NodeId,
         sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagMessage>,
-    ) {
-        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiag::Normal)
-    }
-
-    pub fn buffer_lint_with_diagnostic(
-        &mut self,
-        lint: &'static Lint,
-        id: NodeId,
-        sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagMessage>,
         diagnostic: BuiltinLintDiag,
     ) {
-        self.add_lint(lint, id, sp.into(), msg, diagnostic)
+        self.add_lint(lint, id, sp.into(), diagnostic)
     }
 }
 
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index ae481efb263..38d4a5ee61c 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -158,7 +158,9 @@ impl DiagnosticDeriveVariantBuilder {
         let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind {
             SubdiagnosticKind::Label => parse_quote! { _subdiag::label },
             SubdiagnosticKind::Note => parse_quote! { _subdiag::note },
+            SubdiagnosticKind::NoteOnce => parse_quote! { _subdiag::note_once },
             SubdiagnosticKind::Help => parse_quote! { _subdiag::help },
+            SubdiagnosticKind::HelpOnce => parse_quote! { _subdiag::help_once },
             SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn },
             SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion },
             SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
@@ -233,9 +235,11 @@ impl DiagnosticDeriveVariantBuilder {
         };
         let fn_ident = format_ident!("{}", subdiag);
         match subdiag {
-            SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
-                Ok(self.add_subdiagnostic(&fn_ident, slug))
-            }
+            SubdiagnosticKind::Note
+            | SubdiagnosticKind::NoteOnce
+            | SubdiagnosticKind::Help
+            | SubdiagnosticKind::HelpOnce
+            | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, slug)),
             SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
                 throw_invalid_attr!(attr, |diag| diag
                     .help("`#[label]` and `#[suggestion]` can only be applied to fields"));
@@ -347,7 +351,11 @@ impl DiagnosticDeriveVariantBuilder {
                 report_error_if_not_applied_to_span(attr, &info)?;
                 Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
             }
-            SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
+            SubdiagnosticKind::Note
+            | SubdiagnosticKind::NoteOnce
+            | SubdiagnosticKind::Help
+            | SubdiagnosticKind::HelpOnce
+            | SubdiagnosticKind::Warn => {
                 let inner = info.ty.inner_type();
                 if type_matches_path(inner, &["rustc_span", "Span"])
                     || type_matches_path(inner, &["rustc_span", "MultiSpan"])
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 45236771bce..69014f39925 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -510,11 +510,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
             .map(|binding| self.generate_field_attr_code(binding, kind_stats))
             .collect();
 
-        if kind_slugs.is_empty() {
+        if kind_slugs.is_empty() && !self.has_subdiagnostic {
             if self.is_enum {
                 // It's okay for a variant to not be a subdiagnostic at all..
                 return Ok(quote! {});
-            } else if !self.has_subdiagnostic {
+            } else {
                 // ..but structs should always be _something_.
                 throw_span_err!(
                     self.variant.ast().ident.span().unwrap(),
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 4684306e235..05a5a32514b 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -575,8 +575,12 @@ pub(super) enum SubdiagnosticKind {
     Label,
     /// `#[note(...)]`
     Note,
+    /// `#[note_once(...)]`
+    NoteOnce,
     /// `#[help(...)]`
     Help,
+    /// `#[help_once(...)]`
+    HelpOnce,
     /// `#[warning(...)]`
     Warn,
     /// `#[suggestion{,_short,_hidden,_verbose}]`
@@ -624,7 +628,9 @@ impl SubdiagnosticVariant {
         let mut kind = match name {
             "label" => SubdiagnosticKind::Label,
             "note" => SubdiagnosticKind::Note,
+            "note_once" => SubdiagnosticKind::NoteOnce,
             "help" => SubdiagnosticKind::Help,
+            "help_once" => SubdiagnosticKind::HelpOnce,
             "warning" => SubdiagnosticKind::Warn,
             _ => {
                 // Recover old `#[(multipart_)suggestion_*]` syntaxes
@@ -682,7 +688,9 @@ impl SubdiagnosticVariant {
                 match kind {
                     SubdiagnosticKind::Label
                     | SubdiagnosticKind::Note
+                    | SubdiagnosticKind::NoteOnce
                     | SubdiagnosticKind::Help
+                    | SubdiagnosticKind::HelpOnce
                     | SubdiagnosticKind::Warn
                     | SubdiagnosticKind::MultipartSuggestion { .. } => {
                         return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false }));
@@ -836,7 +844,9 @@ impl SubdiagnosticVariant {
             }
             SubdiagnosticKind::Label
             | SubdiagnosticKind::Note
+            | SubdiagnosticKind::NoteOnce
             | SubdiagnosticKind::Help
+            | SubdiagnosticKind::HelpOnce
             | SubdiagnosticKind::Warn => {}
         }
 
@@ -849,7 +859,9 @@ impl quote::IdentFragment for SubdiagnosticKind {
         match self {
             SubdiagnosticKind::Label => write!(f, "label"),
             SubdiagnosticKind::Note => write!(f, "note"),
+            SubdiagnosticKind::NoteOnce => write!(f, "note_once"),
             SubdiagnosticKind::Help => write!(f, "help"),
+            SubdiagnosticKind::HelpOnce => write!(f, "help_once"),
             SubdiagnosticKind::Warn => write!(f, "warn"),
             SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"),
             SubdiagnosticKind::MultipartSuggestion { .. } => {
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index c7b7eadbd9d..de9c916b4f0 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -108,7 +108,9 @@ decl_derive!(
         // struct attributes
         diag,
         help,
+        help_once,
         note,
+        note_once,
         warning,
         // field attributes
         skip_arg,
@@ -125,7 +127,9 @@ decl_derive!(
         // struct attributes
         diag,
         help,
+        help_once,
         note,
+        note_once,
         warning,
         // field attributes
         skip_arg,
@@ -142,7 +146,9 @@ decl_derive!(
         // struct/variant attributes
         label,
         help,
+        help_once,
         note,
+        note_once,
         warning,
         subdiagnostic,
         suggestion,
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 3d0846ae6de..2f5dfad265c 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -284,8 +284,6 @@ metadata_unsupported_abi =
 metadata_unsupported_abi_i686 =
     ABI not supported by `#[link(kind = "raw-dylib")]` on i686
 
-metadata_wasm_c_abi =
-    older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
 metadata_wasm_import_form =
     wasm import module must be of the form `wasm_import_module = "string"`
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index e3205fc1d30..be1a73ef0a7 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -20,7 +20,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
-use rustc_session::lint;
+use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_span::edition::Edition;
@@ -975,15 +975,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
 
             self.sess.psess.buffer_lint(
-                    lint::builtin::UNUSED_CRATE_DEPENDENCIES,
-                    span,
-                    ast::CRATE_NODE_ID,
-                    format!(
-                        "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
-                        name,
-                        self.tcx.crate_name(LOCAL_CRATE),
-                        name),
-                );
+                lint::builtin::UNUSED_CRATE_DEPENDENCIES,
+                span,
+                ast::CRATE_NODE_ID,
+                BuiltinLintDiag::UnusedCrateDependency {
+                    extern_crate: name_interned,
+                    local_crate: self.tcx.crate_name(LOCAL_CRATE),
+                },
+            );
         }
     }
 
@@ -1020,7 +1019,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 lint::builtin::WASM_C_ABI,
                 span,
                 ast::CRATE_NODE_ID,
-                crate::fluent_generated::metadata_wasm_c_abi,
+                BuiltinLintDiag::WasmCAbi,
             );
         }
     }
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 99584845e49..00bb4c435c8 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,21 +1,22 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
+#![feature(coroutines)]
 #![feature(decl_macro)]
 #![feature(error_iter)]
 #![feature(extract_if)]
-#![feature(coroutines)]
+#![feature(if_let_guard)]
 #![feature(iter_from_coroutine)]
 #![feature(let_chains)]
-#![feature(if_let_guard)]
-#![feature(proc_macro_internals)]
 #![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
-#![feature(trusted_len)]
-#![feature(try_blocks)]
 #![feature(never_type)]
-#![allow(rustc::potential_query_instability)]
+#![feature(proc_macro_internals)]
+#![feature(rustdoc_internals)]
+#![feature(trusted_len)]
+// tidy-alphabetical-end
 
 extern crate proc_macro;
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 79e4ff81093..825034cf96a 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,15 +1,13 @@
 use crate::creader::CrateMetadataRef;
-use decoder::Metadata;
+pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
+use decoder::{DecodeContext, Metadata};
 use def_path_hash_map::DefPathHashMapRef;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
-use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
-use rustc_middle::middle::lib_features::FeatureStability;
-use table::TableBuilder;
-
+use encoder::EncodeContext;
+pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
 use rustc_ast as ast;
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_attr as attr;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
@@ -18,10 +16,13 @@ use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
+use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
 use rustc_macros::{MetadataDecodable, MetadataEncodable};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use rustc_middle::middle::lib_features::FeatureStability;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::mir;
 use rustc_middle::trivially_parameterized_over_tcx;
@@ -33,20 +34,14 @@ use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::edition::Edition;
-use rustc_span::hygiene::{ExpnIndex, MacroKind};
+use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
-
 use std::marker::PhantomData;
 use std::num::NonZero;
-
-use decoder::DecodeContext;
-pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
-use encoder::EncodeContext;
-pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
-use rustc_span::hygiene::SyntaxContextData;
+use table::TableBuilder;
 
 mod decoder;
 mod def_path_hash_map;
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 27d555d7e26..f4d619329eb 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -50,6 +50,20 @@ middle_const_not_used_in_type_alias =
 middle_cycle =
     a cycle occurred during layout computation
 
+middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
+        [true] : {$note}
+        *[other] {""}
+    }
+middle_deprecated_in_future = use of {$kind} `{$path}` that will be deprecated in a future Rust version{$has_note ->
+        [true] : {$note}
+        *[other] {""}
+    }
+middle_deprecated_in_version = use of {$kind} `{$path}` that will be deprecated in future version {$version}{$has_note ->
+        [true] : {$note}
+        *[other] {""}
+    }
+middle_deprecated_suggestion = replace the use of the deprecated {$kind}
+
 middle_drop_check_overflow =
     overflow while adding drop-check rules for {$ty}
     .note = overflowed on {$overflow_ty}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index c7aea137b68..f3f24f77177 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -511,14 +511,14 @@ impl<'hir> Map<'hir> {
         self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
     }
 
-    /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
-    /// `while` or `loop` before reaching it, as block tail returns are not
-    /// available in them.
+    /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
+    /// in the "tail" position of the function, in other words if it's likely to correspond
+    /// to the return type of the function.
     ///
     /// ```
     /// fn foo(x: usize) -> bool {
     ///     if x == 1 {
-    ///         true  // If `get_return_block` gets passed the `id` corresponding
+    ///         true  // If `get_fn_id_for_return_block` gets passed the `id` corresponding
     ///     } else {  // to this, it will return `foo`'s `HirId`.
     ///         false
     ///     }
@@ -528,12 +528,12 @@ impl<'hir> Map<'hir> {
     /// ```compile_fail,E0308
     /// fn foo(x: usize) -> bool {
     ///     loop {
-    ///         true  // If `get_return_block` gets passed the `id` corresponding
+    ///         true  // If `get_fn_id_for_return_block` gets passed the `id` corresponding
     ///     }         // to this, it will return `None`.
     ///     false
     /// }
     /// ```
-    pub fn get_return_block(self, id: HirId) -> Option<HirId> {
+    pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
         let mut iter = self.parent_iter(id).peekable();
         let mut ignore_tail = false;
         if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
@@ -549,6 +549,11 @@ impl<'hir> Map<'hir> {
                     Node::Block(Block { expr: None, .. }) => return None,
                     // The current node is not the tail expression of its parent.
                     Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
+                    Node::Block(Block { expr: Some(e), .. })
+                        if matches!(e.kind, ExprKind::If(_, _, None)) =>
+                    {
+                        return None;
+                    }
                     _ => {}
                 }
             }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 04fd4c8d0f7..70437fdcb6f 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -22,46 +22,46 @@
 //!
 //! This API is completely unstable and subject to change.
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::potential_query_instability)]
+#![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(min_exhaustive_patterns)]
-#![feature(rustdoc_internals)]
 #![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(closure_track_caller)]
-#![feature(core_intrinsics)]
+#![feature(const_option)]
 #![feature(const_type_name)]
-#![feature(discriminant_kind)]
+#![feature(core_intrinsics)]
 #![feature(coroutines)]
-#![feature(stmt_expr_attributes)]
+#![feature(decl_macro)]
+#![feature(discriminant_kind)]
+#![feature(extern_types)]
+#![feature(extract_if)]
 #![feature(if_let_guard)]
+#![feature(intra_doc_pointers)]
 #![feature(iter_from_coroutine)]
+#![feature(let_chains)]
+#![feature(macro_metavar_expr)]
+#![feature(min_exhaustive_patterns)]
+#![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(extern_types)]
 #![feature(new_uninit)]
-#![feature(let_chains)]
-#![feature(min_specialization)]
-#![feature(trusted_len)]
-#![feature(type_alias_impl_trait)]
-#![feature(strict_provenance)]
+#![feature(ptr_alignment_type)]
 #![feature(rustc_attrs)]
-#![feature(control_flow_enum)]
+#![feature(rustdoc_internals)]
+#![feature(strict_provenance)]
 #![feature(trait_upcasting)]
+#![feature(trusted_len)]
 #![feature(try_blocks)]
-#![feature(decl_macro)]
-#![feature(extract_if)]
-#![feature(intra_doc_pointers)]
+#![feature(type_alias_impl_trait)]
 #![feature(yeet_expr)]
-#![feature(const_option)]
-#![feature(ptr_alignment_type)]
-#![feature(macro_metavar_expr)]
-#![allow(internal_features)]
-#![allow(rustc::potential_query_instability)]
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::untranslatable_diagnostic)]
+// tidy-alphabetical-end
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 67bd53f53da..e5df05763b0 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -9,15 +9,15 @@ use rustc_attr::{
     self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
 };
 use rustc_data_structures::unord::UnordMap;
-use rustc_errors::{Applicability, Diag};
+use rustc_errors::{Applicability, Diag, EmissionGuarantee};
 use rustc_feature::GateIssue;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
 use rustc_hir::{self as hir, HirId};
-use rustc_macros::{Decodable, Encodable, HashStable};
+use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
-use rustc_session::lint::{BuiltinLintDiag, Level, Lint, LintBuffer};
+use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer};
 use rustc_session::parse::feature_err_issue;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
@@ -125,90 +125,107 @@ pub fn report_unstable(
     }
 }
 
-pub fn deprecation_suggestion(
-    diag: &mut Diag<'_, ()>,
-    kind: &str,
-    suggestion: Option<Symbol>,
-    span: Span,
-) {
-    if let Some(suggestion) = suggestion {
-        diag.span_suggestion_verbose(
-            span,
-            format!("replace the use of the deprecated {kind}"),
-            suggestion,
-            Applicability::MachineApplicable,
-        );
-    }
-}
-
 fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
     if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE }
 }
 
-fn deprecation_message(
-    is_in_effect: bool,
-    since: DeprecatedSince,
-    note: Option<Symbol>,
-    kind: &str,
-    path: &str,
-) -> String {
-    let message = if is_in_effect {
-        format!("use of deprecated {kind} `{path}`")
+#[derive(Subdiagnostic)]
+#[suggestion(
+    middle_deprecated_suggestion,
+    code = "{suggestion}",
+    style = "verbose",
+    applicability = "machine-applicable"
+)]
+pub struct DeprecationSuggestion {
+    #[primary_span]
+    pub span: Span,
+
+    pub kind: String,
+    pub suggestion: Symbol,
+}
+
+pub struct Deprecated {
+    pub sub: Option<DeprecationSuggestion>,
+
+    // FIXME: make this translatable
+    pub kind: String,
+    pub path: String,
+    pub note: Option<Symbol>,
+    pub since_kind: DeprecatedSinceKind,
+}
+
+impl<'a, G: EmissionGuarantee> rustc_errors::LintDiagnostic<'a, G> for Deprecated {
+    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
+        diag.arg("kind", self.kind);
+        diag.arg("path", self.path);
+        if let DeprecatedSinceKind::InVersion(version) = self.since_kind {
+            diag.arg("version", version);
+        }
+        if let Some(note) = self.note {
+            diag.arg("has_note", true);
+            diag.arg("note", note);
+        } else {
+            diag.arg("has_note", false);
+        }
+        if let Some(sub) = self.sub {
+            diag.subdiagnostic(diag.dcx, sub);
+        }
+    }
+
+    fn msg(&self) -> rustc_errors::DiagMessage {
+        match &self.since_kind {
+            DeprecatedSinceKind::InEffect => crate::fluent_generated::middle_deprecated,
+            DeprecatedSinceKind::InFuture => crate::fluent_generated::middle_deprecated_in_future,
+            DeprecatedSinceKind::InVersion(_) => {
+                crate::fluent_generated::middle_deprecated_in_version
+            }
+        }
+    }
+}
+
+fn deprecated_since_kind(is_in_effect: bool, since: DeprecatedSince) -> DeprecatedSinceKind {
+    if is_in_effect {
+        DeprecatedSinceKind::InEffect
     } else {
         match since {
-            DeprecatedSince::RustcVersion(version) => format!(
-                "use of {kind} `{path}` that will be deprecated in future version {version}"
-            ),
-            DeprecatedSince::Future => {
-                format!("use of {kind} `{path}` that will be deprecated in a future Rust version")
+            DeprecatedSince::RustcVersion(version) => {
+                DeprecatedSinceKind::InVersion(version.to_string())
             }
+            DeprecatedSince::Future => DeprecatedSinceKind::InFuture,
             DeprecatedSince::NonStandard(_)
             | DeprecatedSince::Unspecified
             | DeprecatedSince::Err => {
                 unreachable!("this deprecation is always in effect; {since:?}")
             }
         }
-    };
-
-    match note {
-        Some(reason) => format!("{message}: {reason}"),
-        None => message,
     }
 }
 
-pub fn deprecation_message_and_lint(
-    depr: &Deprecation,
-    kind: &str,
-    path: &str,
-) -> (String, &'static Lint) {
-    let is_in_effect = depr.is_in_effect();
-    (
-        deprecation_message(is_in_effect, depr.since, depr.note, kind, path),
-        deprecation_lint(is_in_effect),
-    )
-}
-
-pub fn early_report_deprecation(
+pub fn early_report_macro_deprecation(
     lint_buffer: &mut LintBuffer,
-    message: String,
-    suggestion: Option<Symbol>,
-    lint: &'static Lint,
+    depr: &Deprecation,
     span: Span,
     node_id: NodeId,
+    path: String,
 ) {
     if span.in_derive_expansion() {
         return;
     }
 
-    let diag = BuiltinLintDiag::DeprecatedMacro(suggestion, span);
-    lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag);
+    let is_in_effect = depr.is_in_effect();
+    let diag = BuiltinLintDiag::DeprecatedMacro {
+        suggestion: depr.suggestion,
+        suggestion_span: span,
+        note: depr.note,
+        path,
+        since_kind: deprecated_since_kind(is_in_effect, depr.since.clone()),
+    };
+    lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag);
 }
 
 fn late_report_deprecation(
     tcx: TyCtxt<'_>,
-    message: String,
-    suggestion: Option<Symbol>,
-    lint: &'static Lint,
+    depr: &Deprecation,
     span: Span,
     method_span: Option<Span>,
     hir_id: HirId,
@@ -217,13 +234,26 @@ fn late_report_deprecation(
     if span.in_derive_expansion() {
         return;
     }
+
+    let def_path = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+    let def_kind = tcx.def_descr(def_id);
+    let is_in_effect = depr.is_in_effect();
+
     let method_span = method_span.unwrap_or(span);
-    tcx.node_span_lint(lint, hir_id, method_span, message, |diag| {
-        if let hir::Node::Expr(_) = tcx.hir_node(hir_id) {
-            let kind = tcx.def_descr(def_id);
-            deprecation_suggestion(diag, kind, suggestion, method_span);
-        }
-    });
+    let suggestion =
+        if let hir::Node::Expr(_) = tcx.hir_node(hir_id) { depr.suggestion } else { None };
+    let diag = Deprecated {
+        sub: suggestion.map(|suggestion| DeprecationSuggestion {
+            span: method_span,
+            kind: def_kind.to_owned(),
+            suggestion,
+        }),
+        kind: def_kind.to_owned(),
+        path: def_path,
+        note: depr.note,
+        since_kind: deprecated_since_kind(is_in_effect, depr.since),
+    };
+    tcx.emit_node_span_lint(deprecation_lint(is_in_effect), hir_id, method_span, diag);
 }
 
 /// Result of `TyCtxt::eval_stability`.
@@ -352,28 +382,9 @@ impl<'tcx> TyCtxt<'tcx> {
                     // Calculating message for lint involves calling `self.def_path_str`.
                     // Which by default to calculate visible path will invoke expensive `visible_parent_map` query.
                     // So we skip message calculation altogether, if lint is allowed.
-                    let is_in_effect = depr_attr.is_in_effect();
-                    let lint = deprecation_lint(is_in_effect);
+                    let lint = deprecation_lint(depr_attr.is_in_effect());
                     if self.lint_level_at_node(lint, id).0 != Level::Allow {
-                        let def_path = with_no_trimmed_paths!(self.def_path_str(def_id));
-                        let def_kind = self.def_descr(def_id);
-
-                        late_report_deprecation(
-                            self,
-                            deprecation_message(
-                                is_in_effect,
-                                depr_attr.since,
-                                depr_attr.note,
-                                def_kind,
-                                &def_path,
-                            ),
-                            depr_attr.suggestion,
-                            lint,
-                            span,
-                            method_span,
-                            id,
-                            def_id,
-                        );
+                        late_report_deprecation(self, depr_attr, span, method_span, id, def_id);
                     }
                 }
             };
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 7f9a5a366d7..4155c61e96d 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -181,8 +181,8 @@ impl Debug for CodeRegion {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
 pub enum Op {
     Subtract,
     Add,
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 5aaa1c30cad..7e8598b49df 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -971,9 +971,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
             }
             BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
-            CheckedBinaryOp(ref op, box (ref a, ref b)) => {
-                write!(fmt, "Checked{op:?}({a:?}, {b:?})")
-            }
             UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
             Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
             NullaryOp(ref op, ref t) => {
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 375f1f15a39..4d9a931d697 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -438,7 +438,6 @@ impl<'tcx> Rvalue<'tcx> {
                 _,
             )
             | Rvalue::BinaryOp(_, _)
-            | Rvalue::CheckedBinaryOp(_, _)
             | Rvalue::NullaryOp(_, _)
             | Rvalue::UnaryOp(_, _)
             | Rvalue::Discriminant(_)
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index e124b478f41..2b28496faec 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1295,18 +1295,12 @@ pub enum Rvalue<'tcx> {
     ///   truncated as needed.
     /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
     ///   types and return a value of that type.
+    /// * The `FooWithOverflow` are like the `Foo`, but returning `(T, bool)` instead of just `T`,
+    ///   where the `bool` is true if the result is not equal to the infinite-precision result.
     /// * The remaining operations accept signed integers, unsigned integers, or floats with
     ///   matching types and return a value of that type.
     BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
 
-    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
-    ///
-    /// For addition, subtraction, and multiplication on integers the error condition is set when
-    /// the infinite precision result would not be equal to the actual result.
-    ///
-    /// Other combinations of types and operators are unsupported.
-    CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
-
     /// Computes a value as described by the operation.
     NullaryOp(NullOp<'tcx>, Ty<'tcx>),
 
@@ -1449,14 +1443,23 @@ pub enum BinOp {
     Add,
     /// Like `Add`, but with UB on overflow.  (Integers only.)
     AddUnchecked,
+    /// Like `Add`, but returns `(T, bool)` of both the wrapped result
+    /// and a bool indicating whether it overflowed.
+    AddWithOverflow,
     /// The `-` operator (subtraction)
     Sub,
     /// Like `Sub`, but with UB on overflow.  (Integers only.)
     SubUnchecked,
+    /// Like `Sub`, but returns `(T, bool)` of both the wrapped result
+    /// and a bool indicating whether it overflowed.
+    SubWithOverflow,
     /// The `*` operator (multiplication)
     Mul,
     /// Like `Mul`, but with UB on overflow.  (Integers only.)
     MulUnchecked,
+    /// Like `Mul`, but returns `(T, bool)` of both the wrapped result
+    /// and a bool indicating whether it overflowed.
+    MulWithOverflow,
     /// The `/` operator (division)
     ///
     /// For integer types, division by zero is UB, as is `MIN / -1` for signed.
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 4994679ad5d..e1ae2e08666 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -179,12 +179,6 @@ impl<'tcx> Rvalue<'tcx> {
                 let rhs_ty = rhs.ty(local_decls, tcx);
                 op.ty(tcx, lhs_ty, rhs_ty)
             }
-            Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
-                let lhs_ty = lhs.ty(local_decls, tcx);
-                let rhs_ty = rhs.ty(local_decls, tcx);
-                let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                Ty::new_tup(tcx, &[ty, tcx.types.bool])
-            }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
@@ -263,6 +257,11 @@ impl<'tcx> BinOp {
                 assert_eq!(lhs_ty, rhs_ty);
                 lhs_ty
             }
+            &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => {
+                // these should be integers of the same size.
+                assert_eq!(lhs_ty, rhs_ty);
+                Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool])
+            }
             &BinOp::Shl
             | &BinOp::ShlUnchecked
             | &BinOp::Shr
@@ -315,6 +314,9 @@ impl BinOp {
             BinOp::Le => hir::BinOpKind::Le,
             BinOp::Ge => hir::BinOpKind::Ge,
             BinOp::Cmp
+            | BinOp::AddWithOverflow
+            | BinOp::SubWithOverflow
+            | BinOp::MulWithOverflow
             | BinOp::AddUnchecked
             | BinOp::SubUnchecked
             | BinOp::MulUnchecked
@@ -325,4 +327,24 @@ impl BinOp {
             }
         }
     }
+
+    /// If this is a `FooWithOverflow`, return `Some(Foo)`.
+    pub fn overflowing_to_wrapping(self) -> Option<BinOp> {
+        Some(match self {
+            BinOp::AddWithOverflow => BinOp::Add,
+            BinOp::SubWithOverflow => BinOp::Sub,
+            BinOp::MulWithOverflow => BinOp::Mul,
+            _ => return None,
+        })
+    }
+
+    /// If this is a `Foo`, return `Some(FooWithOverflow)`.
+    pub fn wrapping_to_overflowing(self) -> Option<BinOp> {
+        Some(match self {
+            BinOp::Add => BinOp::AddWithOverflow,
+            BinOp::Sub => BinOp::SubWithOverflow,
+            BinOp::Mul => BinOp::MulWithOverflow,
+            _ => return None,
+        })
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index d97abc3f190..8901fd42d93 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -696,8 +696,7 @@ macro_rules! make_mir_visitor {
                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                     }
 
-                    Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
-                    | Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => {
+                    Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) => {
                         self.visit_operand(lhs, location);
                         self.visit_operand(rhs, location);
                     }
diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs
index 03ce7cf98cf..2ff4ade21d0 100644
--- a/compiler/rustc_middle/src/traits/solve/cache.rs
+++ b/compiler/rustc_middle/src/traits/solve/cache.rs
@@ -14,11 +14,11 @@ pub struct EvaluationCache<'tcx> {
     map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
 }
 
-#[derive(PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 pub struct CacheData<'tcx> {
     pub result: QueryResult<'tcx>,
     pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
-    pub reached_depth: usize,
+    pub additional_depth: usize,
     pub encountered_overflow: bool,
 }
 
@@ -29,7 +29,7 @@ impl<'tcx> EvaluationCache<'tcx> {
         tcx: TyCtxt<'tcx>,
         key: CanonicalInput<'tcx>,
         proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
-        reached_depth: usize,
+        additional_depth: usize,
         encountered_overflow: bool,
         cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
         dep_node: DepNodeIndex,
@@ -40,17 +40,17 @@ impl<'tcx> EvaluationCache<'tcx> {
         let data = WithDepNode::new(dep_node, QueryData { result, proof_tree });
         entry.cycle_participants.extend(cycle_participants);
         if encountered_overflow {
-            entry.with_overflow.insert(reached_depth, data);
+            entry.with_overflow.insert(additional_depth, data);
         } else {
-            entry.success = Some(Success { data, reached_depth });
+            entry.success = Some(Success { data, additional_depth });
         }
 
         if cfg!(debug_assertions) {
             drop(map);
-            if Some(CacheData { result, proof_tree, reached_depth, encountered_overflow })
-                != self.get(tcx, key, |_| false, Limit(reached_depth))
-            {
-                bug!("unable to retrieve inserted element from cache: {key:?}");
+            let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow };
+            let actual = self.get(tcx, key, [], Limit(additional_depth));
+            if !actual.as_ref().is_some_and(|actual| expected == *actual) {
+                bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}");
             }
         }
     }
@@ -63,23 +63,25 @@ impl<'tcx> EvaluationCache<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         key: CanonicalInput<'tcx>,
-        cycle_participant_in_stack: impl FnOnce(&FxHashSet<CanonicalInput<'tcx>>) -> bool,
+        stack_entries: impl IntoIterator<Item = CanonicalInput<'tcx>>,
         available_depth: Limit,
     ) -> Option<CacheData<'tcx>> {
         let map = self.map.borrow();
         let entry = map.get(&key)?;
 
-        if cycle_participant_in_stack(&entry.cycle_participants) {
-            return None;
+        for stack_entry in stack_entries {
+            if entry.cycle_participants.contains(&stack_entry) {
+                return None;
+            }
         }
 
         if let Some(ref success) = entry.success {
-            if available_depth.value_within_limit(success.reached_depth) {
+            if available_depth.value_within_limit(success.additional_depth) {
                 let QueryData { result, proof_tree } = success.data.get(tcx);
                 return Some(CacheData {
                     result,
                     proof_tree,
-                    reached_depth: success.reached_depth,
+                    additional_depth: success.additional_depth,
                     encountered_overflow: false,
                 });
             }
@@ -90,7 +92,7 @@ impl<'tcx> EvaluationCache<'tcx> {
             CacheData {
                 result,
                 proof_tree,
-                reached_depth: available_depth.0,
+                additional_depth: available_depth.0,
                 encountered_overflow: true,
             }
         })
@@ -99,7 +101,7 @@ impl<'tcx> EvaluationCache<'tcx> {
 
 struct Success<'tcx> {
     data: WithDepNode<QueryData<'tcx>>,
-    reached_depth: usize,
+    additional_depth: usize,
 }
 
 #[derive(Clone, Copy)]
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 9dc30447f0e..f7cc055be11 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -175,6 +175,14 @@ impl<'tcx> Const<'tcx> {
 }
 
 impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
+    fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Self {
+        Const::new_infer(tcx, infer, ty)
+    }
+
+    fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self {
+        Const::new_var(tcx, vid, ty)
+    }
+
     fn new_anon_bound(
         tcx: TyCtxt<'tcx>,
         debruijn: ty::DebruijnIndex,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 69681930be6..8185c99c2fd 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -134,7 +134,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type EarlyParamRegion = ty::EarlyParamRegion;
     type LateParamRegion = ty::LateParamRegion;
     type BoundRegion = ty::BoundRegion;
-    type InferRegion = ty::RegionVid;
     type PlaceholderRegion = ty::PlaceholderRegion;
 
     type ParamEnv = ty::ParamEnv<'tcx>;
@@ -233,6 +232,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     fn parent(self, def_id: Self::DefId) -> Self::DefId {
         self.parent(def_id)
     }
+
+    fn recursion_limit(self) -> usize {
+        self.recursion_limit().0
+    }
 }
 
 impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 38b2987399a..3d263e62de6 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -27,6 +27,7 @@ use std::ops::Deref;
 use std::ptr::NonNull;
 
 pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
+pub type TermKind<'tcx> = rustc_type_ir::TermKind<TyCtxt<'tcx>>;
 
 /// An entity in the Rust type system, which can be one of
 /// several kinds (types, lifetimes, and consts).
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 04655c5d20b..cfaca05c2f0 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -391,6 +391,14 @@ impl<'tcx> Generics {
         }
         false
     }
+
+    pub fn is_empty(&'tcx self) -> bool {
+        self.count() == 0
+    }
+
+    pub fn is_own_empty(&'tcx self) -> bool {
+        self.own_params.is_empty()
+    }
 }
 
 /// Bounds on generics.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ce63fc20ddb..f27409894fa 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -28,7 +28,7 @@ use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::util::Discr;
 pub use adt::*;
 pub use assoc::*;
-pub use generic_args::{GenericArgKind, *};
+pub use generic_args::{GenericArgKind, TermKind, *};
 pub use generics::*;
 pub use intrinsic::IntrinsicDef;
 use rustc_ast as ast;
@@ -48,7 +48,8 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
 use rustc_index::IndexVec;
 use rustc_macros::{
-    Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
+    extension, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
+    TypeVisitable,
 };
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::{Decodable, Encodable};
@@ -521,6 +522,14 @@ pub struct Term<'tcx> {
     marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
 }
 
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> {
+    type Kind = TermKind<'tcx>;
+
+    fn kind(self) -> Self::Kind {
+        self.unpack()
+    }
+}
+
 #[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSend for Term<'tcx> where
     &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSend
@@ -536,14 +545,10 @@ unsafe impl<'tcx> Sync for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Sync
 
 impl Debug for Term<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let data = if let Some(ty) = self.ty() {
-            format!("Term::Ty({ty:?})")
-        } else if let Some(ct) = self.ct() {
-            format!("Term::Ct({ct:?})")
-        } else {
-            unreachable!()
-        };
-        f.write_str(&data)
+        match self.unpack() {
+            TermKind::Ty(ty) => write!(f, "Term::Ty({ty:?})"),
+            TermKind::Const(ct) => write!(f, "Term::Const({ct:?})"),
+        }
     }
 }
 
@@ -570,13 +575,19 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Term<'tcx> {
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        Ok(self.unpack().try_fold_with(folder)?.pack())
+        match self.unpack() {
+            ty::TermKind::Ty(ty) => ty.try_fold_with(folder).map(Into::into),
+            ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
+        }
     }
 }
 
 impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Term<'tcx> {
     fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
-        self.unpack().visit_with(visitor)
+        match self.unpack() {
+            ty::TermKind::Ty(ty) => ty.visit_with(visitor),
+            ty::TermKind::Const(ct) => ct.visit_with(visitor),
+        }
     }
 }
 
@@ -654,13 +665,7 @@ const TAG_MASK: usize = 0b11;
 const TYPE_TAG: usize = 0b00;
 const CONST_TAG: usize = 0b01;
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub enum TermKind<'tcx> {
-    Ty(Ty<'tcx>),
-    Const(Const<'tcx>),
-}
-
+#[extension(pub trait TermKindPackExt<'tcx>)]
 impl<'tcx> TermKind<'tcx> {
     #[inline]
     fn pack(self) -> Term<'tcx> {
@@ -1809,6 +1814,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.get_attrs(did, attr).next().is_some()
     }
 
+    /// Determines whether an item is annotated with a multi-segement attribute
+    pub fn has_attrs_with_path(self, did: impl Into<DefId>, attrs: &[Symbol]) -> bool {
+        self.get_attrs_by_path(did.into(), attrs).next().is_some()
+    }
+
     /// Returns `true` if this is an `auto trait`.
     pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 644fca7c5fe..be91249a25f 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -37,7 +37,11 @@ pub struct Predicate<'tcx>(
     pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
 );
 
-impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx> {}
+impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx> {
+    fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool {
+        self.is_coinductive(interner)
+    }
+}
 
 impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> {
     fn flags(&self) -> TypeFlags {
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index e7589737d64..dc77f59f3d0 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -160,7 +160,7 @@ pub trait Printer<'tcx>: Sized {
                         // If we have any generic arguments to print, we do that
                         // on top of the same path, but without its own generics.
                         _ => {
-                            if !generics.own_params.is_empty() && args.len() >= generics.count() {
+                            if !generics.is_own_empty() && args.len() >= generics.count() {
                                 let args = generics.own_args_no_defaults(self.tcx(), args);
                                 return self.path_generic_args(
                                     |cx| cx.print_def_path(def_id, parent_args),
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 7540f0ab83f..551e2ea2295 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -1,13 +1,12 @@
-use polonius_engine::Atom;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::MultiSpan;
 use rustc_hir::def_id::DefId;
-use rustc_index::Idx;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::symbol::sym;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use rustc_type_ir::RegionKind as IrRegionKind;
+pub use rustc_type_ir::RegionVid;
 use std::ops::Deref;
 
 use crate::ty::{self, BoundVar, TyCtxt, TypeFlags};
@@ -348,21 +347,6 @@ impl std::fmt::Debug for EarlyParamRegion {
     }
 }
 
-rustc_index::newtype_index! {
-    /// A **region** (lifetime) **v**ariable **ID**.
-    #[derive(HashStable)]
-    #[encodable]
-    #[orderable]
-    #[debug_format = "'?{}"]
-    pub struct RegionVid {}
-}
-
-impl Atom for RegionVid {
-    fn index(self) -> usize {
-        Idx::index(self)
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
 #[derive(HashStable)]
 /// The parameter representation of late-bound function parameters, "some region
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7d24824d568..81d92a2a448 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -259,18 +259,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
     }
 }
 
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        match this.infcx.universe_of_lt(*this.data) {
-            Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
-            None => write!(f, "{:?}", this.data),
-        }
-    }
-}
-
 impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -383,13 +371,10 @@ impl<'tcx, T: Lift<TyCtxt<'tcx>>> Lift<TyCtxt<'tcx>> for Option<T> {
 impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for Term<'a> {
     type Lifted = ty::Term<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(
-            match self.unpack() {
-                TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?),
-                TermKind::Const(c) => TermKind::Const(tcx.lift(c)?),
-            }
-            .pack(),
-        )
+        match self.unpack() {
+            TermKind::Ty(ty) => tcx.lift(ty).map(Into::into),
+            TermKind::Const(c) => tcx.lift(c).map(Into::into),
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 7c41c5f512e..2d9d178449e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1611,6 +1611,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         tcx.types.bool
     }
 
+    fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self {
+        Ty::new_infer(tcx, infer)
+    }
+
+    fn new_var(tcx: TyCtxt<'tcx>, vid: ty::TyVid) -> Self {
+        Ty::new_var(tcx, vid)
+    }
+
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
     }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index c5b3de17bcb..cf1cbb93410 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -39,11 +39,16 @@ pub struct TraitDef {
     /// also have already switched to the new trait solver.
     pub is_coinductive: bool,
 
-    /// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]`
+    /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(array)]`
     /// attribute, indicating that editions before 2021 should not consider this trait
     /// during method dispatch if the receiver is an array.
     pub skip_array_during_method_dispatch: bool,
 
+    /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(boxed_slice)]`
+    /// attribute, indicating that editions before 2024 should not consider this trait
+    /// during method dispatch if the receiver is a boxed slice.
+    pub skip_boxed_slice_during_method_dispatch: bool,
+
     /// Used to determine whether the standard library is allowed to specialize
     /// on this trait.
     pub specialization_kind: TraitSpecializationKind,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index c669d3fd623..6f8cfc3af44 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -195,9 +195,15 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             },
             @call(mir_checked, args) => {
                 parse_by_kind!(self, args[0], _, "binary op",
-                    ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
-                        *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
-                    )),
+                    ExprKind::Binary { op, lhs, rhs } => {
+                        if let Some(op_with_overflow) = op.wrapping_to_overflowing() {
+                            Ok(Rvalue::BinaryOp(
+                                op_with_overflow, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
+                            ))
+                        } else {
+                            Err(self.expr_error(expr_id, "No WithOverflow form of this operator"))
+                        }
+                    },
                 )
             },
             @call(mir_offset, args) => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 0b2248d049a..60a2827a3e2 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -568,11 +568,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let result_tup = Ty::new_tup(self.tcx, &[ty, bool_ty]);
                 let result_value = self.temp(result_tup, span);
 
+                let op_with_overflow = op.wrapping_to_overflowing().unwrap();
+
                 self.cfg.push_assign(
                     block,
                     source_info,
                     result_value,
-                    Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
+                    Rvalue::BinaryOp(op_with_overflow, Box::new((lhs.to_copy(), rhs.to_copy()))),
                 );
                 let val_fld = FieldIdx::ZERO;
                 let of_fld = FieldIdx::new(1);
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index bdc70de58e8..706bb796349 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -109,7 +109,6 @@ where
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
             | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..)
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 6ae7df79d30..521ecb1b9a5 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -420,8 +420,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
             | Rvalue::Cast(_, ref operand, _)
             | Rvalue::ShallowInitBox(ref operand, _)
             | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
-            Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs))
-            | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
+            Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
                 self.gather_operand(lhs);
                 self.gather_operand(rhs);
             }
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 807bef07411..1e5322dd99b 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -184,7 +184,6 @@ pub trait ValueAnalysis<'tcx> {
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
             | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..)
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index b98554ec00f..b5968517d77 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -11,7 +11,7 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage
 
 /// The coverage counter or counter expression associated with a particular
 /// BCB node or BCB edge.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub(super) enum BcbCounter {
     Counter { id: CounterId },
     Expression { id: ExpressionId },
@@ -35,6 +35,13 @@ impl Debug for BcbCounter {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+struct BcbExpression {
+    lhs: BcbCounter,
+    op: Op,
+    rhs: BcbCounter,
+}
+
 #[derive(Debug)]
 pub(super) enum CounterIncrementSite {
     Node { bcb: BasicCoverageBlock },
@@ -56,9 +63,13 @@ pub(super) struct CoverageCounters {
     /// We currently don't iterate over this map, but if we do in the future,
     /// switch it back to `FxIndexMap` to avoid query stability hazards.
     bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
+
     /// Table of expression data, associating each expression ID with its
     /// corresponding operator (+ or -) and its LHS/RHS operands.
-    expressions: IndexVec<ExpressionId, Expression>,
+    expressions: IndexVec<ExpressionId, BcbExpression>,
+    /// Remember expressions that have already been created (or simplified),
+    /// so that we don't create unnecessary duplicates.
+    expressions_memo: FxHashMap<BcbExpression, BcbCounter>,
 }
 
 impl CoverageCounters {
@@ -76,6 +87,7 @@ impl CoverageCounters {
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
             bcb_edge_counters: FxHashMap::default(),
             expressions: IndexVec::new(),
+            expressions_memo: FxHashMap::default(),
         };
 
         MakeBcbCounters::new(&mut this, basic_coverage_blocks)
@@ -90,8 +102,57 @@ impl CoverageCounters {
     }
 
     fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
-        let expression = Expression { lhs: lhs.as_term(), op, rhs: rhs.as_term() };
-        let id = self.expressions.push(expression);
+        let new_expr = BcbExpression { lhs, op, rhs };
+        *self
+            .expressions_memo
+            .entry(new_expr)
+            .or_insert_with(|| Self::make_expression_inner(&mut self.expressions, new_expr))
+    }
+
+    /// This is an associated function so that we can call it while borrowing
+    /// `&mut self.expressions_memo`.
+    fn make_expression_inner(
+        expressions: &mut IndexVec<ExpressionId, BcbExpression>,
+        new_expr: BcbExpression,
+    ) -> BcbCounter {
+        // Simplify expressions using basic algebra.
+        //
+        // Some of these cases might not actually occur in practice, depending
+        // on the details of how the instrumentor builds expressions.
+        let BcbExpression { lhs, op, rhs } = new_expr;
+
+        if let BcbCounter::Expression { id } = lhs {
+            let lhs_expr = &expressions[id];
+
+            // Simplify `(a - b) + b` to `a`.
+            if lhs_expr.op == Op::Subtract && op == Op::Add && lhs_expr.rhs == rhs {
+                return lhs_expr.lhs;
+            }
+            // Simplify `(a + b) - b` to `a`.
+            if lhs_expr.op == Op::Add && op == Op::Subtract && lhs_expr.rhs == rhs {
+                return lhs_expr.lhs;
+            }
+            // Simplify `(a + b) - a` to `b`.
+            if lhs_expr.op == Op::Add && op == Op::Subtract && lhs_expr.lhs == rhs {
+                return lhs_expr.rhs;
+            }
+        }
+
+        if let BcbCounter::Expression { id } = rhs {
+            let rhs_expr = &expressions[id];
+
+            // Simplify `a + (b - a)` to `b`.
+            if op == Op::Add && rhs_expr.op == Op::Subtract && lhs == rhs_expr.rhs {
+                return rhs_expr.lhs;
+            }
+            // Simplify `a - (a - b)` to `b`.
+            if op == Op::Subtract && rhs_expr.op == Op::Subtract && lhs == rhs_expr.lhs {
+                return rhs_expr.rhs;
+            }
+        }
+
+        // Simplification failed, so actually create the new expression.
+        let id = expressions.push(new_expr);
         BcbCounter::Expression { id }
     }
 
@@ -166,7 +227,21 @@ impl CoverageCounters {
     }
 
     pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
-        self.expressions
+        let old_len = self.expressions.len();
+        let expressions = self
+            .expressions
+            .into_iter()
+            .map(|BcbExpression { lhs, op, rhs }| Expression {
+                lhs: lhs.as_term(),
+                op,
+                rhs: rhs.as_term(),
+            })
+            .collect::<IndexVec<ExpressionId, _>>();
+
+        // Expression IDs are indexes into this vector, so make sure we didn't
+        // accidentally invalidate them by changing its length.
+        assert_eq!(old_len, expressions.len());
+        expressions
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index a42d64f86be..3d24a56cdd7 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -165,7 +165,9 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                     }
                 }
             }
-            Rvalue::CheckedBinaryOp(op, box (left, right)) => {
+            Rvalue::BinaryOp(overflowing_op, box (left, right))
+                if let Some(op) = overflowing_op.overflowing_to_wrapping() =>
+            {
                 // Flood everything now, so we can use `insert_value_idx` directly later.
                 state.flood(target.as_ref(), self.map());
 
@@ -175,7 +177,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into()));
 
                 if value_target.is_some() || overflow_target.is_some() {
-                    let (val, overflow) = self.binary_op(state, *op, left, right);
+                    let (val, overflow) = self.binary_op(state, op, left, right);
 
                     if let Some(value_target) = value_target {
                         // We have flooded `target` earlier.
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 1bc383fccc7..b1016c0867c 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -564,7 +564,7 @@ impl WriteInfo {
                     | Rvalue::ShallowInitBox(op, _) => {
                         self.add_operand(op);
                     }
-                    Rvalue::BinaryOp(_, ops) | Rvalue::CheckedBinaryOp(_, ops) => {
+                    Rvalue::BinaryOp(_, ops) => {
                         for op in [&ops.0, &ops.1] {
                             self.add_operand(op);
                         }
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 123166a764d..1f3e407180b 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -831,23 +831,18 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 // on both operands for side effect.
                 let lhs = lhs?;
                 let rhs = rhs?;
-                if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
-                    return Some(value);
-                }
-                Value::BinaryOp(op, lhs, rhs)
-            }
-            Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
-                let ty = lhs.ty(self.local_decls, self.tcx);
-                let lhs = self.simplify_operand(lhs, location);
-                let rhs = self.simplify_operand(rhs, location);
-                // Only short-circuit options after we called `simplify_operand`
-                // on both operands for side effect.
-                let lhs = lhs?;
-                let rhs = rhs?;
-                if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
-                    return Some(value);
+
+                if let Some(op) = op.overflowing_to_wrapping() {
+                    if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
+                        return Some(value);
+                    }
+                    Value::CheckedBinaryOp(op, lhs, rhs)
+                } else {
+                    if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
+                        return Some(value);
+                    }
+                    Value::BinaryOp(op, lhs, rhs)
                 }
-                Value::CheckedBinaryOp(op, lhs, rhs)
             }
             Rvalue::UnaryOp(op, ref mut arg) => {
                 let arg = self.simplify_operand(arg, location)?;
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index d0a5a6cada8..38fc37a3a31 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -399,16 +399,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             }
             Rvalue::BinaryOp(op, box (left, right)) => {
                 trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
-                self.check_binary_op(*op, left, right, location)?;
-            }
-            Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                trace!(
-                    "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})",
-                    op,
-                    left,
-                    right
-                );
-                self.check_binary_op(*op, left, right, location)?;
+                let op = op.overflowing_to_wrapping().unwrap_or(*op);
+                self.check_binary_op(op, left, right, location)?;
             }
 
             // Do not try creating references (#67862)
@@ -555,24 +547,18 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 let right = self.eval_operand(right)?;
                 let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?;
 
-                let val =
-                    self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?;
-                val.into()
-            }
-
-            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
-                let left = self.eval_operand(left)?;
-                let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?;
-
-                let right = self.eval_operand(right)?;
-                let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?;
-
-                let (val, overflowed) =
-                    self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
-                let overflowed = ImmTy::from_bool(overflowed, self.tcx);
-                Value::Aggregate {
-                    variant: VariantIdx::ZERO,
-                    fields: [Value::from(val), overflowed.into()].into_iter().collect(),
+                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                    let (val, overflowed) =
+                        self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
+                    let overflowed = ImmTy::from_bool(overflowed, self.tcx);
+                    Value::Aggregate {
+                        variant: VariantIdx::ZERO,
+                        fields: [Value::from(val), overflowed.into()].into_iter().collect(),
+                    }
+                } else {
+                    let val =
+                        self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?;
+                    val.into()
                 }
             }
 
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 43d8c45bb2d..221301b2ceb 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -140,16 +140,16 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                                 rhs = args.next().unwrap();
                             }
                             let bin_op = match intrinsic.name {
-                                sym::add_with_overflow => BinOp::Add,
-                                sym::sub_with_overflow => BinOp::Sub,
-                                sym::mul_with_overflow => BinOp::Mul,
+                                sym::add_with_overflow => BinOp::AddWithOverflow,
+                                sym::sub_with_overflow => BinOp::SubWithOverflow,
+                                sym::mul_with_overflow => BinOp::MulWithOverflow,
                                 _ => bug!("unexpected intrinsic"),
                             };
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
                                     *destination,
-                                    Rvalue::CheckedBinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
+                                    Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
                                 ))),
                             });
                             terminator.kind = TerminatorKind::Goto { target };
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index b3116c002d3..34aa31baab7 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -470,7 +470,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 self.validate_operand(operand)?;
             }
 
-            Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
+            Rvalue::BinaryOp(op, box (lhs, rhs)) => {
                 let op = *op;
                 let lhs_ty = lhs.ty(self.body, self.tcx);
 
@@ -539,10 +539,13 @@ impl<'tcx> Validator<'_, 'tcx> {
                     | BinOp::Offset
                     | BinOp::Add
                     | BinOp::AddUnchecked
+                    | BinOp::AddWithOverflow
                     | BinOp::Sub
                     | BinOp::SubUnchecked
+                    | BinOp::SubWithOverflow
                     | BinOp::Mul
                     | BinOp::MulUnchecked
+                    | BinOp::MulWithOverflow
                     | BinOp::BitXor
                     | BinOp::BitAnd
                     | BinOp::BitOr
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index dd1065590b3..4b435649216 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1429,7 +1429,7 @@ impl<'v> RootCollector<'_, 'v> {
         match self.tcx.def_kind(id.owner_id) {
             DefKind::Enum | DefKind::Struct | DefKind::Union => {
                 if self.strategy == MonoItemCollectionStrategy::Eager
-                    && self.tcx.generics_of(id.owner_id).count() == 0
+                    && self.tcx.generics_of(id.owner_id).is_empty()
                 {
                     debug!("RootCollector: ADT drop-glue for `{id:?}`",);
 
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 6487169d173..14ebe27ac23 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -51,7 +51,7 @@ fn unused_generic_params<'tcx>(
     debug!(?generics);
 
     // Exit early when there are no parameters to be unused.
-    if generics.count() == 0 {
+    if generics.is_empty() {
         return UnusedGenericParams::new_all_used();
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 755f5cfa5a3..696639e9c1b 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -268,7 +268,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             ty::ReVar(vid) => {
                 assert_eq!(
                     self.infcx.opportunistic_resolve_lt_var(vid),
-                    None,
+                    r,
                     "region vid should have been resolved fully before canonicalization"
                 );
                 match self.canonicalize_mode {
@@ -302,13 +302,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             ty::Infer(i) => match i {
                 ty::TyVar(vid) => {
                     assert_eq!(
-                        self.infcx.root_ty_var(vid),
-                        vid,
-                        "ty vid should have been resolved fully before canonicalization"
-                    );
-                    assert_eq!(
-                        self.infcx.probe_ty_var(vid),
-                        None,
+                        self.infcx.opportunistic_resolve_ty_var(vid),
+                        t,
                         "ty vid should have been resolved fully before canonicalization"
                     );
 
@@ -318,10 +313,24 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
                             .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")),
                     ))
                 }
-                ty::IntVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Int),
-                ty::FloatVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Float),
+                ty::IntVar(vid) => {
+                    assert_eq!(
+                        self.infcx.opportunistic_resolve_int_var(vid),
+                        t,
+                        "ty vid should have been resolved fully before canonicalization"
+                    );
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
+                }
+                ty::FloatVar(vid) => {
+                    assert_eq!(
+                        self.infcx.opportunistic_resolve_float_var(vid),
+                        t,
+                        "ty vid should have been resolved fully before canonicalization"
+                    );
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
+                }
                 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
-                    todo!()
+                    panic!("fresh vars not expected in canonicalization")
                 }
             },
             ty::Placeholder(placeholder) => match self.canonicalize_mode {
@@ -387,14 +396,11 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
         let kind = match c.kind() {
             ty::ConstKind::Infer(i) => match i {
                 ty::InferConst::Var(vid) => {
+                    // We compare `kind`s here because we've folded the `ty` with `RegionsToStatic`
+                    // so we'll get a mismatch in types if it actually changed any regions.
                     assert_eq!(
-                        self.infcx.root_ct_var(vid),
-                        vid,
-                        "region vid should have been resolved fully before canonicalization"
-                    );
-                    assert_eq!(
-                        self.infcx.probe_ct_var(vid),
-                        None,
+                        self.infcx.opportunistic_resolve_ct_var(vid, ty).kind(),
+                        c.kind(),
                         "region vid should have been resolved fully before canonicalization"
                     );
                     CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index 4202dc39fb2..b913a05095c 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -1,2 +1,3 @@
 pub mod canonicalizer;
+pub mod resolve;
 pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
new file mode 100644
index 00000000000..1333b4aa7d8
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -0,0 +1,83 @@
+use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::visit::TypeVisitableExt;
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
+
+///////////////////////////////////////////////////////////////////////////
+// EAGER RESOLUTION
+
+/// Resolves ty, region, and const vars to their inferred values or their root vars.
+pub struct EagerResolver<
+    'a,
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner = <Infcx as InferCtxtLike>::Interner,
+> {
+    infcx: &'a Infcx,
+}
+
+impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> {
+    pub fn new(infcx: &'a Infcx) -> Self {
+        EagerResolver { infcx }
+    }
+}
+
+impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> {
+    fn interner(&self) -> I {
+        self.infcx.interner()
+    }
+
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        match t.kind() {
+            ty::Infer(ty::TyVar(vid)) => {
+                let resolved = self.infcx.opportunistic_resolve_ty_var(vid);
+                if t != resolved && resolved.has_infer() {
+                    resolved.fold_with(self)
+                } else {
+                    resolved
+                }
+            }
+            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
+            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
+            _ => {
+                if t.has_infer() {
+                    t.super_fold_with(self)
+                } else {
+                    t
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        match r.kind() {
+            ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid),
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, c: I::Const) -> I::Const {
+        match c.kind() {
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                let ty = c.ty().fold_with(self);
+                let resolved = self.infcx.opportunistic_resolve_ct_var(vid, ty);
+                if c != resolved && resolved.has_infer() {
+                    resolved.fold_with(self)
+                } else {
+                    resolved
+                }
+            }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
+                let bool = Ty::new_bool(self.infcx.interner());
+                debug_assert_eq!(c.ty(), bool);
+                self.infcx.opportunistic_resolve_effect_var(vid, bool)
+            }
+            _ => {
+                if c.has_infer() {
+                    c.super_fold_with(self)
+                } else {
+                    c
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index d2d200a91af..6eb8bed6a8c 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -370,11 +370,10 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
         let content = self.str_from(content_start);
         if contains_text_flow_control_chars(content) {
             let span = self.mk_sp(start, self.pos);
-            self.psess.buffer_lint_with_diagnostic(
+            self.psess.buffer_lint(
                 TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
                 span,
                 ast::CRATE_NODE_ID,
-                "unicode codepoint changing visible direction of text present in comment",
                 BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()),
             );
         }
@@ -723,12 +722,11 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
             self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
         } else {
             // Before Rust 2021, only emit a lint for migration.
-            self.psess.buffer_lint_with_diagnostic(
+            self.psess.buffer_lint(
                 RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
                 prefix_span,
                 ast::CRATE_NODE_ID,
-                format!("prefix `{prefix}` is unknown"),
-                BuiltinLintDiag::ReservedPrefix(prefix_span),
+                BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()),
             );
         }
     }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index d2d21624150..fd3f63a04de 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1913,11 +1913,10 @@ impl<'a> Parser<'a> {
                             | ExprKind::Block(_, None)
                     )
                 {
-                    self.psess.buffer_lint_with_diagnostic(
+                    self.psess.buffer_lint(
                         BREAK_WITH_LABEL_AND_LOOP,
                         lo.to(expr.span),
                         ast::CRATE_NODE_ID,
-                        "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression",
                         BuiltinLintDiag::BreakWithLabelAndLoop(expr.span),
                     );
                 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index a46c104b6d9..f43ddadc2ea 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -58,9 +58,15 @@ impl<'a> Parser<'a> {
         let attrs = self.parse_inner_attributes()?;
 
         let post_attr_lo = self.token.span;
-        let mut items = ThinVec::new();
-        while let Some(item) = self.parse_item(ForceCollect::No)? {
-            self.maybe_consume_incorrect_semicolon(Some(&item));
+        let mut items: ThinVec<P<_>> = ThinVec::new();
+
+        // There shouldn't be any stray semicolons before or after items.
+        // `parse_item` consumes the appropriate semicolons so any leftover is an error.
+        loop {
+            while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons
+            let Some(item) = self.parse_item(ForceCollect::No)? else {
+                break;
+            };
             items.push(item);
         }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index f88edf29dce..b91ef1ae1f3 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -10,6 +10,7 @@ use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::errors::report_lit_error;
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
+use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Span, Symbol};
 
@@ -176,37 +177,26 @@ fn emit_malformed_attribute(
     };
 
     let error_msg = format!("malformed `{name}` attribute input");
-    let mut msg = "attribute must be of the form ".to_owned();
     let mut suggestions = vec![];
-    let mut first = true;
     let inner = if style == ast::AttrStyle::Inner { "!" } else { "" };
     if template.word {
-        first = false;
-        let code = format!("#{inner}[{name}]");
-        msg.push_str(&format!("`{code}`"));
-        suggestions.push(code);
+        suggestions.push(format!("#{inner}[{name}]"));
     }
     if let Some(descr) = template.list {
-        if !first {
-            msg.push_str(" or ");
-        }
-        first = false;
-        let code = format!("#{inner}[{name}({descr})]");
-        msg.push_str(&format!("`{code}`"));
-        suggestions.push(code);
+        suggestions.push(format!("#{inner}[{name}({descr})]"));
     }
     if let Some(descr) = template.name_value_str {
-        if !first {
-            msg.push_str(" or ");
-        }
-        let code = format!("#{inner}[{name} = \"{descr}\"]");
-        msg.push_str(&format!("`{code}`"));
-        suggestions.push(code);
+        suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
     }
-    suggestions.sort();
     if should_warn(name) {
-        psess.buffer_lint(ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg);
+        psess.buffer_lint(
+            ILL_FORMED_ATTRIBUTE_INPUT,
+            span,
+            ast::CRATE_NODE_ID,
+            BuiltinLintDiag::IllFormedAttributeInput { suggestions: suggestions.clone() },
+        );
     } else {
+        suggestions.sort();
         psess
             .dcx
             .struct_span_err(span, error_msg)
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3deefcaa06c..d850644bb45 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -341,7 +341,7 @@ passes_implied_feature_not_exist =
     feature `{$implied_by}` implying `{$feature}` does not exist
 
 passes_incorrect_do_not_recommend_location =
-    `#[do_not_recommend]` can only be placed on trait implementations
+    `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
 
 passes_incorrect_meta_item = expected a quoted string literal
 passes_incorrect_meta_item_suggestion = consider surrounding this with quotes
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index aadbd747313..1924533e280 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -42,12 +42,9 @@ use std::collections::hash_map::Entry;
 
 #[derive(LintDiagnostic)]
 #[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
-pub struct DiagnosticOnUnimplementedOnlyForTraits;
+struct DiagnosticOnUnimplementedOnlyForTraits;
 
-pub(crate) fn target_from_impl_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_item: &hir::ImplItem<'_>,
-) -> Target {
+fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
@@ -99,7 +96,7 @@ struct CheckAttrVisitor<'tcx> {
 }
 
 impl<'tcx> CheckAttrVisitor<'tcx> {
-    pub fn dcx(&self) -> &'tcx DiagCtxt {
+    fn dcx(&self) -> &'tcx DiagCtxt {
         self.tcx.dcx()
     }
 
@@ -116,92 +113,96 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         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),
-                sym::coverage => self.check_coverage(hir_id, attr, span, target),
-                sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
-                sym::marker => self.check_marker(hir_id, attr, span, target),
-                sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs),
-                sym::thread_local => self.check_thread_local(attr, span, target),
-                sym::track_caller => {
+            match attr.path().as_slice() {
+                [sym::diagnostic, sym::do_not_recommend] => {
+                    self.check_do_not_recommend(attr.span, hir_id, target)
+                }
+                [sym::diagnostic, sym::on_unimplemented] => {
+                    self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
+                }
+                [sym::inline] => self.check_inline(hir_id, attr, span, target),
+                [sym::coverage] => self.check_coverage(hir_id, attr, span, target),
+                [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
+                [sym::marker] => self.check_marker(hir_id, attr, span, target),
+                [sym::target_feature] => {
+                    self.check_target_feature(hir_id, attr, span, target, attrs)
+                }
+                [sym::thread_local] => self.check_thread_local(attr, span, target),
+                [sym::track_caller] => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
                 }
-                sym::doc => self.check_doc_attrs(
+                [sym::doc] => self.check_doc_attrs(
                     attr,
                     hir_id,
                     target,
                     &mut specified_inline,
                     &mut doc_aliases,
                 ),
-                sym::no_link => self.check_no_link(hir_id, attr, span, target),
-                sym::export_name => self.check_export_name(hir_id, attr, span, target),
-                sym::rustc_layout_scalar_valid_range_start
-                | sym::rustc_layout_scalar_valid_range_end => {
+                [sym::no_link] => self.check_no_link(hir_id, attr, span, target),
+                [sym::export_name] => self.check_export_name(hir_id, attr, span, target),
+                [sym::rustc_layout_scalar_valid_range_start]
+                | [sym::rustc_layout_scalar_valid_range_end] => {
                     self.check_rustc_layout_scalar_valid_range(attr, span, target)
                 }
-                sym::allow_internal_unstable => {
+                [sym::allow_internal_unstable] => {
                     self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
                 }
-                sym::debugger_visualizer => self.check_debugger_visualizer(attr, target),
-                sym::rustc_allow_const_fn_unstable => {
+                [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target),
+                [sym::rustc_allow_const_fn_unstable] => {
                     self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
                 }
-                sym::rustc_std_internal_symbol => {
+                [sym::rustc_std_internal_symbol] => {
                     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 => {
+                [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 => {
+                [sym::rustc_legacy_const_generics] => {
                     self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
                 }
-                sym::rustc_lint_query_instability => {
+                [sym::rustc_lint_query_instability] => {
                     self.check_rustc_lint_query_instability(hir_id, attr, span, target)
                 }
-                sym::rustc_lint_diagnostics => {
+                [sym::rustc_lint_diagnostics] => {
                     self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
                 }
-                sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(attr, span, target),
-                sym::rustc_lint_opt_deny_field_access => {
+                [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target),
+                [sym::rustc_lint_opt_deny_field_access] => {
                     self.check_rustc_lint_opt_deny_field_access(attr, span, target)
                 }
-                sym::rustc_clean
-                | sym::rustc_dirty
-                | sym::rustc_if_this_changed
-                | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr),
-                sym::rustc_coinductive
-                | sym::rustc_must_implement_one_of
-                | sym::rustc_deny_explicit_impl
-                | sym::const_trait => self.check_must_be_applied_to_trait(attr, span, target),
-                sym::cmse_nonsecure_entry => {
+                [sym::rustc_clean]
+                | [sym::rustc_dirty]
+                | [sym::rustc_if_this_changed]
+                | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr),
+                [sym::rustc_coinductive]
+                | [sym::rustc_must_implement_one_of]
+                | [sym::rustc_deny_explicit_impl]
+                | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target),
+                [sym::cmse_nonsecure_entry] => {
                     self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
                 }
-                sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
-                sym::must_not_suspend => self.check_must_not_suspend(attr, span, target),
-                sym::must_use => self.check_must_use(hir_id, attr, target),
-                sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target),
-                sym::rustc_allow_incoherent_impl => {
+                [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target),
+                [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target),
+                [sym::must_use] => self.check_must_use(hir_id, attr, target),
+                [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target),
+                [sym::rustc_allow_incoherent_impl] => {
                     self.check_allow_incoherent_impl(attr, span, target)
                 }
-                sym::rustc_has_incoherent_inherent_impls => {
+                [sym::rustc_has_incoherent_inherent_impls] => {
                     self.check_has_incoherent_inherent_impls(attr, span, target)
                 }
-                sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
-                sym::ffi_const => self.check_ffi_const(attr.span, target),
-                sym::rustc_const_unstable
-                | sym::rustc_const_stable
-                | sym::unstable
-                | sym::stable
-                | sym::rustc_allowed_through_unstable_modules
-                | sym::rustc_promotable => self.check_stability_promotable(attr, target),
-                sym::link_ordinal => self.check_link_ordinal(attr, span, target),
-                sym::rustc_confusables => self.check_confusables(attr, target),
-                sym::rustc_safe_intrinsic => {
+                [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target),
+                [sym::ffi_const] => self.check_ffi_const(attr.span, target),
+                [sym::rustc_const_unstable]
+                | [sym::rustc_const_stable]
+                | [sym::unstable]
+                | [sym::stable]
+                | [sym::rustc_allowed_through_unstable_modules]
+                | [sym::rustc_promotable] => self.check_stability_promotable(attr, target),
+                [sym::link_ordinal] => self.check_link_ordinal(attr, span, target),
+                [sym::rustc_confusables] => self.check_confusables(attr, target),
+                [sym::rustc_safe_intrinsic] => {
                     self.check_rustc_safe_intrinsic(hir_id, attr, span, target)
                 }
                 _ => true,
@@ -293,18 +294,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         );
     }
 
-    /// Checks if `#[do_not_recommend]` is applied on a trait impl.
-    fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
-        if let Target::Impl = target {
-            true
-        } else {
-            self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
-            false
+    /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
+    fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool {
+        if !matches!(target, Target::Impl) {
+            self.tcx.emit_node_span_lint(
+                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                errors::IncorrectDoNotRecommendLocation,
+            );
         }
+        true
     }
 
     /// 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) {
+    fn check_diagnostic_on_unimplemented(
+        &self,
+        attr_span: Span,
+        hir_id: HirId,
+        target: Target,
+    ) -> bool {
         if !matches!(target, Target::Trait) {
             self.tcx.emit_node_span_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
@@ -313,6 +322,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 DiagnosticOnUnimplementedOnlyForTraits,
             );
         }
+        true
     }
 
     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index b8586e7e974..180552785fe 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -17,12 +17,9 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
 use crate::check_attr::ProcMacroKind;
 use crate::lang_items::Duplicate;
 
-#[derive(Diagnostic)]
+#[derive(LintDiagnostic)]
 #[diag(passes_incorrect_do_not_recommend_location)]
-pub struct IncorrectDoNotRecommendLocation {
-    #[primary_span]
-    pub span: Span,
-}
+pub struct IncorrectDoNotRecommendLocation;
 
 #[derive(LintDiagnostic)]
 #[diag(passes_outer_crate_level_attr)]
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index a5fa94faead..b3722e99e16 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -149,8 +149,9 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
                 }
             };
 
-            // When there's a duplicate lang item, something went very wrong and there's no value in recovering or doing anything.
-            // Give the user the one message to let them debug the mess they created and then wish them farewell.
+            // When there's a duplicate lang item, something went very wrong and there's no value
+            // in recovering or doing anything. Give the user the one message to let them debug the
+            // mess they created and then wish them farewell.
             self.tcx.dcx().emit_fatal(DuplicateLangItem {
                 local_span: item_span,
                 lang_item_name,
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 5fe68085d65..fc3669fecc2 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -32,7 +32,7 @@ use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{pluralize, MultiSpan};
+use rustc_errors::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES};
 use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS};
@@ -151,11 +151,10 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             // We do this in any edition.
             if warn_if_unused {
                 if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
-                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    self.r.lint_buffer.buffer_lint(
                         UNUSED_EXTERN_CRATES,
                         extern_crate.id,
                         span,
-                        "unused extern crate",
                         BuiltinLintDiag::UnusedExternCrate {
                             removal_span: extern_crate.span_with_attributes,
                         },
@@ -204,11 +203,10 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
                 .span
                 .find_ancestor_inside(extern_crate.span)
                 .unwrap_or(extern_crate.ident.span);
-            self.r.lint_buffer.buffer_lint_with_diagnostic(
+            self.r.lint_buffer.buffer_lint(
                 UNUSED_EXTERN_CRATES,
                 extern_crate.id,
                 extern_crate.span,
-                "`extern crate` is not idiomatic in the new edition",
                 BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
             );
         }
@@ -299,13 +297,13 @@ fn calc_unused_spans(
 
             let mut unused_spans = Vec::new();
             let mut to_remove = Vec::new();
-            let mut used_childs = 0;
+            let mut used_children = 0;
             let mut contains_self = false;
             let mut previous_unused = false;
             for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() {
                 let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) {
                     UnusedSpanResult::Used => {
-                        used_childs += 1;
+                        used_children += 1;
                         None
                     }
                     UnusedSpanResult::Unused { mut spans, remove } => {
@@ -313,7 +311,7 @@ fn calc_unused_spans(
                         Some(remove)
                     }
                     UnusedSpanResult::PartialUnused { mut spans, remove: mut to_remove_extra } => {
-                        used_childs += 1;
+                        used_children += 1;
                         unused_spans.append(&mut spans);
                         to_remove.append(&mut to_remove_extra);
                         None
@@ -322,7 +320,7 @@ fn calc_unused_spans(
                 if let Some(remove) = remove {
                     let remove_span = if nested.len() == 1 {
                         remove
-                    } else if pos == nested.len() - 1 || used_childs > 0 {
+                    } else if pos == nested.len() - 1 || used_children > 0 {
                         // Delete everything from the end of the last import, to delete the
                         // previous comma
                         nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span)
@@ -346,7 +344,7 @@ fn calc_unused_spans(
             }
             if unused_spans.is_empty() {
                 UnusedSpanResult::Used
-            } else if used_childs == 0 {
+            } else if used_children == 0 {
                 UnusedSpanResult::Unused { spans: unused_spans, remove: full_span }
             } else {
                 // If there is only one remaining child that is used, the braces around the use
@@ -360,7 +358,7 @@ fn calc_unused_spans(
                 // `self`: `use foo::{self};` is valid Rust syntax, while `use foo::self;` errors
                 // out. We also cannot turn `use foo::{self}` into `use foo`, as the former doesn't
                 // import types with the same name as the module.
-                if used_childs == 1 && !contains_self {
+                if used_children == 1 && !contains_self {
                     // Left brace, from the start of the nested group to the first item.
                     to_remove.push(
                         tree_span.shrink_to_lo().to(nested.first().unwrap().0.span.shrink_to_lo()),
@@ -394,10 +392,7 @@ impl Resolver<'_, '_> {
                                 MACRO_USE_EXTERN_CRATE,
                                 import.root_id,
                                 import.span,
-                                "deprecated `#[macro_use]` attribute used to \
-                                import macros should be replaced at use sites \
-                                with a `use` item to import the macro \
-                                instead",
+                                BuiltinLintDiag::MacroUseDeprecated,
                             );
                         }
                     }
@@ -414,8 +409,12 @@ impl Resolver<'_, '_> {
                     }
                 }
                 ImportKind::MacroUse { .. } => {
-                    let msg = "unused `#[macro_use]` import";
-                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg);
+                    self.lint_buffer.buffer_lint(
+                        UNUSED_IMPORTS,
+                        import.root_id,
+                        import.span,
+                        BuiltinLintDiag::UnusedMacroUse,
+                    );
                 }
                 _ => {}
             }
@@ -434,20 +433,12 @@ impl Resolver<'_, '_> {
         visitor.report_unused_extern_crate_items(maybe_unused_extern_crates);
 
         for unused in visitor.unused_imports.values() {
-            let mut fixes = Vec::new();
-            let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
-                UnusedSpanResult::Used => continue,
-                UnusedSpanResult::Unused { spans, remove } => {
-                    fixes.push((remove, String::new()));
-                    spans
-                }
-                UnusedSpanResult::PartialUnused { spans, remove } => {
-                    for fix in &remove {
-                        fixes.push((*fix, String::new()));
-                    }
-                    spans
-                }
-            };
+            let (spans, remove_spans) =
+                match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
+                    UnusedSpanResult::Used => continue,
+                    UnusedSpanResult::Unused { spans, remove } => (spans, vec![remove]),
+                    UnusedSpanResult::PartialUnused { spans, remove } => (spans, remove),
+                };
 
             let ms = MultiSpan::from_spans(spans);
 
@@ -459,23 +450,8 @@ impl Resolver<'_, '_> {
                 .collect::<Vec<String>>();
             span_snippets.sort();
 
-            let msg = format!(
-                "unused import{}{}",
-                pluralize!(ms.primary_spans().len()),
-                if !span_snippets.is_empty() {
-                    format!(": {}", span_snippets.join(", "))
-                } else {
-                    String::new()
-                }
-            );
-
-            let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
-                "remove the whole `use` item"
-            } else if ms.primary_spans().len() > 1 {
-                "remove the unused imports"
-            } else {
-                "remove the unused import"
-            };
+            let remove_whole_use = remove_spans.len() == 1 && remove_spans[0] == unused.item_span;
+            let num_to_remove = ms.primary_spans().len();
 
             // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
             // attribute; however, if not, suggest adding the attribute. There is no way to
@@ -501,12 +477,17 @@ impl Resolver<'_, '_> {
                 }
             };
 
-            visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+            visitor.r.lint_buffer.buffer_lint(
                 UNUSED_IMPORTS,
                 unused.use_tree_id,
                 ms,
-                msg,
-                BuiltinLintDiag::UnusedImports(fix_msg.into(), fixes, test_module_span),
+                BuiltinLintDiag::UnusedImports {
+                    remove_whole_use,
+                    num_to_remove,
+                    remove_spans,
+                    test_module_span,
+                    span_snippets,
+                },
             );
         }
 
@@ -552,11 +533,10 @@ impl Resolver<'_, '_> {
                 continue;
             }
 
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 UNUSED_QUALIFICATIONS,
                 unn_qua.node_id,
                 unn_qua.path_span,
-                "unnecessary qualification",
                 BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span },
             );
         }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index b28312fa473..856cfbc01e8 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -128,13 +128,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         self.report_with_use_injections(krate);
 
         for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
-            let msg = "macro-expanded `macro_export` macros from the current crate \
-                       cannot be referred to by absolute paths";
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
                 CRATE_NODE_ID,
                 span_use,
-                msg,
                 BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
             );
         }
@@ -145,11 +142,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
                     unreachable!()
                 };
-                self.lint_buffer.buffer_lint_with_diagnostic(
+                self.lint_buffer.buffer_lint(
                     AMBIGUOUS_GLOB_IMPORTS,
                     import.root_id,
                     ambiguity_error.ident.span,
-                    diag.msg.to_string(),
                     BuiltinLintDiag::AmbiguousGlobImports { diag },
                 );
             } else {
@@ -526,12 +522,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
-        self.lint_buffer.buffer_lint_with_diagnostic(
+        self.lint_buffer.buffer_lint(
             ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
             node_id,
             root_span,
-            "absolute paths must start with `self`, `super`, \
-             `crate`, or an external crate name in the 2018 edition",
             diag,
         );
     }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index f88725830f1..57db765c07e 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -524,18 +524,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         match binding {
                             Ok(binding) => {
                                 if let Some(lint_id) = derive_fallback_lint_id {
-                                    this.lint_buffer.buffer_lint_with_diagnostic(
+                                    this.lint_buffer.buffer_lint(
                                         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
                                         lint_id,
                                         orig_ident.span,
-                                        format!(
-                                            "cannot find {} `{}` in this scope",
-                                            ns.descr(),
-                                            ident
-                                        ),
-                                        BuiltinLintDiag::ProcMacroDeriveResolutionFallback(
-                                            orig_ident.span,
-                                        ),
+                                        BuiltinLintDiag::ProcMacroDeriveResolutionFallback {
+                                            span: orig_ident.span,
+                                            ns,
+                                            ident,
+                                        },
                                     );
                                 }
                                 let misc_flags = if module == this.graph_root {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index f53bcb0e9d0..51b87c5a9b0 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -619,11 +619,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         && binding.res() != Res::Err
                         && exported_ambiguities.contains(&binding)
                     {
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             AMBIGUOUS_GLOB_REEXPORTS,
                             import.root_id,
                             import.root_span,
-                            "ambiguous glob re-exports",
                             BuiltinLintDiag::AmbiguousGlobReexports {
                                 name: key.ident.to_string(),
                                 namespace: key.ns.descr().to_string(),
@@ -655,11 +654,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             && glob_binding.vis.is_public()
                             && !binding.vis.is_public()
                         {
-                            self.lint_buffer.buffer_lint_with_diagnostic(
+                            self.lint_buffer.buffer_lint(
                                 HIDDEN_GLOB_REEXPORTS,
                                 binding_id,
                                 binding.span,
-                                "private item shadows public glob re-export",
                                 BuiltinLintDiag::HiddenGlobReexports {
                                     name: key.ident.name.to_string(),
                                     namespace: key.ns.descr().to_owned(),
@@ -1015,17 +1013,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         && !max_vis.is_at_least(import_vis, self.tcx)
                     {
                         let def_id = self.local_def_id(id);
-                        let msg = format!(
-                            "glob import doesn't reexport anything with visibility `{}` because no imported item is public enough",
-                            import_vis.to_string(def_id, self.tcx)
-                        );
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             UNUSED_IMPORTS,
                             id,
                             import.span,
-                            msg,
                             BuiltinLintDiag::RedundantImportVisibility {
                                 max_vis: max_vis.to_string(def_id, self.tcx),
+                                import_vis: import_vis.to_string(def_id, self.tcx),
                                 span: import.span,
                             },
                         );
@@ -1252,16 +1246,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         if !any_successful_reexport {
             let (ns, binding) = reexport_error.unwrap();
             if pub_use_of_private_extern_crate_hack(import, binding) {
-                let msg = format!(
-                    "extern crate `{ident}` is private, and cannot be \
-                                   re-exported (error E0365), consider declaring with \
-                                   `pub`"
-                );
                 self.lint_buffer.buffer_lint(
                     PUB_USE_OF_PRIVATE_EXTERN_CRATE,
                     import_id,
                     import.span,
-                    msg,
+                    BuiltinLintDiag::PrivateExternCrateReexport(ident),
                 );
             } else {
                 if ns == TypeNS {
@@ -1397,7 +1386,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 UNUSED_IMPORTS,
                 id,
                 import.span,
-                format!("the item `{source}` is imported redundantly"),
                 BuiltinLintDiag::RedundantImport(redundant_spans, source),
             );
             */
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 0f585aafdd5..d1d0e336cfe 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -24,7 +24,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::ty::DelegationFnSig;
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
-use rustc_session::lint;
+use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::parse::feature_err;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1675,16 +1675,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     return;
                 }
                 LifetimeRibKind::AnonymousWarn(node_id) => {
-                    let msg = if elided {
-                        "`&` without an explicit lifetime name cannot be used here"
-                    } else {
-                        "`'_` cannot be used here"
-                    };
-                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    self.r.lint_buffer.buffer_lint(
                         lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
                         node_id,
                         lifetime.ident.span,
-                        msg,
                         lint::BuiltinLintDiag::AssociatedConstElidedLifetime {
                             elided,
                             span: lifetime.ident.span,
@@ -1966,11 +1960,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             }
 
             if should_lint {
-                self.r.lint_buffer.buffer_lint_with_diagnostic(
+                self.r.lint_buffer.buffer_lint(
                     lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
                     segment_id,
                     elided_lifetime_span,
-                    "hidden lifetime parameters in types are deprecated",
                     lint::BuiltinLintDiag::ElidedLifetimesInPaths(
                         expected_lifetimes,
                         path_span,
@@ -4822,7 +4815,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
         visit::walk_crate(&mut late_resolution_visitor, krate);
         for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() {
-            self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
+            self.lint_buffer.buffer_lint(
+                lint::builtin::UNUSED_LABELS,
+                *id,
+                *span,
+                BuiltinLintDiag::UnusedLabel,
+            );
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 1958fdf1cbc..9daa22f89d2 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -17,6 +17,7 @@ use rustc_ast::{
 };
 use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
     SuggestionStyle,
@@ -31,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 
 use rustc_middle::ty;
 
@@ -2651,15 +2652,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     let deletion_span =
                         if param.bounds.is_empty() { deletion_span() } else { None };
 
-                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    self.r.lint_buffer.buffer_lint(
                         lint::builtin::SINGLE_USE_LIFETIMES,
                         param.id,
                         param.ident.span,
-                        format!("lifetime parameter `{}` only used once", param.ident),
                         lint::BuiltinLintDiag::SingleUseLifetime {
                             param_span: param.ident.span,
                             use_span: Some((use_span, elidable)),
                             deletion_span,
+                            ident: param.ident,
                         },
                     );
                 }
@@ -2669,15 +2670,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
                     // if the lifetime originates from expanded code, we won't be able to remove it #104432
                     if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) {
-                        self.r.lint_buffer.buffer_lint_with_diagnostic(
+                        self.r.lint_buffer.buffer_lint(
                             lint::builtin::UNUSED_LIFETIMES,
                             param.id,
                             param.ident.span,
-                            format!("lifetime parameter `{}` never used", param.ident),
                             lint::BuiltinLintDiag::SingleUseLifetime {
                                 param_span: param.ident.span,
                                 use_span: None,
                                 deletion_span,
+                                ident: param.ident,
                             },
                         );
                     }
@@ -2714,8 +2715,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         self.suggest_introducing_lifetime(
             &mut err,
             Some(lifetime_ref.ident.name.as_str()),
-            |err, _, span, message, suggestion| {
-                err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
+            |err, _, span, message, suggestion, span_suggs| {
+                err.multipart_suggestion_with_style(
+                    message,
+                    std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
+                    Applicability::MaybeIncorrect,
+                    if span_suggs.is_empty() {
+                        SuggestionStyle::ShowCode
+                    } else {
+                        SuggestionStyle::ShowAlways
+                    },
+                );
                 true
             },
         );
@@ -2726,13 +2736,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         &self,
         err: &mut Diag<'_>,
         name: Option<&str>,
-        suggest: impl Fn(&mut Diag<'_>, bool, Span, Cow<'static, str>, String) -> bool,
+        suggest: impl Fn(
+            &mut Diag<'_>,
+            bool,
+            Span,
+            Cow<'static, str>,
+            String,
+            Vec<(Span, String)>,
+        ) -> bool,
     ) {
         let mut suggest_note = true;
         for rib in self.lifetime_ribs.iter().rev() {
             let mut should_continue = true;
             match rib.kind {
-                LifetimeRibKind::Generics { binder: _, span, kind } => {
+                LifetimeRibKind::Generics { binder, span, kind } => {
                     // Avoid suggesting placing lifetime parameters on constant items unless the relevant
                     // feature is enabled. Suggest the parent item as a possible location if applicable.
                     if let LifetimeBinderKind::ConstItem = kind
@@ -2761,11 +2778,53 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             | LifetimeBinderKind::PolyTrait
                             | LifetimeBinderKind::WhereBound
                     );
+
+                    let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
                     let (span, sugg) = if span.is_empty() {
+                        let mut binder_idents: FxIndexSet<Ident> = Default::default();
+                        binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
+
+                        // We need to special case binders in the following situation:
+                        // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
+                        // T: for<'a> Trait<T> + 'b
+                        //    ^^^^^^^  remove existing inner binder `for<'a>`
+                        // for<'a, 'b> T: Trait<T> + 'b
+                        // ^^^^^^^^^^^  suggest outer binder `for<'a, 'b>`
+                        if let LifetimeBinderKind::WhereBound = kind
+                            && let Some(ast::WherePredicate::BoundPredicate(
+                                ast::WhereBoundPredicate { bounded_ty, bounds, .. },
+                            )) = self.diag_metadata.current_where_predicate
+                            && bounded_ty.id == binder
+                        {
+                            for bound in bounds {
+                                if let ast::GenericBound::Trait(poly_trait_ref, _) = bound
+                                    && let span = poly_trait_ref
+                                        .span
+                                        .with_hi(poly_trait_ref.trait_ref.path.span.lo())
+                                    && !span.is_empty()
+                                {
+                                    rm_inner_binders.insert(span);
+                                    poly_trait_ref.bound_generic_params.iter().for_each(|v| {
+                                        binder_idents.insert(v.ident);
+                                    });
+                                }
+                            }
+                        }
+
+                        let binders_sugg = binder_idents.into_iter().enumerate().fold(
+                            "".to_string(),
+                            |mut binders, (i, x)| {
+                                if i != 0 {
+                                    binders += ", ";
+                                }
+                                binders += x.as_str();
+                                binders
+                            },
+                        );
                         let sugg = format!(
                             "{}<{}>{}",
                             if higher_ranked { "for" } else { "" },
-                            name.unwrap_or("'a"),
+                            binders_sugg,
                             if higher_ranked { " " } else { "" },
                         );
                         (span, sugg)
@@ -2780,13 +2839,28 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         let sugg = format!("{}, ", name.unwrap_or("'a"));
                         (span, sugg)
                     };
+
                     if higher_ranked {
                         let message = Cow::from(format!(
                             "consider making the {} lifetime-generic with a new `{}` lifetime",
                             kind.descr(),
                             name.unwrap_or("'a"),
                         ));
-                        should_continue = suggest(err, true, span, message, sugg);
+                        should_continue = suggest(
+                            err,
+                            true,
+                            span,
+                            message,
+                            sugg,
+                            if !rm_inner_binders.is_empty() {
+                                rm_inner_binders
+                                    .into_iter()
+                                    .map(|v| (v, "".to_string()))
+                                    .collect::<Vec<_>>()
+                            } else {
+                                vec![]
+                            },
+                        );
                         err.note_once(
                             "for more information on higher-ranked polymorphism, visit \
                              https://doc.rust-lang.org/nomicon/hrtb.html",
@@ -2794,10 +2868,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     } else if let Some(name) = name {
                         let message =
                             Cow::from(format!("consider introducing lifetime `{name}` here"));
-                        should_continue = suggest(err, false, span, message, sugg);
+                        should_continue = suggest(err, false, span, message, sugg, vec![]);
                     } else {
                         let message = Cow::from("consider introducing a named lifetime parameter");
-                        should_continue = suggest(err, false, span, message, sugg);
+                        should_continue = suggest(err, false, span, message, sugg, vec![]);
                     }
                 }
                 LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
@@ -3033,11 +3107,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 self.suggest_introducing_lifetime(
                     err,
                     None,
-                    |err, higher_ranked, span, message, intro_sugg| {
+                    |err, higher_ranked, span, message, intro_sugg, _| {
                         err.multipart_suggestion_verbose(
                             message,
                             std::iter::once((span, intro_sugg))
-                                .chain(spans_suggs.iter().cloned())
+                                .chain(spans_suggs.clone())
                                 .collect(),
                             Applicability::MaybeIncorrect,
                         );
@@ -3161,11 +3235,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             self.suggest_introducing_lifetime(
                                 err,
                                 None,
-                                |err, higher_ranked, span, message, intro_sugg| {
+                                |err, higher_ranked, span, message, intro_sugg, _| {
                                     err.multipart_suggestion_verbose(
                                         message,
                                         std::iter::once((span, intro_sugg))
-                                            .chain(spans_suggs.iter().cloned())
+                                            .chain(spans_suggs.clone())
                                             .collect(),
                                         Applicability::MaybeIncorrect,
                                     );
@@ -3309,7 +3383,6 @@ fn mk_where_bound_predicate(
     poly_trait_ref: &ast::PolyTraitRef,
     ty: &Ty,
 ) -> Option<ast::WhereBoundPredicate> {
-    use rustc_span::DUMMY_SP;
     let modified_segments = {
         let mut segments = path.segments.clone();
         let [preceding @ .., second_last, last] = segments.as_mut_slice() else {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 01bcfec4bdc..f4c5ad8f672 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -51,7 +51,7 @@ use rustc_middle::ty::{self, DelegationFnSig, Feed, MainDefinition, RegisteredTo
 use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
-use rustc_session::lint::LintBuffer;
+use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -1860,8 +1860,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
         if let NameBindingKind::Import { import, binding } = used_binding.kind {
             if let ImportKind::MacroUse { warn_private: true } = import.kind {
-                let msg = format!("macro `{ident}` is private");
-                self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg);
+                self.lint_buffer().buffer_lint(
+                    PRIVATE_MACRO_USE,
+                    import.root_id,
+                    ident.span,
+                    BuiltinLintDiag::MacroIsPrivate(ident),
+                );
             }
             // Avoid marking `extern crate` items that refer to a name from extern prelude,
             // but not introduce it, as used if they are accessed from lexical scope.
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index f8d245f94e5..268e7f06d04 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -315,7 +315,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
                 UNUSED_MACROS,
                 node_id,
                 ident.span,
-                format!("unused macro definition: `{}`", ident.name),
+                BuiltinLintDiag::UnusedMacroDefinition(ident.name),
             );
         }
         for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() {
@@ -328,7 +328,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
                 UNUSED_MACRO_RULES,
                 node_id,
                 rule_span,
-                format!("rule #{} of macro `{}` is never used", arm_i + 1, ident.name),
+                BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name),
             );
         }
     }
@@ -552,14 +552,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         // We are trying to avoid reporting this error if other related errors were reported.
         if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes {
-            let msg = match res {
-                Res::Def(..) => "inner macro attributes are unstable",
-                Res::NonMacroAttr(..) => "custom inner attributes are unstable",
+            let is_macro = match res {
+                Res::Def(..) => true,
+                Res::NonMacroAttr(..) => false,
                 _ => unreachable!(),
             };
             if soft_custom_inner_attributes_gate {
-                self.tcx.sess.psess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
+                self.tcx.sess.psess.buffer_lint(
+                    SOFT_UNSTABLE,
+                    path.span,
+                    node_id,
+                    BuiltinLintDiag::InnerAttributeUnstable { is_macro },
+                );
             } else {
+                // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::InnerAttributeUnstable`)
+                let msg = if is_macro {
+                    "inner macro attributes are unstable"
+                } else {
+                    "custom inner attributes are unstable"
+                };
                 feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
             }
         }
@@ -567,22 +578,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && let [namespace, attribute, ..] = &*path.segments
             && namespace.ident.name == sym::diagnostic
-            && attribute.ident.name != sym::on_unimplemented
+            && !(attribute.ident.name == sym::on_unimplemented
+                || (attribute.ident.name == sym::do_not_recommend
+                    && self.tcx.features().do_not_recommend))
         {
             let distance =
                 edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
 
-            let help = if distance.is_some() {
-                BuiltinLintDiag::MaybeTypo { span: attribute.span(), name: sym::on_unimplemented }
-            } else {
-                BuiltinLintDiag::Normal
-            };
-            self.tcx.sess.psess.buffer_lint_with_diagnostic(
+            let typo_name = distance.map(|_| sym::on_unimplemented);
+
+            self.tcx.sess.psess.buffer_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                 attribute.span(),
                 node_id,
-                "unknown diagnostic attribute",
-                help,
+                BuiltinLintDiag::UnknownDiagnosticAttribute { span: attribute.span(), typo_name },
             );
         }
 
@@ -782,11 +791,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             .invocation_parents
                             .get(&parent_scope.expansion)
                             .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]);
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             LEGACY_DERIVE_HELPERS,
                             node_id,
                             ident.span,
-                            "derive helper attribute is used before it is introduced",
                             BuiltinLintDiag::LegacyDeriveHelpers(binding.span),
                         );
                     }
@@ -836,8 +844,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
                 if !is_allowed(feature) && !allowed_by_implication {
                     let lint_buffer = &mut self.lint_buffer;
-                    let soft_handler =
-                        |lint, span, msg: String| lint_buffer.buffer_lint(lint, node_id, span, msg);
+                    let soft_handler = |lint, span, msg: String| {
+                        lint_buffer.buffer_lint(
+                            lint,
+                            node_id,
+                            span,
+                            BuiltinLintDiag::UnstableFeature(
+                                // FIXME make this translatable
+                                msg.into(),
+                            ),
+                        )
+                    };
                     stability::report_unstable(
                         self.tcx.sess,
                         feature,
@@ -853,14 +870,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
         if let Some(depr) = &ext.deprecation {
             let path = pprust::path_to_string(path);
-            let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path);
-            stability::early_report_deprecation(
+            stability::early_report_macro_deprecation(
                 &mut self.lint_buffer,
-                message,
-                depr.suggestion,
-                lint,
+                depr,
                 span,
                 node_id,
+                path,
             );
         }
     }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 21433cfdb61..62eb07e8287 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -269,7 +269,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
 /// if a function is member of the group derived from this type id. Therefore, in the first call to
 /// typeid_for_fnabi (when type ids are attached to functions and methods), it can only include at
 /// most as much information that would be available in the second call (i.e., during code
-/// generation at call sites); otherwise, the type ids would not not match.
+/// generation at call sites); otherwise, the type ids would not match.
 ///
 /// For this, it:
 ///
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index f6053f43fbd..df07f81bc45 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -305,32 +305,12 @@ impl ParseSess {
         lint: &'static Lint,
         span: impl Into<MultiSpan>,
         node_id: NodeId,
-        msg: impl Into<DiagMessage>,
-    ) {
-        self.buffered_lints.with_lock(|buffered_lints| {
-            buffered_lints.push(BufferedEarlyLint {
-                span: span.into(),
-                node_id,
-                msg: msg.into(),
-                lint_id: LintId::of(lint),
-                diagnostic: BuiltinLintDiag::Normal,
-            });
-        });
-    }
-
-    pub fn buffer_lint_with_diagnostic(
-        &self,
-        lint: &'static Lint,
-        span: impl Into<MultiSpan>,
-        node_id: NodeId,
-        msg: impl Into<DiagMessage>,
         diagnostic: BuiltinLintDiag,
     ) {
         self.buffered_lints.with_lock(|buffered_lints| {
             buffered_lints.push(BufferedEarlyLint {
                 span: span.into(),
                 node_id,
-                msg: msg.into(),
                 lint_id: LintId::of(lint),
                 diagnostic,
             });
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index db01bb90d6f..a2872fc1661 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1183,9 +1183,9 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             });
         }
     }
-    // Cannot mix and match sanitizers.
-    let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
-    if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
+
+    // Cannot mix and match mutually-exclusive sanitizers.
+    if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
         sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
             first: first.to_string(),
             second: second.to_string(),
@@ -1220,14 +1220,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         sess.dcx().emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
     }
 
-    // LLVM CFI is incompatible with LLVM KCFI.
-    if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
-        sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
-            first: "cfi".to_string(),
-            second: "kcfi".to_string(),
-        });
-    }
-
     // Canonical jump tables requires CFI.
     if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
         if !sess.is_sanitizer_cfi_enabled() {
diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs
index 39e4541349e..e244c77f7f9 100644
--- a/compiler/rustc_session/src/version.rs
+++ b/compiler/rustc_session/src/version.rs
@@ -1,5 +1,10 @@
 use rustc_macros::{current_rustc_version, Decodable, Encodable, HashStable_Generic};
-use std::fmt::{self, Display};
+use std::{
+    borrow::Cow,
+    fmt::{self, Display},
+};
+
+use rustc_errors::IntoDiagArg;
 
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(HashStable_Generic)]
@@ -18,3 +23,9 @@ impl Display for RustcVersion {
         write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
     }
 }
+
+impl IntoDiagArg for RustcVersion {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        rustc_errors::DiagArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 452ab04c44c..d89caabab3e 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -1,5 +1,6 @@
 //! Conversion of internal Rust compiler `mir` items to stable ones.
 
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::alloc_range;
 use rustc_middle::mir::mono::MonoItem;
@@ -183,16 +184,21 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
                 op.stable(tables),
                 ty.stable(tables),
             ),
-            BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
-                bin_op.stable(tables),
-                ops.0.stable(tables),
-                ops.1.stable(tables),
-            ),
-            CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
-                bin_op.stable(tables),
-                ops.0.stable(tables),
-                ops.1.stable(tables),
-            ),
+            BinaryOp(bin_op, ops) => {
+                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                    stable_mir::mir::Rvalue::CheckedBinaryOp(
+                        bin_op.stable(tables),
+                        ops.0.stable(tables),
+                        ops.1.stable(tables),
+                    )
+                } else {
+                    stable_mir::mir::Rvalue::BinaryOp(
+                        bin_op.stable(tables),
+                        ops.0.stable(tables),
+                        ops.1.stable(tables),
+                    )
+                }
+            }
             NullaryOp(null_op, ty) => {
                 stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
             }
@@ -485,10 +491,13 @@ impl<'tcx> Stable<'tcx> for mir::BinOp {
         match self {
             BinOp::Add => stable_mir::mir::BinOp::Add,
             BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked,
+            BinOp::AddWithOverflow => bug!("AddWithOverflow should have been translated already"),
             BinOp::Sub => stable_mir::mir::BinOp::Sub,
             BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked,
+            BinOp::SubWithOverflow => bug!("AddWithOverflow should have been translated already"),
             BinOp::Mul => stable_mir::mir::BinOp::Mul,
             BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked,
+            BinOp::MulWithOverflow => bug!("AddWithOverflow should have been translated already"),
             BinOp::Div => stable_mir::mir::BinOp::Div,
             BinOp::Rem => stable_mir::mir::BinOp::Rem,
             BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index d59318be720..15447983abb 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -505,6 +505,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
             is_marker: self.is_marker,
             is_coinductive: self.is_coinductive,
             skip_array_during_method_dispatch: self.skip_array_during_method_dispatch,
+            skip_boxed_slice_during_method_dispatch: self.skip_boxed_slice_during_method_dispatch,
             specialization_kind: self.specialization_kind.stable(tables),
             must_implement_one_of: self
                 .must_implement_one_of
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 68b1b32baf2..ace4dff46aa 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -930,6 +930,7 @@ symbols! {
         global_alloc_ty,
         global_allocator,
         global_asm,
+        global_registration,
         globs,
         gt,
         half_open_range_patterns,
@@ -1632,7 +1633,7 @@ symbols! {
         rustc_reservation_impl,
         rustc_safe_intrinsic,
         rustc_serialize,
-        rustc_skip_array_during_method_dispatch,
+        rustc_skip_during_method_dispatch,
         rustc_specialization_trait,
         rustc_std_internal_symbol,
         rustc_strict_coherence,
@@ -1681,6 +1682,7 @@ symbols! {
         simd_cast_ptr,
         simd_ceil,
         simd_ctlz,
+        simd_ctpop,
         simd_cttz,
         simd_div,
         simd_eq,
diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs
index c5b2065080b..05542009083 100644
--- a/compiler/rustc_target/src/spec/base/apple/mod.rs
+++ b/compiler/rustc_target/src/spec/base/apple/mod.rs
@@ -272,6 +272,7 @@ fn macos_default_deployment_target(arch: Arch) -> (u32, u32) {
 
 fn macos_deployment_target(arch: Arch) -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc/platform-support docs.
     from_set_deployment_target("MACOSX_DEPLOYMENT_TARGET")
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
@@ -320,6 +321,7 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
 
 fn ios_deployment_target(arch: Arch, abi: &str) -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc/platform-support docs.
     let (major, minor) = match (arch, abi) {
         (Arm64e, _) => (14, 0),
         // Mac Catalyst defaults to 13.1 in Clang.
@@ -352,6 +354,7 @@ pub fn ios_sim_llvm_target(arch: Arch) -> String {
 
 fn tvos_deployment_target() -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc platform-support docs.
     from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((10, 0))
 }
 
@@ -367,6 +370,7 @@ pub fn tvos_sim_llvm_target(arch: Arch) -> String {
 
 fn watchos_deployment_target() -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc platform-support docs.
     from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
@@ -382,6 +386,7 @@ pub fn watchos_sim_llvm_target(arch: Arch) -> String {
 
 fn visionos_deployment_target() -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc platform-support docs.
     from_set_deployment_target("XROS_DEPLOYMENT_TARGET").unwrap_or((1, 0))
 }
 
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 910c6aeb7d6..83ee63e2cf2 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1317,6 +1317,34 @@ bitflags::bitflags! {
 rustc_data_structures::external_bitflags_debug! { SanitizerSet }
 
 impl SanitizerSet {
+    // Taken from LLVM's sanitizer compatibility logic:
+    // https://github.com/llvm/llvm-project/blob/release/18.x/clang/lib/Driver/SanitizerArgs.cpp#L512
+    const MUTUALLY_EXCLUSIVE: &'static [(SanitizerSet, SanitizerSet)] = &[
+        (SanitizerSet::ADDRESS, SanitizerSet::MEMORY),
+        (SanitizerSet::ADDRESS, SanitizerSet::THREAD),
+        (SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS),
+        (SanitizerSet::ADDRESS, SanitizerSet::MEMTAG),
+        (SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK),
+        (SanitizerSet::LEAK, SanitizerSet::MEMORY),
+        (SanitizerSet::LEAK, SanitizerSet::THREAD),
+        (SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::LEAK, SanitizerSet::SAFESTACK),
+        (SanitizerSet::MEMORY, SanitizerSet::THREAD),
+        (SanitizerSet::MEMORY, SanitizerSet::HWADDRESS),
+        (SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::MEMORY, SanitizerSet::SAFESTACK),
+        (SanitizerSet::THREAD, SanitizerSet::HWADDRESS),
+        (SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::THREAD, SanitizerSet::SAFESTACK),
+        (SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG),
+        (SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK),
+        (SanitizerSet::CFI, SanitizerSet::KCFI),
+        (SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK),
+    ];
+
     /// Return sanitizer's name
     ///
     /// Returns none if the flags is a set of sanitizers numbering not exactly one.
@@ -1337,6 +1365,13 @@ impl SanitizerSet {
             _ => return None,
         })
     }
+
+    pub fn mutually_exclusive(self) -> Option<(SanitizerSet, SanitizerSet)> {
+        Self::MUTUALLY_EXCLUSIVE
+            .into_iter()
+            .find(|&(a, b)| self.contains(*a) && self.contains(*b))
+            .copied()
+    }
 }
 
 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 65cc0a45857..43e61de955a 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -16,10 +16,11 @@
 //! relate them structurally.
 
 use super::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn compute_alias_relate_goal(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index b1dd6ae6611..11524410692 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -1,8 +1,7 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
-use crate::solve::GoalSource;
-use crate::solve::{EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::bug;
 use rustc_middle::traits::solve::inspect::ProbeKind;
@@ -17,6 +16,9 @@ use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use std::fmt::Debug;
 
+use crate::solve::GoalSource;
+use crate::solve::{EvalCtxt, SolverMode};
+
 pub(super) mod structural_traits;
 
 /// A candidate is a possible way to prove a goal.
@@ -46,18 +48,18 @@ pub(super) trait GoalKind<'tcx>:
     /// work, then produce a response (typically by executing
     /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
     fn probe_and_match_goal_against_assumption(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
-        then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// Consider a clause, which consists of a "assumption" and some "requirements",
     /// to satisfy a goal. If the requirements hold, then attempt to satisfy our
     /// goal by equating it with the assumption.
     fn probe_and_consider_implied_clause(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         parent_source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
@@ -75,7 +77,7 @@ pub(super) trait GoalKind<'tcx>:
     /// additionally checking all of the supertraits and object bounds to hold,
     /// since they're not implied by the well-formedness of the object type.
     fn probe_and_consider_object_bound_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
@@ -99,7 +101,7 @@ pub(super) trait GoalKind<'tcx>:
     }
 
     fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution>;
@@ -111,7 +113,7 @@ pub(super) trait GoalKind<'tcx>:
     /// Trait goals always hold while projection goals never do. This is a bit arbitrary
     /// but prevents incorrect normalization while hiding any trait errors.
     fn consider_error_guaranteed_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         guar: ErrorGuaranteed,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -120,13 +122,13 @@ pub(super) trait GoalKind<'tcx>:
     /// These components are given by built-in rules from
     /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`].
     fn consider_auto_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A trait alias holds if the RHS traits and `where` clauses hold.
     fn consider_trait_alias_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -135,7 +137,7 @@ pub(super) trait GoalKind<'tcx>:
     /// These components are given by built-in rules from
     /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
     fn consider_builtin_sized_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -144,27 +146,27 @@ pub(super) trait GoalKind<'tcx>:
     /// These components are given by built-in rules from
     /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`].
     fn consider_builtin_copy_clone_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A type is `PointerLike` if we can compute its layout, and that layout
     /// matches the layout of `usize`.
     fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A type is a `FnPtr` if it is of `FnPtr` type.
     fn consider_builtin_fn_ptr_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
     /// family of traits where `A` is given by the signature of the type.
     fn consider_builtin_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution>;
@@ -172,7 +174,7 @@ pub(super) trait GoalKind<'tcx>:
     /// An async closure is known to implement the `AsyncFn<A>` family of traits
     /// where `A` is given by the signature of the type.
     fn consider_builtin_async_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution>;
@@ -181,13 +183,13 @@ pub(super) trait GoalKind<'tcx>:
     /// is used internally to delay computation for async closures until after
     /// upvar analysis is performed in HIR typeck.
     fn consider_builtin_async_fn_kind_helper_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// `Tuple` is implemented if the `Self` type is a tuple.
     fn consider_builtin_tuple_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -197,7 +199,7 @@ pub(super) trait GoalKind<'tcx>:
     /// the built-in types. For structs, the metadata type is given by the struct
     /// tail.
     fn consider_builtin_pointee_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -205,7 +207,7 @@ pub(super) trait GoalKind<'tcx>:
     /// `Future<Output = O>`, where `O` is given by the coroutine's return type
     /// that was computed during type-checking.
     fn consider_builtin_future_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -213,19 +215,19 @@ pub(super) trait GoalKind<'tcx>:
     /// `Iterator<Item = O>`, where `O` is given by the generator's yield type
     /// that was computed during type-checking.
     fn consider_builtin_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A coroutine (that comes from a `gen` desugaring) is known to implement
     /// `FusedIterator`
     fn consider_builtin_fused_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_async_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -233,27 +235,27 @@ pub(super) trait GoalKind<'tcx>:
     /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
     /// and return types of the coroutine computed during type-checking.
     fn consider_builtin_coroutine_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_async_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_transmute_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -265,12 +267,12 @@ pub(super) trait GoalKind<'tcx>:
     /// otherwise recompute this for codegen. This is a bit of a mess but the
     /// easiest way to maintain the existing behavior for now.
     fn consider_structural_builtin_unsize_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<Candidate<'tcx>>;
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index cf826596392..930ae5af811 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -3,6 +3,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::LangItem;
 use rustc_hir::{def_id::DefId, Movability, Mutability};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
@@ -18,7 +19,7 @@ use crate::solve::EvalCtxt;
 // instantiate the binder with placeholders eagerly.
 #[instrument(level = "trace", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     let tcx = ecx.tcx();
@@ -97,7 +98,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
 #[instrument(level = "trace", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     match *ty.kind() {
@@ -161,7 +162,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
 
 #[instrument(level = "trace", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     match *ty.kind() {
@@ -663,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
 // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
 // for more details.
 pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -716,7 +717,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
 }
 
 struct ReplaceProjectionWith<'a, 'tcx> {
-    ecx: &'a EvalCtxt<'a, 'tcx>,
+    ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
     nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 52deb22098f..9590a82c067 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -18,7 +18,6 @@ use rustc_index::IndexVec;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
-use rustc_infer::infer::resolve::EagerResolver;
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::infer::{InferCtxt, InferOk};
 use rustc_infer::traits::solve::NestedNormalizationGoals;
@@ -31,6 +30,7 @@ use rustc_middle::traits::solve::{
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
 use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
+use rustc_next_trait_solver::resolve::EagerResolver;
 use rustc_span::{Span, DUMMY_SP};
 use std::assert_matches::assert_matches;
 use std::iter;
@@ -52,7 +52,7 @@ impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> {
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     /// Canonicalizes the goal remembering the original values
     /// for each bound variable.
     pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>(
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 70308d4359d..7e1d7d73e0b 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -4,7 +4,6 @@ use std::ops::ControlFlow;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::at::ToTrace;
-use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::{
     BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
 };
@@ -13,10 +12,8 @@ use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals};
 use rustc_infer::traits::ObligationCause;
 use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_middle::bug;
-use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::traits::solve::{
-    inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques,
-    PredefinedOpaquesData, QueryResult,
+    inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
 };
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::{
@@ -25,7 +22,7 @@ use rustc_middle::ty::{
 };
 use rustc_session::config::DumpSolverProofTree;
 use rustc_span::DUMMY_SP;
-use rustc_type_ir::{self as ir, Interner};
+use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::traits::coherence;
@@ -41,7 +38,11 @@ pub(super) mod canonical;
 mod probe;
 mod select;
 
-pub struct EvalCtxt<'a, 'tcx> {
+pub struct EvalCtxt<
+    'a,
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner = <Infcx as InferCtxtLike>::Interner,
+> {
     /// The inference context that backs (mostly) inference and placeholder terms
     /// instantiated while solving goals.
     ///
@@ -57,11 +58,11 @@ pub struct EvalCtxt<'a, 'tcx> {
     /// If some `InferCtxt` method is missing, please first think defensively about
     /// the method's compatibility with this solver, or if an existing one does
     /// the job already.
-    infcx: &'a InferCtxt<'tcx>,
+    infcx: &'a Infcx,
 
     /// The variable info for the `var_values`, only used to make an ambiguous response
     /// with no constraints.
-    variables: CanonicalVarInfos<'tcx>,
+    variables: I::CanonicalVars,
     /// Whether we're currently computing a `NormalizesTo` goal. Unlike other goals,
     /// `NormalizesTo` goals act like functions with the expected term always being
     /// fully unconstrained. This would weaken inference however, as the nested goals
@@ -70,9 +71,9 @@ pub struct EvalCtxt<'a, 'tcx> {
     /// when then adds these to its own context. The caller is always an `AliasRelate`
     /// goal so this never leaks out of the solver.
     is_normalizes_to_goal: bool,
-    pub(super) var_values: CanonicalVarValues<'tcx>,
+    pub(super) var_values: CanonicalVarValues<I>,
 
-    predefined_opaques_in_body: PredefinedOpaques<'tcx>,
+    predefined_opaques_in_body: I::PredefinedOpaques,
 
     /// The highest universe index nameable by the caller.
     ///
@@ -85,9 +86,9 @@ pub struct EvalCtxt<'a, 'tcx> {
     /// new placeholders to the caller.
     pub(super) max_input_universe: ty::UniverseIndex,
 
-    pub(super) search_graph: &'a mut SearchGraph<'tcx>,
+    pub(super) search_graph: &'a mut SearchGraph<I>,
 
-    nested_goals: NestedGoals<TyCtxt<'tcx>>,
+    nested_goals: NestedGoals<I>,
 
     // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`?
     //
@@ -97,7 +98,7 @@ pub struct EvalCtxt<'a, 'tcx> {
     // evaluation code.
     tainted: Result<(), NoSolution>,
 
-    pub(super) inspect: ProofTreeBuilder<TyCtxt<'tcx>>,
+    pub(super) inspect: ProofTreeBuilder<I>,
 }
 
 #[derive(derivative::Derivative)]
@@ -157,7 +158,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 }
 
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     pub(super) fn solver_mode(&self) -> SolverMode {
         self.search_graph.solver_mode()
     }
@@ -172,7 +173,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     pub(super) fn enter_root<R>(
         infcx: &InferCtxt<'tcx>,
         generate_proof_tree: GenerateProofTree,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> R,
     ) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) {
         let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
         let mut search_graph = search_graph::SearchGraph::new(mode);
@@ -225,10 +226,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     /// and registering opaques from the canonicalized input.
     fn enter_canonical<R>(
         tcx: TyCtxt<'tcx>,
-        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
+        search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
         canonical_input: CanonicalInput<'tcx>,
         canonical_goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
     ) -> R {
         let intercrate = match search_graph.solver_mode() {
             SolverMode::Normal => false,
@@ -287,7 +288,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)]
     fn evaluate_canonical_goal(
         tcx: TyCtxt<'tcx>,
-        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
+        search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
         canonical_input: CanonicalInput<'tcx>,
         goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
     ) -> QueryResult<'tcx> {
@@ -600,7 +601,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
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 9edc489754c..1748c9be927 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -1,6 +1,7 @@
 use crate::solve::assembly::Candidate;
 
 use super::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::BuiltinImplSource;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
@@ -8,7 +9,7 @@ use rustc_middle::ty::TyCtxt;
 use std::marker::PhantomData;
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
-    ecx: &'me mut EvalCtxt<'a, 'tcx>,
+    ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
     probe_kind: F,
     _result: PhantomData<T>,
 }
@@ -17,7 +18,10 @@ impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T>
 where
     F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
 {
-    pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
+    pub(in crate::solve) fn enter(
+        self,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> T,
+    ) -> T {
         let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
 
         let infcx = outer_ecx.infcx;
@@ -60,13 +64,13 @@ where
     #[instrument(level = "debug", skip_all, fields(source = ?self.source))]
     pub(in crate::solve) fn enter(
         self,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
     }
 }
 
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     /// `probe_kind` is only called when proof tree building is enabled so it can be
     /// as expensive as necessary to output the desired information.
     pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T>
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 4933080451d..7291eb00e72 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -380,7 +380,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             source: CandidateSource::Impl(impl_def_id),
             result: _,
         } = candidate.kind()
-            && goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend)
+            && goal
+                .infcx()
+                .tcx
+                .has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
         {
             return ControlFlow::Break(self.obligation.clone());
         }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index e12c66b6928..737d03f73f0 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -11,7 +11,6 @@
 
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
-use rustc_infer::infer::resolve::EagerResolver;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_macros::extension;
 use rustc_middle::traits::query::NoSolution;
@@ -20,6 +19,7 @@ use rustc_middle::traits::solve::{Certainty, Goal};
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{TyCtxt, TypeFoldable};
 use rustc_middle::{bug, ty};
+use rustc_next_trait_solver::resolve::EagerResolver;
 use rustc_span::{Span, DUMMY_SP};
 
 use crate::solve::eval_ctxt::canonical;
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index b085d009d75..60722d3618f 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -15,6 +15,7 @@
 //! about it on zulip.
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_macros::extension;
 use rustc_middle::bug;
@@ -82,7 +83,7 @@ impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> {
     }
 }
 
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self))]
     fn compute_type_outlives_goal(
         &mut self,
@@ -201,7 +202,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self, goals))]
     fn add_goals(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
index 94e078f5615..c9621e705e5 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
@@ -1,8 +1,9 @@
 use crate::solve::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn normalize_anon_const(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
index 353bdb9caff..2146a2c2f08 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
@@ -4,12 +4,13 @@
 //! 1. instantiate generic parameters,
 //! 2. equate the self type, and
 //! 3. instantiate and register where clauses.
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
 use rustc_middle::ty;
 
 use crate::solve::EvalCtxt;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn normalize_inherent_associated_type(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 8c492b62c1a..7ef8373663b 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -5,6 +5,7 @@ use super::assembly::{self, structural_traits, Candidate};
 use super::{EvalCtxt, GoalSource};
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::MaybeCause;
@@ -24,7 +25,7 @@ mod inherent;
 mod opaque_types;
 mod weak_types;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn compute_normalizes_to_goal(
         &mut self,
@@ -98,11 +99,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn probe_and_match_goal_against_assumption(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
-        then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
             if projection_pred.projection_def_id() == goal.predicate.def_id() {
@@ -137,7 +138,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -199,7 +200,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
             };
 
-            let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| {
+            let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| {
                 let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
                 let error_term = match assoc_def.item.kind {
                     ty::AssocKind::Const => ty::Const::new_error(
@@ -279,14 +280,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error`
     /// and succeed. Can experiment with this to figure out what results in better error messages.
     fn consider_error_guaranteed_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         _guar: ErrorGuaranteed,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         Err(NoSolution)
     }
 
     fn consider_auto_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         ecx.tcx().dcx().span_delayed_bug(
@@ -297,42 +298,42 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_trait_alias_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("trait aliases do not have associated types: {:?}", goal);
     }
 
     fn consider_builtin_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Sized` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_copy_clone_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`PointerLike` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_fn_ptr_trait_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`FnPtr` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -375,7 +376,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_async_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -460,7 +461,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_async_fn_kind_helper_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let [
@@ -507,14 +508,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_tuple_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Tuple` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_pointee_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let tcx = ecx.tcx();
@@ -596,7 +597,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_future_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -628,7 +629,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -660,14 +661,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_fused_iterator_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`FusedIterator` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_async_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -703,7 +704,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_coroutine_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -748,14 +749,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_structural_builtin_unsize_candidates(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<Candidate<'tcx>> {
         bug!("`Unsize` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -807,7 +808,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_async_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -860,14 +861,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
     }
 
     fn consider_builtin_destruct_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Destruct` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_transmute_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
@@ -880,7 +881,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
 /// diverge.
 #[instrument(level = "trace", skip(ecx, param_env), ret)]
 fn fetch_eligible_assoc_item_def<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     goal_trait_ref: ty::TraitRef<'tcx>,
     trait_assoc_def_id: DefId,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
index 9fdb280cdc6..3b83d347276 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
@@ -1,6 +1,7 @@
 //! Computes a normalizes-to (projection) goal for opaque types. This goal
 //! behaves differently depending on the param-env's reveal mode and whether
 //! the opaque is in a defining scope.
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::traits::Reveal;
@@ -9,7 +10,7 @@ use rustc_middle::ty::util::NotUniqueParam;
 
 use crate::solve::{EvalCtxt, SolverMode};
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn normalize_opaque_type(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
index 13af5068b6c..109a9e9671f 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
@@ -3,12 +3,13 @@
 //!
 //! Since a weak alias is never ambiguous, this just computes the `type_of` of
 //! the alias and registers the where-clauses of the type alias.
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
 use rustc_middle::ty;
 
 use crate::solve::EvalCtxt;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn normalize_weak_type(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 0f1be1072a8..8fa78e49dc6 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -1,10 +1,11 @@
 use crate::solve::GoalSource;
 
 use super::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty::{self, ProjectionPredicate};
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn compute_projection_goal(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 0164d44667c..bcd210f789b 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -1,18 +1,21 @@
-use crate::solve::FIXPOINT_STEP_LIMIT;
+use std::mem;
 
-use super::inspect;
-use super::inspect::ProofTreeBuilder;
-use super::SolverMode;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::Idx;
 use rustc_index::IndexVec;
 use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::traits::solve::CacheData;
-use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
+use rustc_middle::traits::solve::EvaluationCache;
 use rustc_middle::ty::TyCtxt;
+use rustc_next_trait_solver::solve::{CanonicalInput, Certainty, QueryResult};
 use rustc_session::Limit;
-use std::mem;
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::Interner;
+
+use super::inspect;
+use super::inspect::ProofTreeBuilder;
+use super::SolverMode;
+use crate::solve::FIXPOINT_STEP_LIMIT;
 
 rustc_index::newtype_index! {
     #[orderable]
@@ -30,9 +33,10 @@ bitflags::bitflags! {
     }
 }
 
-#[derive(Debug)]
-struct StackEntry<'tcx> {
-    input: CanonicalInput<'tcx>,
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+struct StackEntry<I: Interner> {
+    input: CanonicalInput<I>,
 
     available_depth: Limit,
 
@@ -43,21 +47,40 @@ struct StackEntry<'tcx> {
     /// Whether this entry is a non-root cycle participant.
     ///
     /// We must not move the result of non-root cycle participants to the
-    /// global cache. See [SearchGraph::cycle_participants] for more details.
-    /// We store the highest stack depth of a head of a cycle this goal is involved
-    /// in. This necessary to soundly cache its provisional result.
+    /// global cache. We store the highest stack depth of a head of a cycle
+    /// this goal is involved in. This necessary to soundly cache its
+    /// provisional result.
     non_root_cycle_participant: Option<StackDepth>,
 
     encountered_overflow: bool,
 
     has_been_used: HasBeenUsed,
+
+    /// We put only the root goal of a coinductive cycle into the global cache.
+    ///
+    /// If we were to use that result when later trying to prove another cycle
+    /// participant, we can end up with unstable query results.
+    ///
+    /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
+    /// an example of where this is needed.
+    ///
+    /// There can  be multiple roots on the same stack, so we need to track
+    /// cycle participants per root:
+    /// ```plain
+    /// A :- B
+    /// B :- A, C
+    /// C :- D
+    /// D :- C
+    /// ```
+    cycle_participants: FxHashSet<CanonicalInput<I>>,
     /// Starts out as `None` and gets set when rerunning this
     /// goal in case we encounter a cycle.
-    provisional_result: Option<QueryResult<'tcx>>,
+    provisional_result: Option<QueryResult<I>>,
 }
 
 /// The provisional result for a goal which is not on the stack.
-struct DetachedEntry<'tcx> {
+#[derive(Debug)]
+struct DetachedEntry<I: Interner> {
     /// The head of the smallest non-trivial cycle involving this entry.
     ///
     /// Given the following rules, when proving `A` the head for
@@ -68,7 +91,7 @@ struct DetachedEntry<'tcx> {
     /// C :- A + B + C
     /// ```
     head: StackDepth,
-    result: QueryResult<'tcx>,
+    result: QueryResult<I>,
 }
 
 /// Stores the stack depth of a currently evaluated goal *and* already
@@ -83,14 +106,15 @@ struct DetachedEntry<'tcx> {
 ///
 /// The provisional cache can theoretically result in changes to the observable behavior,
 /// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs.
-#[derive(Default)]
-struct ProvisionalCacheEntry<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(Default(bound = ""))]
+struct ProvisionalCacheEntry<I: Interner> {
     stack_depth: Option<StackDepth>,
-    with_inductive_stack: Option<DetachedEntry<'tcx>>,
-    with_coinductive_stack: Option<DetachedEntry<'tcx>>,
+    with_inductive_stack: Option<DetachedEntry<I>>,
+    with_coinductive_stack: Option<DetachedEntry<I>>,
 }
 
-impl<'tcx> ProvisionalCacheEntry<'tcx> {
+impl<I: Interner> ProvisionalCacheEntry<I> {
     fn is_empty(&self) -> bool {
         self.stack_depth.is_none()
             && self.with_inductive_stack.is_none()
@@ -98,53 +122,30 @@ impl<'tcx> ProvisionalCacheEntry<'tcx> {
     }
 }
 
-pub(super) struct SearchGraph<'tcx> {
+pub(super) struct SearchGraph<I: Interner> {
     mode: SolverMode,
     /// The stack of goals currently being computed.
     ///
     /// An element is *deeper* in the stack if its index is *lower*.
-    stack: IndexVec<StackDepth, StackEntry<'tcx>>,
-    provisional_cache: FxHashMap<CanonicalInput<'tcx>, ProvisionalCacheEntry<'tcx>>,
-    /// We put only the root goal of a coinductive cycle into the global cache.
-    ///
-    /// If we were to use that result when later trying to prove another cycle
-    /// participant, we can end up with unstable query results.
-    ///
-    /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
-    /// an example of where this is needed.
-    cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
+    stack: IndexVec<StackDepth, StackEntry<I>>,
+    provisional_cache: FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
 }
 
-impl<'tcx> SearchGraph<'tcx> {
-    pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> {
-        Self {
-            mode,
-            stack: Default::default(),
-            provisional_cache: Default::default(),
-            cycle_participants: Default::default(),
-        }
+impl<I: Interner> SearchGraph<I> {
+    pub(super) fn new(mode: SolverMode) -> SearchGraph<I> {
+        Self { mode, stack: Default::default(), provisional_cache: Default::default() }
     }
 
     pub(super) fn solver_mode(&self) -> SolverMode {
         self.mode
     }
 
-    /// Update the stack and reached depths on cache hits.
-    #[instrument(level = "trace", skip(self))]
-    fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
-        let reached_depth = self.stack.next_index().plus(additional_depth);
-        if let Some(last) = self.stack.raw.last_mut() {
-            last.reached_depth = last.reached_depth.max(reached_depth);
-            last.encountered_overflow |= encountered_overflow;
-        }
-    }
-
     /// Pops the highest goal from the stack, lazily updating the
     /// the next goal in the stack.
     ///
     /// Directly popping from the stack instead of using this method
     /// would cause us to not track overflow and recursion depth correctly.
-    fn pop_stack(&mut self) -> StackEntry<'tcx> {
+    fn pop_stack(&mut self) -> StackEntry<I> {
         let elem = self.stack.pop().unwrap();
         if let Some(last) = self.stack.raw.last_mut() {
             last.reached_depth = last.reached_depth.max(elem.reached_depth);
@@ -153,25 +154,8 @@ impl<'tcx> SearchGraph<'tcx> {
         elem
     }
 
-    /// The trait solver behavior is different for coherence
-    /// so we use a separate cache. Alternatively we could use
-    /// a single cache and share it between coherence and ordinary
-    /// trait solving.
-    pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> {
-        match self.mode {
-            SolverMode::Normal => &tcx.new_solver_evaluation_cache,
-            SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache,
-        }
-    }
-
     pub(super) fn is_empty(&self) -> bool {
-        if self.stack.is_empty() {
-            debug_assert!(self.provisional_cache.is_empty());
-            debug_assert!(self.cycle_participants.is_empty());
-            true
-        } else {
-            false
-        }
+        self.stack.is_empty()
     }
 
     /// Returns the remaining depth allowed for nested goals.
@@ -181,8 +165,8 @@ impl<'tcx> SearchGraph<'tcx> {
     /// the remaining depth of all nested goals to prevent hangs
     /// in case there is exponential blowup.
     fn allowed_depth_for_nested(
-        tcx: TyCtxt<'tcx>,
-        stack: &IndexVec<StackDepth, StackEntry<'tcx>>,
+        tcx: I,
+        stack: &IndexVec<StackDepth, StackEntry<I>>,
     ) -> Option<Limit> {
         if let Some(last) = stack.raw.last() {
             if last.available_depth.0 == 0 {
@@ -195,13 +179,13 @@ impl<'tcx> SearchGraph<'tcx> {
                 Limit(last.available_depth.0 - 1)
             })
         } else {
-            Some(tcx.recursion_limit())
+            Some(Limit(tcx.recursion_limit()))
         }
     }
 
     fn stack_coinductive_from(
-        tcx: TyCtxt<'tcx>,
-        stack: &IndexVec<StackDepth, StackEntry<'tcx>>,
+        tcx: I,
+        stack: &IndexVec<StackDepth, StackEntry<I>>,
         head: StackDepth,
     ) -> bool {
         stack.raw[head.index()..]
@@ -220,21 +204,32 @@ impl<'tcx> SearchGraph<'tcx> {
     // we reach a fixpoint and all other cycle participants to make sure that
     // their result does not get moved to the global cache.
     fn tag_cycle_participants(
-        stack: &mut IndexVec<StackDepth, StackEntry<'tcx>>,
-        cycle_participants: &mut FxHashSet<CanonicalInput<'tcx>>,
+        stack: &mut IndexVec<StackDepth, StackEntry<I>>,
         usage_kind: HasBeenUsed,
         head: StackDepth,
     ) {
         stack[head].has_been_used |= usage_kind;
         debug_assert!(!stack[head].has_been_used.is_empty());
-        for entry in &mut stack.raw[head.index() + 1..] {
+
+        // The current root of these cycles. Note that this may not be the final
+        // root in case a later goal depends on a goal higher up the stack.
+        let mut current_root = head;
+        while let Some(parent) = stack[current_root].non_root_cycle_participant {
+            current_root = parent;
+            debug_assert!(!stack[current_root].has_been_used.is_empty());
+        }
+
+        let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1);
+        let current_cycle_root = &mut stack[current_root.as_usize()];
+        for entry in cycle_participants {
             entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
-            cycle_participants.insert(entry.input);
+            current_cycle_root.cycle_participants.insert(entry.input);
+            current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants));
         }
     }
 
     fn clear_dependent_provisional_results(
-        provisional_cache: &mut FxHashMap<CanonicalInput<'tcx>, ProvisionalCacheEntry<'tcx>>,
+        provisional_cache: &mut FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
         head: StackDepth,
     ) {
         #[allow(rustc::potential_query_instability)]
@@ -244,6 +239,19 @@ impl<'tcx> SearchGraph<'tcx> {
             !entry.is_empty()
         });
     }
+}
+
+impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
+    /// The trait solver behavior is different for coherence
+    /// so we use a separate cache. Alternatively we could use
+    /// a single cache and share it between coherence and ordinary
+    /// trait solving.
+    pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> {
+        match self.mode {
+            SolverMode::Normal => &tcx.new_solver_evaluation_cache,
+            SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache,
+        }
+    }
 
     /// Probably the most involved method of the whole solver.
     ///
@@ -252,10 +260,14 @@ impl<'tcx> SearchGraph<'tcx> {
     pub(super) fn with_new_goal(
         &mut self,
         tcx: TyCtxt<'tcx>,
-        input: CanonicalInput<'tcx>,
+        input: CanonicalInput<TyCtxt<'tcx>>,
         inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
-        mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<'tcx>,
-    ) -> QueryResult<'tcx> {
+        mut prove_goal: impl FnMut(
+            &mut Self,
+            &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        ) -> QueryResult<TyCtxt<'tcx>>,
+    ) -> QueryResult<TyCtxt<'tcx>> {
+        self.check_invariants();
         // Check for overflow.
         let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else {
             if let Some(last) = self.stack.raw.last_mut() {
@@ -266,37 +278,7 @@ impl<'tcx> SearchGraph<'tcx> {
             return Self::response_no_constraints(tcx, input, Certainty::overflow(true));
         };
 
-        // Try to fetch the goal from the global cache.
-        'global: {
-            let Some(CacheData { result, proof_tree, reached_depth, encountered_overflow }) =
-                self.global_cache(tcx).get(
-                    tcx,
-                    input,
-                    |cycle_participants| {
-                        self.stack.iter().any(|entry| cycle_participants.contains(&entry.input))
-                    },
-                    available_depth,
-                )
-            else {
-                break 'global;
-            };
-
-            // If we're building a proof tree and the current cache entry does not
-            // contain a proof tree, we do not use the entry but instead recompute
-            // the goal. We simply overwrite the existing entry once we're done,
-            // caching the proof tree.
-            if !inspect.is_noop() {
-                if let Some(revisions) = proof_tree {
-                    inspect.goal_evaluation_kind(
-                        inspect::WipCanonicalGoalEvaluationKind::Interned { revisions },
-                    );
-                } else {
-                    break 'global;
-                }
-            }
-
-            self.on_cache_hit(reached_depth, encountered_overflow);
-            debug!("global cache hit");
+        if let Some(result) = self.lookup_global_cache(tcx, input, available_depth, inspect) {
             return result;
         }
 
@@ -322,12 +304,7 @@ impl<'tcx> SearchGraph<'tcx> {
             // already set correctly while computing the cache entry.
             inspect
                 .goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::ProvisionalCacheHit);
-            Self::tag_cycle_participants(
-                &mut self.stack,
-                &mut self.cycle_participants,
-                HasBeenUsed::empty(),
-                entry.head,
-            );
+            Self::tag_cycle_participants(&mut self.stack, HasBeenUsed::empty(), entry.head);
             return entry.result;
         } else if let Some(stack_depth) = cache_entry.stack_depth {
             debug!("encountered cycle with depth {stack_depth:?}");
@@ -344,12 +321,7 @@ impl<'tcx> SearchGraph<'tcx> {
             } else {
                 HasBeenUsed::INDUCTIVE_CYCLE
             };
-            Self::tag_cycle_participants(
-                &mut self.stack,
-                &mut self.cycle_participants,
-                usage_kind,
-                stack_depth,
-            );
+            Self::tag_cycle_participants(&mut self.stack, usage_kind, stack_depth);
 
             // Return the provisional result or, if we're in the first iteration,
             // start with no constraints.
@@ -370,6 +342,7 @@ impl<'tcx> SearchGraph<'tcx> {
                 non_root_cycle_participant: None,
                 encountered_overflow: false,
                 has_been_used: HasBeenUsed::empty(),
+                cycle_participants: Default::default(),
                 provisional_result: None,
             };
             assert_eq!(self.stack.push(entry), depth);
@@ -378,63 +351,16 @@ impl<'tcx> SearchGraph<'tcx> {
 
         // This is for global caching, so we properly track query dependencies.
         // Everything that affects the `result` should be performed within this
-        // `with_anon_task` closure.
+        // `with_anon_task` closure. If computing this goal depends on something
+        // not tracked by the cache key and from outside of this anon task, it
+        // must not be added to the global cache. Notably, this is the case for
+        // trait solver cycles participants.
         let ((final_entry, result), dep_node) =
             tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || {
-                // When we encounter a coinductive cycle, we have to fetch the
-                // result of that cycle while we are still computing it. Because
-                // of this we continuously recompute the cycle until the result
-                // of the previous iteration is equal to the final result, at which
-                // point we are done.
                 for _ in 0..FIXPOINT_STEP_LIMIT {
-                    let result = prove_goal(self, inspect);
-                    let stack_entry = self.pop_stack();
-                    debug_assert_eq!(stack_entry.input, input);
-
-                    // If the current goal is not the root of a cycle, we are done.
-                    if stack_entry.has_been_used.is_empty() {
-                        return (stack_entry, result);
-                    }
-
-                    // If it is a cycle head, we have to keep trying to prove it until
-                    // we reach a fixpoint. We need to do so for all cycle heads,
-                    // not only for the root.
-                    //
-                    // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
-                    // for an example.
-
-                    // Start by clearing all provisional cache entries which depend on this
-                    // the current goal.
-                    Self::clear_dependent_provisional_results(
-                        &mut self.provisional_cache,
-                        self.stack.next_index(),
-                    );
-
-                    // Check whether we reached a fixpoint, either because the final result
-                    // is equal to the provisional result of the previous iteration, or because
-                    // this was only the root of either coinductive or inductive cycles, and the
-                    // final result is equal to the initial response for that case.
-                    let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
-                        r == result
-                    } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
-                        Self::response_no_constraints(tcx, input, Certainty::Yes) == result
-                    } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
-                        Self::response_no_constraints(tcx, input, Certainty::overflow(false))
-                            == result
-                    } else {
-                        false
-                    };
-
-                    // If we did not reach a fixpoint, update the provisional result and reevaluate.
-                    if reached_fixpoint {
-                        return (stack_entry, result);
-                    } else {
-                        let depth = self.stack.push(StackEntry {
-                            has_been_used: HasBeenUsed::empty(),
-                            provisional_result: Some(result),
-                            ..stack_entry
-                        });
-                        debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
+                    match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) {
+                        StepResult::Done(final_entry, result) => return (final_entry, result),
+                        StepResult::HasChanged => {}
                     }
                 }
 
@@ -463,14 +389,13 @@ impl<'tcx> SearchGraph<'tcx> {
         } else {
             self.provisional_cache.remove(&input);
             let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len();
-            let cycle_participants = mem::take(&mut self.cycle_participants);
             // When encountering a cycle, both inductive and coinductive, we only
             // move the root into the global cache. We also store all other cycle
             // participants involved.
             //
             // We must not use the global cache entry of a root goal if a cycle
             // participant is on the stack. This is necessary to prevent unstable
-            // results. See the comment of `SearchGraph::cycle_participants` for
+            // results. See the comment of `StackEntry::cycle_participants` for
             // more details.
             self.global_cache(tcx).insert(
                 tcx,
@@ -478,20 +403,208 @@ impl<'tcx> SearchGraph<'tcx> {
                 proof_tree,
                 reached_depth,
                 final_entry.encountered_overflow,
-                cycle_participants,
+                final_entry.cycle_participants,
                 dep_node,
                 result,
             )
         }
 
+        self.check_invariants();
+
         result
     }
 
+    /// Try to fetch a previously computed result from the global cache,
+    /// making sure to only do so if it would match the result of reevaluating
+    /// this goal.
+    fn lookup_global_cache(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        input: CanonicalInput<TyCtxt<'tcx>>,
+        available_depth: Limit,
+        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+    ) -> Option<QueryResult<TyCtxt<'tcx>>> {
+        let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self
+            .global_cache(tcx)
+            .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth)?;
+
+        // If we're building a proof tree and the current cache entry does not
+        // contain a proof tree, we do not use the entry but instead recompute
+        // the goal. We simply overwrite the existing entry once we're done,
+        // caching the proof tree.
+        if !inspect.is_noop() {
+            if let Some(revisions) = proof_tree {
+                let kind = inspect::WipCanonicalGoalEvaluationKind::Interned { revisions };
+                inspect.goal_evaluation_kind(kind);
+            } else {
+                return None;
+            }
+        }
+
+        // Update the reached depth of the current goal to make sure
+        // its state is the same regardless of whether we've used the
+        // global cache or not.
+        let reached_depth = self.stack.next_index().plus(additional_depth);
+        if let Some(last) = self.stack.raw.last_mut() {
+            last.reached_depth = last.reached_depth.max(reached_depth);
+            last.encountered_overflow |= encountered_overflow;
+        }
+
+        Some(result)
+    }
+}
+
+enum StepResult<I: Interner> {
+    Done(StackEntry<I>, QueryResult<I>),
+    HasChanged,
+}
+
+impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
+    /// When we encounter a coinductive cycle, we have to fetch the
+    /// result of that cycle while we are still computing it. Because
+    /// of this we continuously recompute the cycle until the result
+    /// of the previous iteration is equal to the final result, at which
+    /// point we are done.
+    fn fixpoint_step_in_task<F>(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        input: CanonicalInput<TyCtxt<'tcx>>,
+        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        prove_goal: &mut F,
+    ) -> StepResult<TyCtxt<'tcx>>
+    where
+        F: FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>,
+    {
+        let result = prove_goal(self, inspect);
+        let stack_entry = self.pop_stack();
+        debug_assert_eq!(stack_entry.input, input);
+
+        // If the current goal is not the root of a cycle, we are done.
+        if stack_entry.has_been_used.is_empty() {
+            return StepResult::Done(stack_entry, result);
+        }
+
+        // If it is a cycle head, we have to keep trying to prove it until
+        // we reach a fixpoint. We need to do so for all cycle heads,
+        // not only for the root.
+        //
+        // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
+        // for an example.
+
+        // Start by clearing all provisional cache entries which depend on this
+        // the current goal.
+        Self::clear_dependent_provisional_results(
+            &mut self.provisional_cache,
+            self.stack.next_index(),
+        );
+
+        // Check whether we reached a fixpoint, either because the final result
+        // is equal to the provisional result of the previous iteration, or because
+        // this was only the root of either coinductive or inductive cycles, and the
+        // final result is equal to the initial response for that case.
+        let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
+            r == result
+        } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
+            Self::response_no_constraints(tcx, input, Certainty::Yes) == result
+        } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
+            Self::response_no_constraints(tcx, input, Certainty::overflow(false)) == result
+        } else {
+            false
+        };
+
+        // If we did not reach a fixpoint, update the provisional result and reevaluate.
+        if reached_fixpoint {
+            StepResult::Done(stack_entry, result)
+        } else {
+            let depth = self.stack.push(StackEntry {
+                has_been_used: HasBeenUsed::empty(),
+                provisional_result: Some(result),
+                ..stack_entry
+            });
+            debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
+            StepResult::HasChanged
+        }
+    }
+
     fn response_no_constraints(
         tcx: TyCtxt<'tcx>,
-        goal: CanonicalInput<'tcx>,
+        goal: CanonicalInput<TyCtxt<'tcx>>,
         certainty: Certainty,
-    ) -> QueryResult<'tcx> {
+    ) -> QueryResult<TyCtxt<'tcx>> {
         Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty))
     }
 }
+
+impl<I: Interner> SearchGraph<I> {
+    #[allow(rustc::potential_query_instability)]
+    fn check_invariants(&self) {
+        if !cfg!(debug_assertions) {
+            return;
+        }
+
+        let SearchGraph { mode: _, stack, provisional_cache } = self;
+        if stack.is_empty() {
+            assert!(provisional_cache.is_empty());
+        }
+
+        for (depth, entry) in stack.iter_enumerated() {
+            let StackEntry {
+                input,
+                available_depth: _,
+                reached_depth: _,
+                non_root_cycle_participant,
+                encountered_overflow: _,
+                has_been_used,
+                ref cycle_participants,
+                provisional_result,
+            } = *entry;
+            let cache_entry = provisional_cache.get(&entry.input).unwrap();
+            assert_eq!(cache_entry.stack_depth, Some(depth));
+            if let Some(head) = non_root_cycle_participant {
+                assert!(head < depth);
+                assert!(cycle_participants.is_empty());
+                assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
+
+                let mut current_root = head;
+                while let Some(parent) = stack[current_root].non_root_cycle_participant {
+                    current_root = parent;
+                }
+                assert!(stack[current_root].cycle_participants.contains(&input));
+            }
+
+            if !cycle_participants.is_empty() {
+                assert!(provisional_result.is_some() || !has_been_used.is_empty());
+                for entry in stack.iter().take(depth.as_usize()) {
+                    assert_eq!(cycle_participants.get(&entry.input), None);
+                }
+            }
+        }
+
+        for (&input, entry) in &self.provisional_cache {
+            let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } =
+                entry;
+            assert!(
+                stack_depth.is_some()
+                    || with_coinductive_stack.is_some()
+                    || with_inductive_stack.is_some()
+            );
+
+            if let &Some(stack_depth) = stack_depth {
+                assert_eq!(stack[stack_depth].input, input);
+            }
+
+            let check_detached = |detached_entry: &DetachedEntry<I>| {
+                let DetachedEntry { head, result: _ } = *detached_entry;
+                assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
+            };
+
+            if let Some(with_coinductive_stack) = with_coinductive_stack {
+                check_detached(with_coinductive_stack);
+            }
+
+            if let Some(with_inductive_stack) = with_inductive_stack {
+                check_detached(with_inductive_stack);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 9139c75d399..e59eef22f41 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -8,6 +8,7 @@ use super::{EvalCtxt, GoalSource, SolverMode};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::MaybeCause;
 use rustc_middle::bug;
@@ -37,7 +38,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -93,7 +94,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_error_guaranteed_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         _guar: ErrorGuaranteed,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         // FIXME: don't need to enter a probe here.
@@ -102,11 +103,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn probe_and_match_goal_against_assumption(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
-        then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if let Some(trait_clause) = assumption.as_trait_clause() {
             if trait_clause.def_id() == goal.predicate.def_id()
@@ -130,7 +131,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_auto_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -173,7 +174,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_trait_alias_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -196,7 +197,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_sized_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -211,7 +212,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_copy_clone_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -226,7 +227,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -256,7 +257,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_fn_ptr_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -287,7 +288,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -328,7 +329,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_async_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -379,7 +380,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_async_fn_kind_helper_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
@@ -406,7 +407,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     /// impl Tuple for (T1, .., Tn) {}
     /// ```
     fn consider_builtin_tuple_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -422,7 +423,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_pointee_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -434,7 +435,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_future_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -460,7 +461,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -486,7 +487,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_fused_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -510,7 +511,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_async_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -536,7 +537,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_coroutine_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -568,7 +569,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -581,7 +582,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_async_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -594,7 +595,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -610,7 +611,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 
     fn consider_builtin_transmute_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -651,7 +652,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     /// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {}
     /// ```
     fn consider_structural_builtin_unsize_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<Candidate<'tcx>> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -722,7 +723,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     /// Trait upcasting allows for coercions between trait objects:
     /// ```ignore (builtin impl example)
     /// trait Super {}
@@ -846,7 +847,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // having any inference side-effects. We process obligations because
         // unification may initially succeed due to deferred projection equality.
         let projection_may_match =
-            |ecx: &mut EvalCtxt<'_, 'tcx>,
+            |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
              source_projection: ty::PolyExistentialProjection<'tcx>,
              target_projection: ty::PolyExistentialProjection<'tcx>| {
                 source_projection.item_def_id() == target_projection.item_def_id()
@@ -1152,7 +1153,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         source: CandidateSource<'tcx>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         constituent_tys: impl Fn(
-            &EvalCtxt<'_, 'tcx>,
+            &EvalCtxt<'_, InferCtxt<'tcx>>,
             Ty<'tcx>,
         ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index d693bac90dc..494fca0336c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -422,6 +422,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+                        let trait_predicate = self.apply_do_not_recommend(trait_predicate, &mut obligation);
 
                         // Let's use the root obligation as the main message, when we care about the
                         // most general case ("X doesn't implement Pattern<'_>") over the case that
@@ -1003,6 +1004,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         err.emit()
     }
 
+    fn apply_do_not_recommend(
+        &self,
+        mut trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+        obligation: &'_ mut PredicateObligation<'tcx>,
+    ) -> ty::Binder<'tcx, ty::TraitPredicate<'tcx>> {
+        let mut base_cause = obligation.cause.code().clone();
+        loop {
+            if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
+                if self.tcx.has_attrs_with_path(
+                    c.impl_or_alias_def_id,
+                    &[sym::diagnostic, sym::do_not_recommend],
+                ) {
+                    let code = (*c.derived.parent_code).clone();
+                    obligation.cause.map_code(|_| code);
+                    obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
+                    trait_predicate = c.derived.parent_trait_pred.clone();
+                }
+            }
+            if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
+                base_cause = parent_cause.clone();
+            } else {
+                break;
+            }
+        }
+
+        trait_predicate
+    }
+
     fn emit_specialized_closure_kind_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index abb19c7efd8..8ce1271fc17 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -398,7 +398,7 @@ pub fn object_safety_violations_for_assoc_item(
         // Associated types can only be object safe if they have `Self: Sized` bounds.
         ty::AssocKind::Type => {
             if !tcx.features().generic_associated_types_extended
-                && !tcx.generics_of(item.def_id).own_params.is_empty()
+                && !tcx.generics_of(item.def_id).is_own_empty()
                 && !item.is_impl_trait_in_trait()
             {
                 vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)]
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 65048ffdfba..c684f087d32 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -619,7 +619,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // higher-ranked things.
             // Prevent, e.g., `dyn Iterator<Item = str>`.
             for bound in self.tcx().item_bounds(assoc_type).transpose_iter() {
-                let arg_bound = if defs.count() == 0 {
+                let arg_bound = if defs.is_empty() {
                     bound.instantiate(tcx, trait_predicate.trait_ref.args)
                 } else {
                     let mut args = smallvec::SmallVec::with_capacity(defs.count());
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 19affac7970..4a94643d908 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1781,7 +1781,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // FIXME(generic-associated-types): This only detects one layer of inference,
             // which is probably not what we actually want, but fixing it causes some ambiguity:
             // <https://github.com/rust-lang/rust/issues/125196>.
-            if !generics.own_params.is_empty()
+            if !generics.is_own_empty()
                 && obligation.predicate.args[generics.parent_count..].iter().any(|&p| {
                     p.has_non_region_infer()
                         && match p.unpack() {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index fec02f515ca..b40a0d0a58e 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -81,9 +81,9 @@ fn destructure_const<'tcx>(
 fn check_binop(op: mir::BinOp) -> bool {
     use mir::BinOp::*;
     match op {
-        Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
-        | BitAnd | BitOr | Shl | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge
-        | Gt | Cmp => true,
+        Add | AddUnchecked | AddWithOverflow | Sub | SubUnchecked | SubWithOverflow | Mul
+        | MulUnchecked | MulWithOverflow | Div | Rem | BitXor | BitAnd | BitOr | Shl
+        | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge | Gt | Cmp => true,
         Offset => false,
     }
 }
diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs
index 9298360f749..4e8be1ee4c2 100644
--- a/compiler/rustc_type_ir/src/debug.rs
+++ b/compiler/rustc_type_ir/src/debug.rs
@@ -1,4 +1,6 @@
-use crate::{ConstVid, InferCtxtLike, Interner, TyVid, UniverseIndex};
+use crate::{
+    ConstVid, EffectVid, FloatVid, InferCtxtLike, IntVid, Interner, RegionVid, TyVid, UniverseIndex,
+};
 
 use core::fmt;
 use std::marker::PhantomData;
@@ -16,7 +18,7 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> {
         None
     }
 
-    fn universe_of_lt(&self, _lt: I::InferRegion) -> Option<UniverseIndex> {
+    fn universe_of_lt(&self, _lt: RegionVid) -> Option<UniverseIndex> {
         None
     }
 
@@ -24,27 +26,31 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> {
         None
     }
 
-    fn root_ty_var(&self, vid: TyVid) -> TyVid {
-        vid
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> I::Ty {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn probe_ty_var(&self, _vid: TyVid) -> Option<I::Ty> {
-        None
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> I::Ty {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn opportunistic_resolve_lt_var(&self, _vid: I::InferRegion) -> Option<I::Region> {
-        None
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> I::Ty {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
-        vid
+    fn opportunistic_resolve_ct_var(&self, vid: ConstVid, _: I::Ty) -> I::Const {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> {
-        None
+    fn opportunistic_resolve_effect_var(&self, vid: EffectVid, _: I::Ty) -> I::Const {
+        panic!("cannot resolve {vid:?}")
+    }
+
+    fn opportunistic_resolve_lt_var(&self, vid: crate::RegionVid) -> I::Region {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes {
+    fn defining_opaque_types(&self) -> I::DefiningOpaqueTypes {
         Default::default()
     }
 }
diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs
index 622a4080608..cc8c4444657 100644
--- a/compiler/rustc_type_ir/src/generic_arg.rs
+++ b/compiler/rustc_type_ir/src/generic_arg.rs
@@ -16,3 +16,17 @@ pub enum GenericArgKind<I: Interner> {
     Type(I::Ty),
     Const(I::Const),
 }
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Debug(bound = ""),
+    Eq(bound = ""),
+    PartialEq(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum TermKind<I: Interner> {
+    Ty(I::Ty),
+    Const(I::Const),
+}
diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs
index a53287c1987..bb5081fb335 100644
--- a/compiler/rustc_type_ir/src/infcx.rs
+++ b/compiler/rustc_type_ir/src/infcx.rs
@@ -1,4 +1,4 @@
-use crate::{ConstVid, Interner, TyVid, UniverseIndex};
+use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex};
 
 pub trait InferCtxtLike {
     type Interner: Interner;
@@ -6,37 +6,23 @@ pub trait InferCtxtLike {
     fn interner(&self) -> Self::Interner;
 
     fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
+    fn universe_of_lt(&self, lt: RegionVid) -> Option<UniverseIndex>;
+    fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
 
-    /// Resolve `TyVid` to its root `TyVid`.
-    fn root_ty_var(&self, vid: TyVid) -> TyVid;
-
-    /// Resolve `TyVid` to its inferred type, if it has been equated with a non-infer type.
-    fn probe_ty_var(&self, vid: TyVid) -> Option<<Self::Interner as Interner>::Ty>;
-
-    fn universe_of_lt(
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_ct_var(
         &self,
-        lt: <Self::Interner as Interner>::InferRegion,
-    ) -> Option<UniverseIndex>;
-
-    /// Resolve `InferRegion` to its inferred region, if it has been equated with
-    /// a non-infer region.
-    ///
-    /// FIXME: This has slightly different semantics than `{probe,resolve}_{ty,ct}_var`,
-    /// that has to do with the fact unlike `Ty` or `Const` vars, in rustc, we may
-    /// not always be able to *name* the root region var from the universe of the
-    /// var we're trying to resolve. That's why it's called *opportunistic*.
-    fn opportunistic_resolve_lt_var(
+        vid: ConstVid,
+        ty: <Self::Interner as Interner>::Ty,
+    ) -> <Self::Interner as Interner>::Const;
+    fn opportunistic_resolve_effect_var(
         &self,
-        vid: <Self::Interner as Interner>::InferRegion,
-    ) -> Option<<Self::Interner as Interner>::Region>;
-
-    fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
-
-    /// Resolve `ConstVid` to its root `ConstVid`.
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid;
-
-    /// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type.
-    fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>;
+        vid: EffectVid,
+        ty: <Self::Interner as Interner>::Ty,
+    ) -> <Self::Interner as Interner>::Const;
+    fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region;
 
     fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
 }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 5289dfd932f..f66c6e722f7 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -7,11 +7,11 @@ use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
 
-use crate::fold::TypeSuperFoldable;
+use crate::fold::{TypeFoldable, TypeSuperFoldable};
 use crate::visit::{Flags, TypeSuperVisitable};
 use crate::{
-    AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind,
-    TyKind, UnevaluatedConst, UniverseIndex,
+    AliasTy, AliasTyKind, BoundVar, ConstKind, ConstVid, DebruijnIndex, DebugWithInfcx, InferConst,
+    InferTy, Interner, RegionKind, TyKind, TyVid, UnevaluatedConst, UniverseIndex,
 };
 
 pub trait Ty<I: Interner<Ty = Self>>:
@@ -28,6 +28,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
 {
     fn new_bool(interner: I) -> Self;
 
+    fn new_infer(interner: I, var: InferTy) -> Self;
+
+    fn new_var(interner: I, var: TyVid) -> Self;
+
     fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
 
     fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self;
@@ -68,6 +72,10 @@ pub trait Const<I: Interner<Const = Self>>:
     + TypeSuperFoldable<I>
     + Flags
 {
+    fn new_infer(interner: I, var: InferConst, ty: I::Ty) -> Self;
+
+    fn new_var(interner: I, var: ConstVid, ty: I::Ty) -> Self;
+
     fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
 
     fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self;
@@ -87,6 +95,7 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
     + IntoIterator<Item = I::GenericArg>
     + Deref<Target: Deref<Target = [I::GenericArg]>>
     + Default
+    + TypeFoldable<I>
 {
     fn type_at(self, i: usize) -> I::Ty;
 
@@ -96,6 +105,7 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
 pub trait Predicate<I: Interner<Predicate = Self>>:
     Copy + Debug + Hash + Eq + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags
 {
+    fn is_coinductive(self, interner: I) -> bool;
 }
 
 /// Common capabilities of placeholder kinds
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 9acf7c04dd6..6516d5b1645 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -10,7 +10,7 @@ use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
     AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
     DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind,
-    NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
+    NormalizesTo, ProjectionPredicate, SubtypePredicate, TermKind, TraitPredicate, TraitRef,
 };
 
 pub trait Interner:
@@ -36,7 +36,7 @@ pub trait Interner:
     /// not including the args from the parent item (trait or impl).
     type OwnItemArgs: Copy + Debug + Hash + Eq;
     type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq + IntoKind<Kind = GenericArgKind<Self>>;
-    type Term: Copy + Debug + Hash + Eq;
+    type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>>;
 
     type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
     type BoundVars: IntoIterator<Item = Self::BoundVar>;
@@ -79,7 +79,6 @@ pub trait Interner:
     type EarlyParamRegion: Copy + Debug + Hash + Eq;
     type LateParamRegion: Copy + Debug + Hash + Eq;
     type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
-    type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type PlaceholderRegion: PlaceholderLike;
 
     // Predicates
@@ -124,6 +123,8 @@ pub trait Interner:
     ) -> Self::GenericArgs;
 
     fn parent(self, def_id: Self::DefId) -> Self::DefId;
+
+    fn recursion_limit(self) -> usize;
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index eaae4ee0130..48ade273289 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -1,13 +1,35 @@
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
-use rustc_macros::{TyDecodable, TyEncodable};
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use std::fmt;
 
 use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
 
 use self::RegionKind::*;
 
+rustc_index::newtype_index! {
+    /// A **region** **v**ariable **ID**.
+    #[encodable]
+    #[orderable]
+    #[debug_format = "'?{}"]
+    #[gate_rustc_only]
+    #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+    pub struct RegionVid {}
+}
+
+impl<I: Interner> DebugWithInfcx<I> for RegionVid {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut core::fmt::Formatter<'_>,
+    ) -> core::fmt::Result {
+        match this.infcx.universe_of_lt(*this.data) {
+            Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
+            None => write!(f, "{:?}", this.data),
+        }
+    }
+}
+
 /// Representation of regions. Note that the NLL checker uses a distinct
 /// representation of regions. For this reason, it internally replaces all the
 /// regions with inference variables -- the index of the variable is then used
@@ -152,7 +174,7 @@ pub enum RegionKind<I: Interner> {
     ReStatic,
 
     /// A region variable. Should not exist outside of type inference.
-    ReVar(I::InferRegion),
+    ReVar(RegionVid),
 
     /// A placeholder region -- the higher-ranked version of `ReLateParam`.
     /// Should not exist outside of type inference.
@@ -251,7 +273,6 @@ where
     I::EarlyParamRegion: HashStable<CTX>,
     I::BoundRegion: HashStable<CTX>,
     I::LateParamRegion: HashStable<CTX>,
-    I::InferRegion: HashStable<CTX>,
     I::PlaceholderRegion: HashStable<CTX>,
 {
     #[inline]
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 759e3f166bd..321c56b623a 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1205,6 +1205,7 @@ pub struct TraitDecl {
     pub is_marker: bool,
     pub is_coinductive: bool,
     pub skip_array_during_method_dispatch: bool,
+    pub skip_boxed_slice_during_method_dispatch: bool,
     pub specialization_kind: TraitSpecializationKind,
     pub must_implement_one_of: Option<Vec<Ident>>,
     pub implement_via_object: bool,
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index e8afed6b35a..2e7fcb9dbd3 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -37,4 +37,6 @@ compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
 compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
 compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"]
 # Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = []
+panic_immediate_abort = ["core/panic_immediate_abort"]
+# Choose algorithms that are optimized for binary size instead of runtime performance
+optimize_for_size = ["core/optimize_for_size"]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f1a6df94e11..21d00503001 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -135,6 +135,45 @@
 //! is not allowed. For more guidance on working with box from unsafe code, see
 //! [rust-lang/unsafe-code-guidelines#326][ucg#326].
 //!
+//! # Editions
+//!
+//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021
+//! edition, as documented [here][array]. Unfortunately, it was later found that a similar
+//! workaround should be added for boxed slices, and this was applied in the 2024 edition.
+//!
+//! Specifically, `IntoIterator` is implemented for `Box<[T]>` on all editions, but specific calls
+//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before
+//! 2024:
+//!
+#![cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")]
+#![cfg_attr(not(bootstrap), doc = "```rust,edition2021")]
+//! // Rust 2015, 2018, and 2021:
+//!
+//! # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)`
+//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice();
+//!
+//! // This creates a slice iterator, producing references to each value.
+//! for item in boxed_slice.into_iter().enumerate() {
+//!     let (i, x): (usize, &i32) = item;
+//!     println!("boxed_slice[{i}] = {x}");
+//! }
+//!
+//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility:
+//! for item in boxed_slice.iter().enumerate() {
+//!     let (i, x): (usize, &i32) = item;
+//!     println!("boxed_slice[{i}] = {x}");
+//! }
+//!
+//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter`
+//! for item in IntoIterator::into_iter(boxed_slice).enumerate() {
+//!     let (i, x): (usize, i32) = item;
+//!     println!("boxed_slice[{i}] = {x}");
+//! }
+//! ```
+//!
+//! Similar to the array implementation, this may be modified in the future to remove this override,
+//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve
+//! compatibility with future versions of the compiler.
 //!
 //! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
 //! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
@@ -165,6 +204,7 @@ use core::ops::{
 };
 use core::pin::Pin;
 use core::ptr::{self, addr_of_mut, NonNull, Unique};
+use core::slice;
 use core::task::{Context, Poll};
 
 #[cfg(not(no_global_oom_handling))]
@@ -177,6 +217,7 @@ use crate::raw_vec::RawVec;
 use crate::str::from_boxed_utf8_unchecked;
 #[cfg(not(no_global_oom_handling))]
 use crate::string::String;
+use crate::vec;
 #[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
@@ -2080,6 +2121,51 @@ impl<I> FromIterator<I> for Box<[I]> {
     }
 }
 
+/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<I, A: Allocator> !Iterator for Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
+
+// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
+// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
+// so those calls will still resolve to the slice implementation, by reference.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<I, A: Allocator> IntoIterator for Box<[I], A> {
+    type IntoIter = vec::IntoIter<I, A>;
+    type Item = I;
+    fn into_iter(self) -> vec::IntoIter<I, A> {
+        self.into_vec().into_iter()
+    }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
+    type IntoIter = slice::Iter<'a, I>;
+    type Item = &'a I;
+    fn into_iter(self) -> slice::Iter<'a, I> {
+        self.iter()
+    }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
+    type IntoIter = slice::IterMut<'a, I>;
+    type Item = &'a mut I;
+    fn into_iter(self) -> slice::IterMut<'a, I> {
+        self.iter_mut()
+    }
+}
+
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
 impl FromIterator<char> for Box<str> {
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index f143e557871..b13af93d06c 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -910,6 +910,19 @@ impl From<&CStr> for Rc<CStr> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Rc<CStr> {
+    /// Creates an empty CStr inside an Rc
+    ///
+    /// This may or may not share an allocation with other Rcs on the same thread.
+    #[inline]
+    fn default() -> Self {
+        let c_str: &CStr = Default::default();
+        Rc::from(c_str)
+    }
+}
+
 #[cfg(not(test))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<CStr> {
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 91b83cfe011..4ac0c9b15be 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -160,6 +160,7 @@
 #![feature(tuple_trait)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
+#![feature(unwrap_infallible)]
 #![feature(vec_pop_if)]
 // tidy-alphabetical-end
 //
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 45b20535675..875c24c28e4 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1356,6 +1356,33 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
         ptr
     }
 
+    /// Consumes the `Rc`, returning the wrapped pointer and allocator.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Rc` using
+    /// [`Rc::from_raw_in`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// use std::rc::Rc;
+    /// use std::alloc::System;
+    ///
+    /// let x = Rc::new_in("hello".to_owned(), System);
+    /// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
+    /// assert_eq!(unsafe { &*ptr }, "hello");
+    /// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
+    /// assert_eq!(&*x, "hello");
+    /// ```
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(this);
+        let ptr = Self::as_ptr(&this);
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
+        (ptr, alloc)
+    }
+
     /// Provides a raw pointer to the data.
     ///
     /// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -2224,6 +2251,31 @@ impl<T: Default> Default for Rc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Rc<str> {
+    /// Creates an empty str inside an Rc
+    ///
+    /// This may or may not share an allocation with other Rcs on the same thread.
+    #[inline]
+    fn default() -> Self {
+        Rc::from("")
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for Rc<[T]> {
+    /// Creates an empty `[T]` inside an Rc
+    ///
+    /// This may or may not share an allocation with other Rcs on the same thread.
+    #[inline]
+    fn default() -> Self {
+        let arr: [T; 0] = [];
+        Rc::from(arr)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 trait RcEqIdent<T: ?Sized + PartialEq, A: Allocator> {
     fn eq(&self, other: &Rc<T, A>) -> bool;
@@ -2999,11 +3051,11 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
         result
     }
 
-    /// Consumes the `Weak<T>` and turns it into a raw pointer.
+    /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
     ///
     /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
     /// one weak reference (the weak count is not modified by this operation). It can be turned
-    /// back into the `Weak<T>` with [`from_raw`].
+    /// back into the `Weak<T>` with [`from_raw_in`].
     ///
     /// The same restrictions of accessing the target of the pointer as with
     /// [`as_ptr`] apply.
@@ -3011,27 +3063,30 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(allocator_api)]
     /// use std::rc::{Rc, Weak};
+    /// use std::alloc::System;
     ///
-    /// let strong = Rc::new("hello".to_owned());
+    /// let strong = Rc::new_in("hello".to_owned(), System);
     /// let weak = Rc::downgrade(&strong);
-    /// let raw = weak.into_raw();
+    /// let (raw, alloc) = weak.into_raw_with_allocator();
     ///
     /// assert_eq!(1, Rc::weak_count(&strong));
     /// assert_eq!("hello", unsafe { &*raw });
     ///
-    /// drop(unsafe { Weak::from_raw(raw) });
+    /// drop(unsafe { Weak::from_raw_in(raw, alloc) });
     /// assert_eq!(0, Rc::weak_count(&strong));
     /// ```
     ///
-    /// [`from_raw`]: Weak::from_raw
+    /// [`from_raw_in`]: Weak::from_raw_in
     /// [`as_ptr`]: Weak::as_ptr
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn into_raw_and_alloc(self) -> (*const T, A) {
-        let rc = mem::ManuallyDrop::new(self);
-        let result = rc.as_ptr();
-        let alloc = unsafe { ptr::read(&rc.alloc) };
+    pub fn into_raw_with_allocator(self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(self);
+        let result = this.as_ptr();
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
         (result, alloc)
     }
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index a35c99849b3..7dcaa59dcd1 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1496,6 +1496,34 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
         ptr
     }
 
+    /// Consumes the `Arc`, returning the wrapped pointer and allocator.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Arc` using
+    /// [`Arc::from_raw_in`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// use std::sync::Arc;
+    /// use std::alloc::System;
+    ///
+    /// let x = Arc::new_in("hello".to_owned(), System);
+    /// let (ptr, alloc) = Arc::into_raw_with_allocator(x);
+    /// assert_eq!(unsafe { &*ptr }, "hello");
+    /// let x = unsafe { Arc::from_raw_in(ptr, alloc) };
+    /// assert_eq!(&*x, "hello");
+    /// ```
+    #[must_use = "losing the pointer will leak memory"]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(this);
+        let ptr = Self::as_ptr(&this);
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
+        (ptr, alloc)
+    }
+
     /// Provides a raw pointer to the data.
     ///
     /// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
@@ -2468,6 +2496,14 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Arc<T, A> {
         // [2]: (https://github.com/rust-lang/rust/pull/41714)
         acquire!(self.inner().strong);
 
+        // Make sure we aren't trying to "drop" the shared static for empty slices
+        // used by Default::default.
+        debug_assert!(
+            !ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner),
+            "Arcs backed by a static should never reach a strong count of 0. \
+            Likely decrement_strong_count or from_raw were called too many times.",
+        );
+
         unsafe {
             self.drop_slow();
         }
@@ -2740,6 +2776,45 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
         result
     }
 
+    /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
+    ///
+    /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
+    /// one weak reference (the weak count is not modified by this operation). It can be turned
+    /// back into the `Weak<T>` with [`from_raw_in`].
+    ///
+    /// The same restrictions of accessing the target of the pointer as with
+    /// [`as_ptr`] apply.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// use std::sync::{Arc, Weak};
+    /// use std::alloc::System;
+    ///
+    /// let strong = Arc::new_in("hello".to_owned(), System);
+    /// let weak = Arc::downgrade(&strong);
+    /// let (raw, alloc) = weak.into_raw_with_allocator();
+    ///
+    /// assert_eq!(1, Arc::weak_count(&strong));
+    /// assert_eq!("hello", unsafe { &*raw });
+    ///
+    /// drop(unsafe { Weak::from_raw_in(raw, alloc) });
+    /// assert_eq!(0, Arc::weak_count(&strong));
+    /// ```
+    ///
+    /// [`from_raw_in`]: Weak::from_raw_in
+    /// [`as_ptr`]: Weak::as_ptr
+    #[must_use = "losing the pointer will leak memory"]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn into_raw_with_allocator(self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(self);
+        let result = this.as_ptr();
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
+        (result, alloc)
+    }
+
     /// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
     /// allocator.
     ///
@@ -3059,6 +3134,15 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak<T, A> {
 
         if inner.weak.fetch_sub(1, Release) == 1 {
             acquire!(inner.weak);
+
+            // Make sure we aren't trying to "deallocate" the shared static for empty slices
+            // used by Default::default.
+            debug_assert!(
+                !ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner),
+                "Arc/Weaks backed by a static should never be deallocated. \
+                Likely decrement_strong_count or from_raw were called too many times.",
+            );
+
             unsafe {
                 self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()))
             }
@@ -3300,6 +3384,89 @@ impl<T: Default> Default for Arc<T> {
     }
 }
 
+/// Struct to hold the static `ArcInner` used for empty `Arc<str/CStr/[T]>` as
+/// returned by `Default::default`.
+///
+/// Layout notes:
+/// * `repr(align(16))` so we can use it for `[T]` with `align_of::<T>() <= 16`.
+/// * `repr(C)` so `inner` is at offset 0 (and thus guaranteed to actually be aligned to 16).
+/// * `[u8; 1]` (to be initialized with 0) so it can be used for `Arc<CStr>`.
+#[repr(C, align(16))]
+struct SliceArcInnerForStatic {
+    inner: ArcInner<[u8; 1]>,
+}
+#[cfg(not(no_global_oom_handling))]
+const MAX_STATIC_INNER_SLICE_ALIGNMENT: usize = 16;
+
+static STATIC_INNER_SLICE: SliceArcInnerForStatic = SliceArcInnerForStatic {
+    inner: ArcInner {
+        strong: atomic::AtomicUsize::new(1),
+        weak: atomic::AtomicUsize::new(1),
+        data: [0],
+    },
+};
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Arc<str> {
+    /// Creates an empty str inside an Arc
+    ///
+    /// This may or may not share an allocation with other Arcs.
+    #[inline]
+    fn default() -> Self {
+        let arc: Arc<[u8]> = Default::default();
+        debug_assert!(core::str::from_utf8(&*arc).is_ok());
+        let (ptr, alloc) = Arc::into_inner_with_allocator(arc);
+        unsafe { Arc::from_ptr_in(ptr.as_ptr() as *mut ArcInner<str>, alloc) }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Arc<core::ffi::CStr> {
+    /// Creates an empty CStr inside an Arc
+    ///
+    /// This may or may not share an allocation with other Arcs.
+    #[inline]
+    fn default() -> Self {
+        use core::ffi::CStr;
+        let inner: NonNull<ArcInner<[u8]>> = NonNull::from(&STATIC_INNER_SLICE.inner);
+        let inner: NonNull<ArcInner<CStr>> =
+            NonNull::new(inner.as_ptr() as *mut ArcInner<CStr>).unwrap();
+        // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
+        let this: mem::ManuallyDrop<Arc<CStr>> =
+            unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
+        (*this).clone()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for Arc<[T]> {
+    /// Creates an empty `[T]` inside an Arc
+    ///
+    /// This may or may not share an allocation with other Arcs.
+    #[inline]
+    fn default() -> Self {
+        if mem::align_of::<T>() <= MAX_STATIC_INNER_SLICE_ALIGNMENT {
+            // We take a reference to the whole struct instead of the ArcInner<[u8; 1]> inside it so
+            // we don't shrink the range of bytes the ptr is allowed to access under Stacked Borrows.
+            // (Miri complains on 32-bit targets with Arc<[Align16]> otherwise.)
+            // (Note that NonNull::from(&STATIC_INNER_SLICE.inner) is fine under Tree Borrows.)
+            let inner: NonNull<SliceArcInnerForStatic> = NonNull::from(&STATIC_INNER_SLICE);
+            let inner: NonNull<ArcInner<[T; 0]>> = inner.cast();
+            // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
+            let this: mem::ManuallyDrop<Arc<[T; 0]>> =
+                unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
+            return (*this).clone();
+        }
+
+        // If T's alignment is too large for the static, make a new unique allocation.
+        let arr: [T; 0] = [];
+        Arc::from(arr)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Hash, A: Allocator> Hash for Arc<T, A> {
     fn hash<H: Hasher>(&self, state: &mut H) {
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index 88aa1b1b0e0..22541a2b9d8 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -259,7 +259,8 @@ where
             inner.cap,
             inner.buf.cast::<T>(),
             inner.end as *const T,
-            inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
+            // SAFETY: the multiplication can not overflow, since `inner.cap * size_of::<I::SRC>()` is the size of the allocation.
+            inner.cap.unchecked_mul(mem::size_of::<I::Src>()) / mem::size_of::<T>(),
         )
     };
 
@@ -374,7 +375,7 @@ where
         // - it lets us thread the write pointer through its innards and get it back in the end
         let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
         let sink =
-            self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).unwrap();
+            self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).into_ok();
         // iteration succeeded, don't drop head
         unsafe { ManuallyDrop::new(sink).dst.sub_ptr(dst_buf) }
     }
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index b0226c84833..c4798933770 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -289,6 +289,60 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         };
     }
 
+    fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        if T::IS_ZST {
+            while self.ptr.as_ptr() != self.end.cast_mut() {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // See `next` for why we subtract from `end` here.
+                self.end = self.end.wrapping_byte_sub(1);
+                accum = f(accum, tmp);
+            }
+        } else {
+            // SAFETY: `self.end` can only be null if `T` is a ZST.
+            while self.ptr != non_null!(self.end, T) {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // SAFETY: the maximum this can be is `self.end`.
+                // Increment `self.ptr` first to avoid double dropping in the event of a panic.
+                self.ptr = unsafe { self.ptr.add(1) };
+                accum = f(accum, tmp);
+            }
+        }
+        accum
+    }
+
+    fn try_fold<B, F, R>(&mut self, mut accum: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: core::ops::Try<Output = B>,
+    {
+        if T::IS_ZST {
+            while self.ptr.as_ptr() != self.end.cast_mut() {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // See `next` for why we subtract from `end` here.
+                self.end = self.end.wrapping_byte_sub(1);
+                accum = f(accum, tmp)?;
+            }
+        } else {
+            // SAFETY: `self.end` can only be null if `T` is a ZST.
+            while self.ptr != non_null!(self.end, T) {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // SAFETY: the maximum this can be is `self.end`.
+                // Increment `self.ptr` first to avoid double dropping in the event of a panic.
+                self.ptr = unsafe { self.ptr.add(1) };
+                accum = f(accum, tmp)?;
+            }
+        }
+        R::from_output(accum)
+    }
+
     unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml
index a02fcf50416..11d33971f25 100644
--- a/library/core/Cargo.toml
+++ b/library/core/Cargo.toml
@@ -31,6 +31,8 @@ rand_xorshift = { version = "0.3.0", default-features = false }
 [features]
 # Make panics and failed asserts immediately abort without formatting any message
 panic_immediate_abort = []
+# Choose algorithms that are optimized for binary size instead of runtime performance
+optimize_for_size = []
 # Make `RefCell` store additional debugging information, which is printed out when
 # a borrow error occurs
 debug_refcell = []
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index e3d2cd2a31f..b314d0536a3 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -38,7 +38,7 @@ pub struct IntoIter<T, const N: usize> {
     alive: IndexRange,
 }
 
-// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
+// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
 // hides this implementation from explicit `.into_iter()` calls on editions < 2021,
 // so those calls will still resolve to the slice implementation, by reference.
 #[stable(feature = "array_into_iter_impl", since = "1.53.0")]
diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs
index a36e7efcd95..6b07236f1da 100644
--- a/library/core/src/fmt/nofloat.rs
+++ b/library/core/src/fmt/nofloat.rs
@@ -4,6 +4,7 @@ macro_rules! floating {
     ($ty:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
         impl Debug for $ty {
+            #[inline]
             fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result {
                 panic!("floating point support is turned off");
             }
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index ceea6790129..d1be534eaf0 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -569,6 +569,13 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn simd_ctlz<T>(x: T) -> T;
 
+    /// Count the number of ones in each element.
+    ///
+    /// `T` must be a vector of integers.
+    #[rustc_nounwind]
+    #[cfg(not(bootstrap))]
+    pub fn simd_ctpop<T>(x: T) -> T;
+
     /// Count the trailing zeros of each element.
     ///
     /// `T` must be a vector of integers.
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index 81371708b51..d497da33dd9 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -92,14 +92,20 @@ impl<'data> BorrowedBuf<'data> {
     #[inline]
     pub fn filled(&self) -> &[u8] {
         // SAFETY: We only slice the filled part of the buffer, which is always valid
-        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
+        unsafe {
+            let buf = self.buf.get_unchecked(..self.filled);
+            MaybeUninit::slice_assume_init_ref(buf)
+        }
     }
 
     /// Returns a mutable reference to the filled portion of the buffer.
     #[inline]
     pub fn filled_mut(&mut self) -> &mut [u8] {
         // SAFETY: We only slice the filled part of the buffer, which is always valid
-        unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+        unsafe {
+            let buf = self.buf.get_unchecked_mut(..self.filled);
+            MaybeUninit::slice_assume_init_mut(buf)
+        }
     }
 
     /// Returns a cursor over the unfilled part of the buffer.
@@ -205,7 +211,10 @@ impl<'a> BorrowedCursor<'a> {
     #[inline]
     pub fn init_ref(&self) -> &[u8] {
         // SAFETY: We only slice the initialized part of the buffer, which is always valid
-        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) }
+        unsafe {
+            let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init);
+            MaybeUninit::slice_assume_init_ref(buf)
+        }
     }
 
     /// Returns a mutable reference to the initialized portion of the cursor.
@@ -213,7 +222,8 @@ impl<'a> BorrowedCursor<'a> {
     pub fn init_mut(&mut self) -> &mut [u8] {
         // SAFETY: We only slice the initialized part of the buffer, which is always valid
         unsafe {
-            MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init])
+            let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init);
+            MaybeUninit::slice_assume_init_mut(buf)
         }
     }
 
@@ -222,7 +232,8 @@ impl<'a> BorrowedCursor<'a> {
     /// It is safe to uninitialize any of these bytes.
     #[inline]
     pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
-        &mut self.buf.buf[self.buf.init..]
+        // SAFETY: always in bounds
+        unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }
     }
 
     /// Returns a mutable reference to the whole cursor.
@@ -232,7 +243,8 @@ impl<'a> BorrowedCursor<'a> {
     /// The caller must not uninitialize any bytes in the initialized portion of the cursor.
     #[inline]
     pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
-        &mut self.buf.buf[self.buf.filled..]
+        // SAFETY: always in bounds
+        unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) }
     }
 
     /// Advance the cursor by asserting that `n` bytes have been filled.
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 563781230c0..d9d860c7b6c 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -268,7 +268,6 @@ where
 /// }
 /// ```
 #[rustc_diagnostic_item = "IntoIterator"]
-#[rustc_skip_array_during_method_dispatch]
 #[rustc_on_unimplemented(
     on(
         _Self = "core::ops::range::RangeTo<Idx>",
@@ -312,6 +311,8 @@ where
     label = "`{Self}` is not an iterator",
     message = "`{Self}` is not an iterator"
 )]
+#[cfg_attr(bootstrap, rustc_skip_array_during_method_dispatch)]
+#[cfg_attr(not(bootstrap), rustc_skip_during_method_dispatch(array, boxed_slice))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait IntoIterator {
     /// The type of the elements being iterated over.
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index d7d4f90c1a5..96fc87ab2e9 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -16,6 +16,9 @@ use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull};
 
 use super::{from_raw_parts, from_raw_parts_mut};
 
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<T> !Iterator for [T] {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> IntoIterator for &'a [T] {
     type Item = &'a T;
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index d8e10eeaa1a..dd7303a97b1 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -122,7 +122,7 @@ macro_rules! for_base_types {
                     #[inline]
                     #[must_use = "operator returns a new vector without mutating the inputs"]
                     // TODO: only useful for int Div::div, but we hope that this
-                    // will essentially always always get inlined anyway.
+                    // will essentially always get inlined anyway.
                     #[track_caller]
                     fn $call(self, rhs: Self) -> Self::Output {
                         $macro_impl!(self, rhs, $inner, $scalar)
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 1720fe84fa7..5b36867fe24 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -31,11 +31,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.21.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "=0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
-
-# Pin libc (pending https://github.com/rust-lang/rust/pull/124560)
-[target.'cfg(all(windows, target_env = "msvc"))'.dependencies]
-libc = { version = "=0.2.153", default-features = false }
+libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
 
 [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
 object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }
@@ -82,6 +78,8 @@ system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
 
 # Make panics and failed asserts immediately abort without formatting any message
 panic_immediate_abort = ["core/panic_immediate_abort", "alloc/panic_immediate_abort"]
+# Choose algorithms that are optimized for binary size instead of runtime performance
+optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]
 
 # Enable std_detect default features for stdarch/crates/std_detect:
 # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 37492e9efab..a1a8b2a3505 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -328,7 +328,7 @@ where
     fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         let prev_written = cursor.written();
 
-        Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
+        Read::read_buf(&mut self.remaining_slice(), cursor.reborrow())?;
 
         self.pos += (cursor.written() - prev_written) as u64;
 
@@ -352,17 +352,24 @@ where
     }
 
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
-        let n = buf.len();
-        Read::read_exact(&mut self.remaining_slice(), buf)?;
-        self.pos += n as u64;
-        Ok(())
+        let result = Read::read_exact(&mut self.remaining_slice(), buf);
+
+        match result {
+            Ok(_) => self.pos += buf.len() as u64,
+            // The only possible error condition is EOF, so place the cursor at "EOF"
+            Err(_) => self.pos = self.inner.as_ref().len() as u64,
+        }
+
+        result
     }
 
-    fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
-        let n = cursor.capacity();
-        Read::read_buf_exact(&mut self.remaining_slice(), cursor)?;
-        self.pos += n as u64;
-        Ok(())
+    fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        let prev_written = cursor.written();
+
+        let result = Read::read_buf_exact(&mut self.remaining_slice(), cursor.reborrow());
+        self.pos += (cursor.written() - prev_written) as u64;
+
+        result
     }
 
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 46f04c7cd39..a8a2e9413e1 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -287,6 +287,9 @@ impl Read for &[u8] {
     #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
+            // `read_exact` makes no promise about the content of `buf` if it
+            // fails so don't bother about that.
+            *self = &self[self.len()..];
             return Err(io::Error::READ_EXACT_EOF);
         }
         let (a, b) = self.split_at(buf.len());
@@ -307,6 +310,9 @@ impl Read for &[u8] {
     #[inline]
     fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         if cursor.capacity() > self.len() {
+            // Append everything we can to the cursor.
+            cursor.append(*self);
+            *self = &self[self.len()..];
             return Err(io::Error::READ_EXACT_EOF);
         }
         let (a, b) = self.split_at(cursor.capacity());
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 07fa9259e0b..c8968b74b12 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -1161,7 +1161,41 @@ pub trait IsTerminal: crate::sealed::Sealed {
     /// starting with `msys-` or `cygwin-` and ending in `-pty` will be considered terminals.
     /// Note that this [may change in the future][changes].
     ///
+    /// # Examples
+    ///
+    /// An example of a type for which `IsTerminal` is implemented is [`Stdin`]:
+    ///
+    /// ```no_run
+    /// use std::io::{self, IsTerminal, Write};
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let stdin = io::stdin();
+    ///
+    ///     // Indicate that the user is prompted for input, if this is a terminal.
+    ///     if stdin.is_terminal() {
+    ///         print!("> ");
+    ///         io::stdout().flush()?;
+    ///     }
+    ///
+    ///     let mut name = String::new();
+    ///     let _ = stdin.read_line(&mut name)?;
+    ///
+    ///     println!("Hello {}", name.trim_end());
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// The example can be run in two ways:
+    ///
+    /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable`
+    ///   it will print: `Hello foo`.
+    /// - If you instead run the example interactively by running the executable directly, it will
+    ///   panic with the message "Expected input to be piped to the process".
+    ///
+    ///
     /// [changes]: io#platform-specific-behavior
+    /// [`Stdin`]: crate::io::Stdin
     #[stable(feature = "is_terminal", since = "1.70.0")]
     fn is_terminal(&self) -> bool;
 }
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 090a091b09a..a2c1c430863 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -653,6 +653,38 @@ fn test_take_wrong_length() {
     let _ = reader.read(&mut buffer[..]);
 }
 
+#[test]
+fn slice_read_exact_eof() {
+    let slice = &b"123456"[..];
+
+    let mut r = slice;
+    assert!(r.read_exact(&mut [0; 10]).is_err());
+    assert!(r.is_empty());
+
+    let mut r = slice;
+    let buf = &mut [0; 10];
+    let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    assert!(r.read_buf_exact(buf.unfilled()).is_err());
+    assert!(r.is_empty());
+    assert_eq!(buf.filled(), b"123456");
+}
+
+#[test]
+fn cursor_read_exact_eof() {
+    let slice = Cursor::new(b"123456");
+
+    let mut r = slice.clone();
+    assert!(r.read_exact(&mut [0; 10]).is_err());
+    assert!(r.is_empty());
+
+    let mut r = slice;
+    let buf = &mut [0; 10];
+    let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    assert!(r.read_buf_exact(buf.unfilled()).is_err());
+    assert!(r.is_empty());
+    assert_eq!(buf.filled(), b"123456");
+}
+
 #[bench]
 fn bench_take_read(b: &mut test::Bencher) {
     b.iter(|| {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 27b46b46204..949c543a264 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -435,6 +435,7 @@ extern crate alloc as alloc_crate;
 // so include it here even if it's unused.
 #[doc(masked)]
 #[allow(unused_extern_crates)]
+#[cfg(not(all(windows, target_env = "msvc")))]
 extern crate libc;
 
 // We always need an unwinder currently for backtraces
diff --git a/library/std/src/os/hermit/mod.rs b/library/std/src/os/hermit/mod.rs
index 89b1b831912..02a4b2c3ab5 100644
--- a/library/std/src/os/hermit/mod.rs
+++ b/library/std/src/os/hermit/mod.rs
@@ -2,7 +2,7 @@
 
 #[allow(unused_extern_crates)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub extern crate hermit_abi as abi;
+pub extern crate hermit_abi;
 
 pub mod ffi;
 pub mod io;
diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs
index e7bb7d7e73e..f41a22e1bcc 100644
--- a/library/std/src/os/raw/tests.rs
+++ b/library/std/src/os/raw/tests.rs
@@ -1,3 +1,5 @@
+#![cfg(not(all(windows, target_env = "msvc")))]
+
 use crate::any::TypeId;
 
 macro_rules! ok {
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 15ab2250122..9cca27fa5dd 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -199,14 +199,14 @@ pub trait CommandExt: Sealed {
 
     /// Append literal text to the command line without any quoting or escaping.
     ///
-    /// This is useful for passing arguments to applications which doesn't follow
+    /// This is useful for passing arguments to applications that don't follow
     /// the standard C run-time escaping rules, such as `cmd.exe /c`.
     ///
-    /// # Bat files
+    /// # Batch files
     ///
-    /// Note the `cmd /c` command line has slightly different escaping rules then bat files
+    /// Note the `cmd /c` command line has slightly different escaping rules than batch files
     /// themselves. If possible, it may be better to write complex arguments to a temporary
-    /// .bat file, with appropriate escaping, and simply run that using:
+    /// `.bat` file, with appropriate escaping, and simply run that using:
     ///
     /// ```no_run
     /// # use std::process::Command;
@@ -217,7 +217,7 @@ pub trait CommandExt: Sealed {
     ///
     /// # Example
     ///
-    /// Run a bat script using both trusted and untrusted arguments.
+    /// Run a batch script using both trusted and untrusted arguments.
     ///
     /// ```no_run
     /// #[cfg(windows)]
@@ -241,9 +241,10 @@ pub trait CommandExt: Sealed {
     ///     if !user_name.chars().all(|c| c.is_alphanumeric()) {
     ///         return Err(Error::new(ErrorKind::InvalidInput, "invalid user name"));
     ///     }
-    ///     // now we've checked the user name, let's add that too.
-    ///     cmd_args.push(' ');
-    ///     cmd_args.push_str(&format!("--user {user_name}"));
+    ///
+    ///     // now we have validated the user name, let's add that too.
+    ///     cmd_args.push_str(" --user ");
+    ///     cmd_args.push_str(user_name);
     ///
     ///     // call cmd.exe and return the output
     ///     Command::new("cmd.exe")
@@ -287,25 +288,37 @@ pub trait CommandExt: Sealed {
     #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
     fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
 
-    /// Sets a raw attribute on the command, providing extended configuration options for Windows processes.
+    /// Set a raw attribute on the command, providing extended configuration options for Windows
+    /// processes.
+    ///
+    /// This method allows you to specify custom attributes for a child process on Windows systems
+    /// using raw attribute values. Raw attributes provide extended configurability for process
+    /// creation, but their usage can be complex and potentially unsafe.
     ///
-    /// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values.
-    /// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe.
+    /// The `attribute` parameter specifies the raw attribute to be set, while the `value`
+    /// parameter holds the value associated with that attribute. Please refer to the
+    /// [`windows-rs` documentation] or the [Win32 API documentation] for detailed information
+    /// about available attributes and their meanings.
     ///
-    /// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute.
-    /// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings.
+    /// [`windows-rs` documentation]: https://microsoft.github.io/windows-docs-rs/doc/windows/
+    /// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
     ///
     /// # Note
     ///
     /// The maximum number of raw attributes is the value of [`u32::MAX`].
-    /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded.
+    /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error`
+    /// indicating that the maximum number of attributes has been exceeded.
+    ///
     /// # Safety
     ///
-    /// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors.
+    /// The usage of raw attributes is potentially unsafe and should be done with caution.
+    /// Incorrect attribute values or improper configuration can lead to unexpected behavior or
+    /// errors.
     ///
     /// # Example
     ///
-    /// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute.
+    /// The following example demonstrates how to create a child process with a specific parent
+    /// process ID using a raw attribute.
     ///
     /// ```rust
     /// #![feature(windows_process_extensions_raw_attribute)]
@@ -339,7 +352,9 @@ pub trait CommandExt: Sealed {
     ///
     /// # Safety Note
     ///
-    /// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used.
+    /// Remember that improper use of raw attributes can lead to undefined behavior or security
+    /// vulnerabilities. Always consult the documentation and ensure proper attribute values are
+    /// used.
     #[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
     unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
         &mut self,
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 79d800ff072..f835b69f0cf 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3323,7 +3323,7 @@ impl Error for StripPrefixError {
 ///
 /// # Examples
 ///
-/// ## Posix paths
+/// ## POSIX paths
 ///
 /// ```
 /// # #[cfg(unix)]
@@ -3369,9 +3369,12 @@ impl Error for StripPrefixError {
 /// ```
 ///
 /// For verbatim paths this will simply return the path as given. For other
-/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
-/// This may change in the future.
+/// paths this is currently equivalent to calling
+/// [`GetFullPathNameW`][windows-path].
 ///
+/// Note that this [may change in the future][changes].
+///
+/// [changes]: io#platform-specific-behavior
 /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
 /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
 #[stable(feature = "absolute_path", since = "1.79.0")]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index d1848224251..c926c89f7a9 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -90,8 +90,8 @@
 //!
 //! # Windows argument splitting
 //!
-//! On Unix systems arguments are passed to a new process as an array of strings
-//! but on Windows arguments are passed as a single commandline string and it's
+//! On Unix systems arguments are passed to a new process as an array of strings,
+//! but on Windows arguments are passed as a single commandline string and it is
 //! up to the child process to parse it into an array. Therefore the parent and
 //! child processes must agree on how the commandline string is encoded.
 //!
@@ -107,26 +107,26 @@
 //! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping
 //!   rules used by [`arg`] so should be used with due caution.
 //!
-//! `cmd.exe` and `.bat` use non-standard argument parsing and are especially
+//! `cmd.exe` and `.bat` files use non-standard argument parsing and are especially
 //! vulnerable to malicious input as they may be used to run arbitrary shell
 //! commands. Untrusted arguments should be restricted as much as possible.
 //! For examples on handling this see [`raw_arg`].
 //!
-//! ### Bat file special handling
+//! ### Batch file special handling
 //!
 //! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to
-//! spawn new processes. An undocumented feature of this function is that,
+//! spawn new processes. An undocumented feature of this function is that
 //! when given a `.bat` file as the application to run, it will automatically
-//! convert that into running `cmd.exe /c` with the bat file as the next argument.
+//! convert that into running `cmd.exe /c` with the batch file as the next argument.
 //!
 //! For historical reasons Rust currently preserves this behaviour when using
 //! [`Command::new`], and escapes the arguments according to `cmd.exe` rules.
 //! Due to the complexity of `cmd.exe` argument handling, it might not be
-//! possible to safely escape some special chars, and using them will result
+//! possible to safely escape some special characters, and using them will result
 //! in an error being returned at process spawn. The set of unescapeable
-//! special chars might change between releases.
+//! special characters might change between releases.
 //!
-//! Also note that running `.bat` scripts in this way may be removed in the
+//! Also note that running batch scripts in this way may be removed in the
 //! future and so should not be relied upon.
 //!
 //! [`spawn`]: Command::spawn
@@ -659,16 +659,19 @@ impl Command {
     ///
     /// Note that the argument is not passed through a shell, but given
     /// literally to the program. This means that shell syntax like quotes,
-    /// escaped characters, word splitting, glob patterns, variable substitution, etc.
-    /// have no effect.
+    /// escaped characters, word splitting, glob patterns, variable substitution,
+    /// etc. have no effect.
     ///
     /// <div class="warning">
     ///
-    /// On Windows use caution with untrusted inputs. Most applications use the
-    /// standard convention for decoding arguments passed to them. These are safe to use with `arg`.
-    /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
-    /// and are therefore vulnerable to malicious input.
-    /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
+    /// On Windows, use caution with untrusted inputs. Most applications use the
+    /// standard convention for decoding arguments passed to them. These are safe to
+    /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files
+    /// use a non-standard way of decoding arguments. They are therefore vulnerable
+    /// to malicious input.
+    ///
+    /// In the case of `cmd.exe` this is especially important because a malicious
+    /// argument can potentially run arbitrary shell commands.
     ///
     /// See [Windows argument splitting][windows-args] for more details
     /// or [`raw_arg`] for manually implementing non-standard argument encoding.
@@ -710,11 +713,14 @@ impl Command {
     ///
     /// <div class="warning">
     ///
-    /// On Windows use caution with untrusted inputs. Most applications use the
-    /// standard convention for decoding arguments passed to them. These are safe to use with `args`.
-    /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
-    /// and are therefore vulnerable to malicious input.
-    /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
+    /// On Windows, use caution with untrusted inputs. Most applications use the
+    /// standard convention for decoding arguments passed to them. These are safe to
+    /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files
+    /// use a non-standard way of decoding arguments. They are therefore vulnerable
+    /// to malicious input.
+    ///
+    /// In the case of `cmd.exe` this is especially important because a malicious
+    /// argument can potentially run arbitrary shell commands.
     ///
     /// See [Windows argument splitting][windows-args] for more details
     /// or [`raw_arg`] for manually implementing non-standard argument encoding.
diff --git a/library/std/src/sys/pal/hermit/alloc.rs b/library/std/src/sys/pal/hermit/alloc.rs
index de550987a43..2cd0db90940 100644
--- a/library/std/src/sys/pal/hermit/alloc.rs
+++ b/library/std/src/sys/pal/hermit/alloc.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
 
@@ -6,11 +6,11 @@ use crate::ptr;
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        abi::malloc(layout.size(), layout.align())
+        hermit_abi::malloc(layout.size(), layout.align())
     }
 
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        let addr = abi::malloc(layout.size(), layout.align());
+        let addr = hermit_abi::malloc(layout.size(), layout.align());
 
         if !addr.is_null() {
             ptr::write_bytes(addr, 0x00, layout.size());
@@ -21,11 +21,11 @@ unsafe impl GlobalAlloc for System {
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        abi::free(ptr, layout.size(), layout.align())
+        hermit_abi::free(ptr, layout.size(), layout.align())
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        abi::realloc(ptr, layout.size(), layout.align(), new_size)
+        hermit_abi::realloc(ptr, layout.size(), layout.align(), new_size)
     }
 }
diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs
index 962577bb1ed..d7dab08cfbd 100644
--- a/library/std/src/sys/pal/hermit/fd.rs
+++ b/library/std/src/sys/pal/hermit/fd.rs
@@ -1,6 +1,6 @@
 #![unstable(reason = "not public", issue = "none", feature = "fd")]
 
-use super::abi;
+use super::hermit_abi;
 use crate::io::{self, Read};
 use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
@@ -16,7 +16,8 @@ pub struct FileDesc {
 
 impl FileDesc {
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
+        let result =
+            cvt(unsafe { hermit_abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
         Ok(result as usize)
     }
 
@@ -26,7 +27,8 @@ impl FileDesc {
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
+        let result =
+            cvt(unsafe { hermit_abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
         Ok(result as usize)
     }
 
@@ -49,8 +51,8 @@ impl FileDesc {
         unsupported()
     }
 
-    pub fn fstat(&self, stat: *mut abi::stat) -> io::Result<()> {
-        cvt(unsafe { abi::fstat(self.fd.as_raw_fd(), stat) })?;
+    pub fn fstat(&self, stat: *mut hermit_abi::stat) -> io::Result<()> {
+        cvt(unsafe { hermit_abi::fstat(self.fd.as_raw_fd(), stat) })?;
         Ok(())
     }
 }
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index 6519cc22f1f..a4a16e6e86b 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -1,8 +1,8 @@
-use super::abi::{
+use super::fd::FileDesc;
+use super::hermit_abi::{
     self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT,
     O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG,
 };
-use super::fd::FileDesc;
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
@@ -47,7 +47,7 @@ impl InnerReadDir {
 
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
-    pos: i64,
+    pos: usize,
 }
 
 impl ReadDir {
@@ -197,38 +197,31 @@ impl Iterator for ReadDir {
 
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         let mut counter: usize = 0;
-        let mut offset: i64 = 0;
+        let mut offset: usize = 0;
 
         // loop over all directory entries and search the entry for the current position
         loop {
             // leave function, if the loop reaches the of the buffer (with all entries)
-            if offset >= self.inner.dir.len().try_into().unwrap() {
+            if offset >= self.inner.dir.len() {
                 return None;
             }
 
-            let dir = unsafe {
-                &*(self.inner.dir.as_ptr().offset(offset.try_into().unwrap()) as *const dirent64)
-            };
+            let dir = unsafe { &*(self.inner.dir.as_ptr().add(offset) as *const dirent64) };
 
-            if counter == self.pos.try_into().unwrap() {
+            if counter == self.pos {
                 self.pos += 1;
 
                 // After dirent64, the file name is stored. d_reclen represents the length of the dirent64
                 // plus the length of the file name. Consequently, file name has a size of d_reclen minus
                 // the size of dirent64. The file name is always a C string and terminated by `\0`.
                 // Consequently, we are able to ignore the last byte.
-                let name_bytes = unsafe {
-                    core::slice::from_raw_parts(
-                        &dir.d_name as *const _ as *const u8,
-                        dir.d_reclen as usize - core::mem::size_of::<dirent64>() - 1,
-                    )
-                    .to_vec()
-                };
+                let name_bytes =
+                    unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const i8).to_bytes() };
                 let entry = DirEntry {
                     root: self.inner.root.clone(),
                     ino: dir.d_ino,
                     type_: dir.d_type as u32,
-                    name: OsString::from_vec(name_bytes),
+                    name: OsString::from_vec(name_bytes.to_vec()),
                 };
 
                 return Some(Ok(entry));
@@ -237,7 +230,7 @@ impl Iterator for ReadDir {
             counter += 1;
 
             // move to the next dirent64, which is directly stored after the previous one
-            offset = offset + dir.d_off;
+            offset = offset + usize::from(dir.d_reclen);
         }
     }
 }
@@ -365,7 +358,7 @@ impl File {
             mode = 0;
         }
 
-        let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
+        let fd = unsafe { cvt(hermit_abi::open(path.as_ptr(), flags, mode))? };
         Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) }))
     }
 
@@ -446,7 +439,7 @@ impl DirBuilder {
 
     pub fn mkdir(&self, path: &Path) -> io::Result<()> {
         run_path_with_cstr(path, &|path| {
-            cvt(unsafe { abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ())
+            cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ())
         })
     }
 
@@ -508,7 +501,8 @@ impl FromRawFd for File {
 }
 
 pub fn readdir(path: &Path) -> io::Result<ReadDir> {
-    let fd_raw = run_path_with_cstr(path, &|path| cvt(unsafe { abi::opendir(path.as_ptr()) }))?;
+    let fd_raw =
+        run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::opendir(path.as_ptr()) }))?;
     let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) };
     let root = path.to_path_buf();
 
@@ -519,8 +513,9 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
         // reserve memory to receive all directory entries
         vec.resize(sz, 0);
 
-        let readlen =
-            unsafe { abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) };
+        let readlen = unsafe {
+            hermit_abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz)
+        };
         if readlen > 0 {
             // shrink down to the minimal size
             vec.resize(readlen.try_into().unwrap(), 0);
@@ -529,7 +524,7 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
 
         // if the buffer is too small, getdents64 returns EINVAL
         // otherwise, getdents64 returns an error number
-        if readlen != (-abi::errno::EINVAL).into() {
+        if readlen != (-hermit_abi::errno::EINVAL).into() {
             return Err(Error::from_raw_os_error(readlen.try_into().unwrap()));
         }
 
@@ -547,7 +542,7 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(path: &Path) -> io::Result<()> {
-    run_path_with_cstr(path, &|path| cvt(unsafe { abi::unlink(path.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::unlink(path.as_ptr()) }).map(|_| ()))
 }
 
 pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
@@ -559,7 +554,7 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
 }
 
 pub fn rmdir(path: &Path) -> io::Result<()> {
-    run_path_with_cstr(path, &|path| cvt(unsafe { abi::rmdir(path.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::rmdir(path.as_ptr()) }).map(|_| ()))
 }
 
 pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
@@ -581,7 +576,7 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
 pub fn stat(path: &Path) -> io::Result<FileAttr> {
     run_path_with_cstr(path, &|path| {
         let mut stat_val: stat_struct = unsafe { mem::zeroed() };
-        cvt(unsafe { abi::stat(path.as_ptr(), &mut stat_val) })?;
+        cvt(unsafe { hermit_abi::stat(path.as_ptr(), &mut stat_val) })?;
         Ok(FileAttr::from_stat(stat_val))
     })
 }
@@ -589,7 +584,7 @@ pub fn stat(path: &Path) -> io::Result<FileAttr> {
 pub fn lstat(path: &Path) -> io::Result<FileAttr> {
     run_path_with_cstr(path, &|path| {
         let mut stat_val: stat_struct = unsafe { mem::zeroed() };
-        cvt(unsafe { abi::lstat(path.as_ptr(), &mut stat_val) })?;
+        cvt(unsafe { hermit_abi::lstat(path.as_ptr(), &mut stat_val) })?;
         Ok(FileAttr::from_stat(stat_val))
     })
 }
diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs
index 427d8ff6f2e..571b2885658 100644
--- a/library/std/src/sys/pal/hermit/futex.rs
+++ b/library/std/src/sys/pal/hermit/futex.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::ptr::null;
 use crate::sync::atomic::AtomicU32;
 use crate::time::Duration;
@@ -8,32 +8,32 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
     //
     // Overflows are rounded up to an infinite timeout (None).
     let timespec = timeout.and_then(|dur| {
-        Some(abi::timespec {
+        Some(hermit_abi::timespec {
             tv_sec: dur.as_secs().try_into().ok()?,
             tv_nsec: dur.subsec_nanos().into(),
         })
     });
 
     let r = unsafe {
-        abi::futex_wait(
+        hermit_abi::futex_wait(
             futex.as_ptr(),
             expected,
-            timespec.as_ref().map_or(null(), |t| t as *const abi::timespec),
-            abi::FUTEX_RELATIVE_TIMEOUT,
+            timespec.as_ref().map_or(null(), |t| t as *const hermit_abi::timespec),
+            hermit_abi::FUTEX_RELATIVE_TIMEOUT,
         )
     };
 
-    r != -abi::errno::ETIMEDOUT
+    r != -hermit_abi::errno::ETIMEDOUT
 }
 
 #[inline]
 pub fn futex_wake(futex: &AtomicU32) -> bool {
-    unsafe { abi::futex_wake(futex.as_ptr(), 1) > 0 }
+    unsafe { hermit_abi::futex_wake(futex.as_ptr(), 1) > 0 }
 }
 
 #[inline]
 pub fn futex_wake_all(futex: &AtomicU32) {
     unsafe {
-        abi::futex_wake(futex.as_ptr(), i32::MAX);
+        hermit_abi::futex_wake(futex.as_ptr(), i32::MAX);
     }
 }
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 910935541bd..a64323a3a29 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -39,7 +39,7 @@ pub mod thread_local_key;
 pub mod time;
 
 use crate::io::ErrorKind;
-use crate::os::hermit::abi;
+use crate::os::hermit::hermit_abi;
 
 pub fn unsupported<T>() -> crate::io::Result<T> {
     Err(unsupported_err())
@@ -54,7 +54,7 @@ pub fn unsupported_err() -> crate::io::Error {
 
 pub fn abort_internal() -> ! {
     unsafe {
-        abi::abort();
+        hermit_abi::abort();
     }
 }
 
@@ -62,7 +62,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     let mut buf = [0; 16];
     let mut slice = &mut buf[..];
     while !slice.is_empty() {
-        let res = cvt(unsafe { abi::read_entropy(slice.as_mut_ptr(), slice.len(), 0) })
+        let res = cvt(unsafe { hermit_abi::read_entropy(slice.as_mut_ptr(), slice.len(), 0) })
             .expect("failed to generate random hashmap keys");
         slice = &mut slice[res as usize..];
     }
@@ -109,31 +109,31 @@ pub unsafe extern "C" fn runtime_entry(
     let result = main(argc as isize, argv);
 
     run_dtors();
-    abi::exit(result);
+    hermit_abi::exit(result);
 }
 
 #[inline]
 pub(crate) fn is_interrupted(errno: i32) -> bool {
-    errno == abi::errno::EINTR
+    errno == hermit_abi::errno::EINTR
 }
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno {
-        abi::errno::EACCES => ErrorKind::PermissionDenied,
-        abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
-        abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
-        abi::errno::EAGAIN => ErrorKind::WouldBlock,
-        abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
-        abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
-        abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
-        abi::errno::EEXIST => ErrorKind::AlreadyExists,
-        abi::errno::EINTR => ErrorKind::Interrupted,
-        abi::errno::EINVAL => ErrorKind::InvalidInput,
-        abi::errno::ENOENT => ErrorKind::NotFound,
-        abi::errno::ENOTCONN => ErrorKind::NotConnected,
-        abi::errno::EPERM => ErrorKind::PermissionDenied,
-        abi::errno::EPIPE => ErrorKind::BrokenPipe,
-        abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
+        hermit_abi::errno::EACCES => ErrorKind::PermissionDenied,
+        hermit_abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
+        hermit_abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+        hermit_abi::errno::EAGAIN => ErrorKind::WouldBlock,
+        hermit_abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
+        hermit_abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        hermit_abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
+        hermit_abi::errno::EEXIST => ErrorKind::AlreadyExists,
+        hermit_abi::errno::EINTR => ErrorKind::Interrupted,
+        hermit_abi::errno::EINVAL => ErrorKind::InvalidInput,
+        hermit_abi::errno::ENOENT => ErrorKind::NotFound,
+        hermit_abi::errno::ENOTCONN => ErrorKind::NotConnected,
+        hermit_abi::errno::EPERM => ErrorKind::PermissionDenied,
+        hermit_abi::errno::EPIPE => ErrorKind::BrokenPipe,
+        hermit_abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
         _ => ErrorKind::Uncategorized,
     }
 }
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs
index 23ac71cb9f2..00dbca86a4b 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/pal/hermit/net.rs
@@ -175,23 +175,12 @@ impl Socket {
     }
 
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let mut size: isize = 0;
-
-        for i in bufs.iter_mut() {
-            let ret: isize =
-                cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
-
-            if ret != 0 {
-                size += ret;
-            }
-        }
-
-        Ok(size.try_into().unwrap())
+        crate::io::default_read_vectored(|b| self.read(b), bufs)
     }
 
     #[inline]
     pub fn is_read_vectored(&self) -> bool {
-        true
+        false
     }
 
     fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
@@ -225,17 +214,11 @@ impl Socket {
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let mut size: isize = 0;
-
-        for i in bufs.iter() {
-            size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
-        }
-
-        Ok(size.try_into().unwrap())
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
     }
 
     pub fn is_write_vectored(&self) -> bool {
-        true
+        false
     }
 
     pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs
index 1f9affbf773..cc678123831 100644
--- a/library/std/src/sys/pal/hermit/os.rs
+++ b/library/std/src/sys/pal/hermit/os.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::collections::HashMap;
 use crate::error::Error as StdError;
 use crate::ffi::{CStr, OsStr, OsString};
@@ -14,11 +14,11 @@ use crate::vec;
 use core::slice::memchr;
 
 pub fn errno() -> i32 {
-    unsafe { abi::get_errno() }
+    unsafe { hermit_abi::get_errno() }
 }
 
 pub fn error_string(errno: i32) -> String {
-    abi::error_string(errno).to_string()
+    hermit_abi::error_string(errno).to_string()
 }
 
 pub fn getcwd() -> io::Result<PathBuf> {
@@ -197,10 +197,10 @@ pub fn home_dir() -> Option<PathBuf> {
 
 pub fn exit(code: i32) -> ! {
     unsafe {
-        abi::exit(code);
+        hermit_abi::exit(code);
     }
 }
 
 pub fn getpid() -> u32 {
-    unsafe { abi::getpid() }
+    unsafe { hermit_abi::getpid() }
 }
diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs
index ac54385e8ce..777c57b391c 100644
--- a/library/std/src/sys/pal/hermit/stdio.rs
+++ b/library/std/src/sys/pal/hermit/stdio.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::io;
 use crate::io::{IoSlice, IoSliceMut};
 
@@ -37,7 +37,7 @@ impl io::Write for Stdout {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
@@ -49,7 +49,7 @@ impl io::Write for Stdout {
     fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
@@ -78,7 +78,7 @@ impl io::Write for Stderr {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
@@ -90,7 +90,7 @@ impl io::Write for Stderr {
     fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 4fe6b12a95b..b336dcd6860 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -1,6 +1,6 @@
 #![allow(dead_code)]
 
-use super::abi;
+use super::hermit_abi;
 use super::thread_local_dtor::run_dtors;
 use crate::ffi::CStr;
 use crate::io;
@@ -9,7 +9,7 @@ use crate::num::NonZero;
 use crate::ptr;
 use crate::time::Duration;
 
-pub type Tid = abi::Tid;
+pub type Tid = hermit_abi::Tid;
 
 pub struct Thread {
     tid: Tid,
@@ -27,10 +27,10 @@ impl Thread {
         core_id: isize,
     ) -> io::Result<Thread> {
         let p = Box::into_raw(Box::new(p));
-        let tid = abi::spawn2(
+        let tid = hermit_abi::spawn2(
             thread_start,
             p.expose_provenance(),
-            abi::Priority::into(abi::NORMAL_PRIO),
+            hermit_abi::Priority::into(hermit_abi::NORMAL_PRIO),
             stack,
             core_id,
         );
@@ -62,7 +62,7 @@ impl Thread {
     #[inline]
     pub fn yield_now() {
         unsafe {
-            abi::yield_now();
+            hermit_abi::yield_now();
         }
     }
 
@@ -74,13 +74,13 @@ impl Thread {
     #[inline]
     pub fn sleep(dur: Duration) {
         unsafe {
-            abi::usleep(dur.as_micros() as u64);
+            hermit_abi::usleep(dur.as_micros() as u64);
         }
     }
 
     pub fn join(self) {
         unsafe {
-            let _ = abi::join(self.tid);
+            let _ = hermit_abi::join(self.tid);
         }
     }
 
@@ -98,5 +98,5 @@ impl Thread {
 }
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsafe { Ok(NonZero::new_unchecked(abi::get_processor_count())) }
+    unsafe { Ok(NonZero::new_unchecked(hermit_abi::get_processor_count())) }
 }
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index d6f9e4c1476..2bf24462fa8 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -1,8 +1,6 @@
 #![allow(dead_code)]
 
-use super::abi;
-use super::abi::timespec;
-use super::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
+use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
 use crate::cmp::Ordering;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::time::Duration;
@@ -106,7 +104,8 @@ pub struct Instant(Timespec);
 impl Instant {
     pub fn now() -> Instant {
         let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) };
+        let _ =
+            unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) };
 
         Instant(time)
     }
@@ -207,7 +206,8 @@ impl SystemTime {
 
     pub fn now() -> SystemTime {
         let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
+        let _ =
+            unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
 
         SystemTime(time)
     }
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index 2a3298e8b4c..db2ec73148e 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -5,8 +5,9 @@
 
 #![allow(dead_code)] // runtime init functions not used during testing
 
-use crate::ffi::OsString;
+use crate::ffi::{CStr, OsString};
 use crate::fmt;
+use crate::os::unix::ffi::OsStringExt;
 use crate::vec;
 
 /// One-time global initialization.
@@ -16,7 +17,46 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
 
 /// Returns the command line arguments
 pub fn args() -> Args {
-    imp::args()
+    let (argc, argv) = imp::argc_argv();
+
+    let mut vec = Vec::with_capacity(argc as usize);
+
+    for i in 0..argc {
+        // SAFETY: `argv` is non-null if `argc` is positive, and it is
+        // guaranteed to be at least as long as `argc`, so reading from it
+        // should be safe.
+        let ptr = unsafe { argv.offset(i).read() };
+
+        // Some C commandline parsers (e.g. GLib and Qt) are replacing already
+        // handled arguments in `argv` with `NULL` and move them to the end.
+        //
+        // Since they can't directly ensure updates to `argc` as well, this
+        // means that `argc` might be bigger than the actual number of
+        // non-`NULL` pointers in `argv` at this point.
+        //
+        // To handle this we simply stop iterating at the first `NULL`
+        // argument. `argv` is also guaranteed to be `NULL`-terminated so any
+        // non-`NULL` arguments after the first `NULL` can safely be ignored.
+        if ptr.is_null() {
+            // NOTE: On Apple platforms, `-[NSProcessInfo arguments]` does not
+            // stop iterating here, but instead `continue`, always iterating
+            // up until it reached `argc`.
+            //
+            // This difference will only matter in very specific circumstances
+            // where `argc`/`argv` have been modified, but in unexpected ways,
+            // so it likely doesn't really matter which option we choose.
+            // See the following PR for further discussion:
+            // <https://github.com/rust-lang/rust/pull/125225>
+            break;
+        }
+
+        // SAFETY: Just checked that the pointer is not NULL, and arguments
+        // are otherwise guaranteed to be valid C strings.
+        let cstr = unsafe { CStr::from_ptr(ptr) };
+        vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
+    }
+
+    Args { iter: vec.into_iter() }
 }
 
 pub struct Args {
@@ -75,9 +115,7 @@ impl DoubleEndedIterator for Args {
     target_os = "hurd",
 ))]
 mod imp {
-    use super::Args;
-    use crate::ffi::{CStr, OsString};
-    use crate::os::unix::prelude::*;
+    use crate::ffi::c_char;
     use crate::ptr;
     use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
 
@@ -126,162 +164,78 @@ mod imp {
         init_wrapper
     };
 
-    pub fn args() -> Args {
-        Args { iter: clone().into_iter() }
-    }
-
-    fn clone() -> Vec<OsString> {
-        unsafe {
-            // Load ARGC and ARGV, which hold the unmodified system-provided
-            // argc/argv, so we can read the pointed-to memory without atomics
-            // or synchronization.
-            //
-            // If either ARGC or ARGV is still zero or null, then either there
-            // really are no arguments, or someone is asking for `args()`
-            // before initialization has completed, and we return an empty
-            // list.
-            let argv = ARGV.load(Ordering::Relaxed);
-            let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
-            let mut args = Vec::with_capacity(argc as usize);
-            for i in 0..argc {
-                let ptr = *argv.offset(i) as *const libc::c_char;
-
-                // Some C commandline parsers (e.g. GLib and Qt) are replacing already
-                // handled arguments in `argv` with `NULL` and move them to the end. That
-                // means that `argc` might be bigger than the actual number of non-`NULL`
-                // pointers in `argv` at this point.
-                //
-                // To handle this we simply stop iterating at the first `NULL` argument.
-                //
-                // `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
-                // after the first `NULL` can safely be ignored.
-                if ptr.is_null() {
-                    break;
-                }
-
-                let cstr = CStr::from_ptr(ptr);
-                args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
-            }
-
-            args
-        }
+    pub fn argc_argv() -> (isize, *const *const c_char) {
+        // Load ARGC and ARGV, which hold the unmodified system-provided
+        // argc/argv, so we can read the pointed-to memory without atomics or
+        // synchronization.
+        //
+        // If either ARGC or ARGV is still zero or null, then either there
+        // really are no arguments, or someone is asking for `args()` before
+        // initialization has completed, and we return an empty list.
+        let argv = ARGV.load(Ordering::Relaxed);
+        let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
+
+        // Cast from `*mut *const u8` to `*const *const c_char`
+        (argc, argv.cast())
     }
 }
 
+// Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms.
+//
+// Even though these have underscores in their names, they've been available
+// since since the first versions of both macOS and iOS, and are declared in
+// the header `crt_externs.h`.
+//
+// NOTE: This header was added to the iOS 13.0 SDK, which has been the source
+// of a great deal of confusion in the past about the availability of these
+// APIs.
+//
+// NOTE(madsmtm): This has not strictly been verified to not cause App Store
+// rejections; if this is found to be the case, the previous implementation
+// of this used `[[NSProcessInfo processInfo] arguments]`.
 #[cfg(target_vendor = "apple")]
 mod imp {
-    use super::Args;
-    use crate::ffi::CStr;
+    use crate::ffi::{c_char, c_int};
 
-    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
-
-    #[cfg(target_os = "macos")]
-    pub fn args() -> Args {
-        use crate::os::unix::prelude::*;
-        extern "C" {
-            // These functions are in crt_externs.h.
-            fn _NSGetArgc() -> *mut libc::c_int;
-            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
-        }
-
-        let vec = unsafe {
-            let (argc, argv) =
-                (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
-            (0..argc as isize)
-                .map(|i| {
-                    let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
-                    OsStringExt::from_vec(bytes)
-                })
-                .collect::<Vec<_>>()
-        };
-        Args { iter: vec.into_iter() }
+    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+        // No need to initialize anything in here, `libdyld.dylib` has already
+        // done the work for us.
     }
 
-    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-    // and use underscores in their names - they're most probably
-    // are considered private and therefore should be avoided.
-    // Here is another way to get arguments using the Objective-C
-    // runtime.
-    //
-    // In general it looks like:
-    // res = Vec::new()
-    // let args = [[NSProcessInfo processInfo] arguments]
-    // for i in (0..[args count])
-    //      res.push([args objectAtIndex:i])
-    // res
-    #[cfg(not(target_os = "macos"))]
-    pub fn args() -> Args {
-        use crate::ffi::{c_char, c_void, OsString};
-        use crate::mem;
-        use crate::str;
-
-        type Sel = *const c_void;
-        type NsId = *const c_void;
-        type NSUInteger = usize;
-
+    pub fn argc_argv() -> (isize, *const *const c_char) {
         extern "C" {
-            fn sel_registerName(name: *const c_char) -> Sel;
-            fn objc_getClass(class_name: *const c_char) -> NsId;
-
-            // This must be transmuted to an appropriate function pointer type before being called.
-            fn objc_msgSend();
-        }
-
-        const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
-        const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
-            unsafe { mem::transmute(MSG_SEND_PTR) };
-        const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
-            NsId,
-            Sel,
-        ) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
-        const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
-            NsId,
-            Sel,
-            NSUInteger,
-        )
-            -> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };
-
-        let mut res = Vec::new();
-
-        unsafe {
-            let process_info_sel = sel_registerName(c"processInfo".as_ptr());
-            let arguments_sel = sel_registerName(c"arguments".as_ptr());
-            let count_sel = sel_registerName(c"count".as_ptr());
-            let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
-            let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());
-
-            let klass = objc_getClass(c"NSProcessInfo".as_ptr());
-            // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
-            let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);
-
-            // `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
-            let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);
-
-            let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
-            for i in 0..cnt {
-                // `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
-                let ns_string =
-                    MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
-                // The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
-                let utf_c_str: *const c_char =
-                    MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
-                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
-                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
-            }
+            // These functions are in crt_externs.h.
+            fn _NSGetArgc() -> *mut c_int;
+            fn _NSGetArgv() -> *mut *mut *mut c_char;
         }
 
-        Args { iter: res.into_iter() }
+        // SAFETY: The returned pointer points to a static initialized early
+        // in the program lifetime by `libdyld.dylib`, and as such is always
+        // valid.
+        //
+        // NOTE: Similar to `_NSGetEnviron`, there technically isn't anything
+        // protecting us against concurrent modifications to this, and there
+        // doesn't exist a lock that we can take. Instead, it is generally
+        // expected that it's only modified in `main` / before other code
+        // runs, so reading this here should be fine.
+        let argc = unsafe { _NSGetArgc().read() };
+        // SAFETY: Same as above.
+        let argv = unsafe { _NSGetArgv().read() };
+
+        // Cast from `*mut *mut c_char` to `*const *const c_char`
+        (argc as isize, argv.cast())
     }
 }
 
 #[cfg(any(target_os = "espidf", target_os = "vita"))]
 mod imp {
-    use super::Args;
+    use crate::ffi::c_char;
+    use crate::ptr;
 
     #[inline(always)]
     pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
 
-    pub fn args() -> Args {
-        Args { iter: Vec::new().into_iter() }
+    pub fn argc_argv() -> (isize, *const *const c_char) {
+        (0, ptr::null())
     }
 }
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 21f233e2262..735ed96bc7b 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -399,14 +399,13 @@ cfg_if::cfg_if! {
         // Use libumem for the (malloc-compatible) allocator
         #[link(name = "umem")]
         extern "C" {}
-    } else if #[cfg(target_os = "macos")] {
+    } else if #[cfg(target_vendor = "apple")] {
+        // Link to `libSystem.dylib`.
+        //
+        // Don't get confused by the presence of `System.framework`,
+        // it is a deprecated wrapper over the dynamic library.
         #[link(name = "System")]
         extern "C" {}
-    } else if #[cfg(all(target_vendor = "apple", not(target_os = "macos")))] {
-        #[link(name = "System")]
-        #[link(name = "objc")]
-        #[link(name = "Foundation", kind = "framework")]
-        extern "C" {}
     } else if #[cfg(target_os = "fuchsia")] {
         #[link(name = "zircon")]
         #[link(name = "fdio")]
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 3a281525f8d..8afc49f5227 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -576,12 +576,36 @@ impl Iterator for Env {
     }
 }
 
-#[cfg(target_os = "macos")]
+// Use `_NSGetEnviron` on Apple platforms.
+//
+// `_NSGetEnviron` is the documented alternative (see `man environ`), and has
+// been available since the first versions of both macOS and iOS.
+//
+// Nowadays, specifically since macOS 10.8, `environ` has been exposed through
+// `libdyld.dylib`, which is linked via. `libSystem.dylib`:
+// <https://github.com/apple-oss-distributions/dyld/blob/dyld-1160.6/libdyld/libdyldGlue.cpp#L913>
+//
+// So in the end, it likely doesn't really matter which option we use, but the
+// performance cost of using `_NSGetEnviron` is extremely miniscule, and it
+// might be ever so slightly more supported, so let's just use that.
+//
+// NOTE: The header where this is defined (`crt_externs.h`) was added to the
+// iOS 13.0 SDK, which has been the source of a great deal of confusion in the
+// past about the availability of this API.
+//
+// NOTE(madsmtm): Neither this nor using `environ` has been verified to not
+// cause App Store rejections; if this is found to be the case, an alternative
+// implementation of this is possible using `[NSProcessInfo environment]`
+// - which internally uses `_NSGetEnviron` and a system-wide lock on the
+// environment variables to protect against `setenv`, so using that might be
+// desirable anyhow? Though it also means that we have to link to Foundation.
+#[cfg(target_vendor = "apple")]
 pub unsafe fn environ() -> *mut *const *const c_char {
     libc::_NSGetEnviron() as *mut *const *const c_char
 }
 
-#[cfg(not(target_os = "macos"))]
+// Use the `environ` static which is part of POSIX.
+#[cfg(not(target_vendor = "apple"))]
 pub unsafe fn environ() -> *mut *const *const c_char {
     extern "C" {
         static mut environ: *const *const c_char;
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 6ff24a8db59..1ddacd92e6b 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -22,6 +22,7 @@ llvm-libunwind = ["std/llvm-libunwind"]
 system-llvm-libunwind = ["std/system-llvm-libunwind"]
 panic-unwind = ["std/panic_unwind"]
 panic_immediate_abort = ["std/panic_immediate_abort"]
+optimize_for_size = ["std/optimize_for_size"]
 profiler = ["std/profiler"]
 std_detect_file_io = ["std/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
diff --git a/rustfmt.toml b/rustfmt.toml
index 850d01ea7cb..ef56059feb1 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -40,6 +40,7 @@ ignore = [
     "src/tools/clippy",
     "src/tools/miri",
     "src/tools/rust-analyzer",
+    "src/tools/rustc-perf",
     "src/tools/rustfmt",
 
     # these are ignored by a standard cargo fmt run
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 4a5d768961f..127699b8641 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -341,9 +341,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.151"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 1f006e1453f..91039d0c8dc 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1010,6 +1010,9 @@ impl Step for PlainSourceTarball {
         if builder.rust_info().is_managed_git_subrepository()
             || builder.rust_info().is_from_tarball()
         {
+            // FIXME: This code looks _very_ similar to what we have in `src/core/build_steps/vendor.rs`
+            // perhaps it should be removed in favor of making `dist` perform the `vendor` step?
+
             // Ensure we have all submodules from src and other directories checked out.
             for submodule in builder.get_all_submodules() {
                 builder.update_submodule(Path::new(submodule));
@@ -1029,6 +1032,10 @@ impl Step for PlainSourceTarball {
                 .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
                 .arg("--sync")
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
+                .arg("--sync")
+                .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml"))
+                .arg("--sync")
+                .arg(builder.src.join("./src/tools/rustc-perf/Cargo.toml"))
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
                 .env("RUSTC_BOOTSTRAP", "1")
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 3af1a05caa8..8ca7af2febe 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -508,7 +508,7 @@ impl Step for Llvm {
             cfg.define("LLVM_VERSION_SUFFIX", suffix);
         }
 
-        configure_cmake(builder, target, &mut cfg, true, ldflags, &[], &[]);
+        configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);
         configure_llvm(builder, target, &mut cfg);
 
         for (key, val) in &builder.config.llvm_build_config {
@@ -597,7 +597,6 @@ fn configure_cmake(
     cfg: &mut cmake::Config,
     use_compiler_launcher: bool,
     mut ldflags: LdFlags,
-    extra_compiler_flags: &[&str],
     suppressed_compiler_flag_prefixes: &[&str],
 ) {
     // Do not print installation messages for up-to-date files.
@@ -751,9 +750,6 @@ fn configure_cmake(
     if builder.config.llvm_clang_cl.is_some() {
         cflags.push(&format!(" --target={target}"));
     }
-    for flag in extra_compiler_flags {
-        cflags.push(&format!(" {flag}"));
-    }
     cfg.define("CMAKE_C_FLAGS", cflags);
     let mut cxxflags: OsString = builder
         .cflags(target, GitRepo::Llvm, CLang::Cxx)
@@ -773,9 +769,6 @@ fn configure_cmake(
     if builder.config.llvm_clang_cl.is_some() {
         cxxflags.push(&format!(" --target={target}"));
     }
-    for flag in extra_compiler_flags {
-        cxxflags.push(&format!(" {flag}"));
-    }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = builder.ar(target) {
         if ar.is_absolute() {
@@ -944,7 +937,7 @@ impl Step for Lld {
             ldflags.push_all("-Wl,-rpath,'$ORIGIN/../../../'");
         }
 
-        configure_cmake(builder, target, &mut cfg, true, ldflags, &[], &[]);
+        configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);
         configure_llvm(builder, target, &mut cfg);
 
         // Re-use the same flags as llvm to control the level of debug information
@@ -1043,8 +1036,6 @@ impl Step for Sanitizers {
         // Unfortunately sccache currently lacks support to build them successfully.
         // Disable compiler launcher on Darwin targets to avoid potential issues.
         let use_compiler_launcher = !self.target.contains("apple-darwin");
-        let extra_compiler_flags: &[&str] =
-            if self.target.contains("apple") { &["-fembed-bitcode=off"] } else { &[] };
         // Since v1.0.86, the cc crate adds -mmacosx-version-min to the default
         // flags on MacOS. A long-standing bug in the CMake rules for compiler-rt
         // causes architecture detection to be skipped when this flag is present,
@@ -1057,7 +1048,6 @@ impl Step for Sanitizers {
             &mut cfg,
             use_compiler_launcher,
             LdFlags::default(),
-            extra_compiler_flags,
             suppressed_compiler_flag_prefixes,
         );
 
diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
index 89d50b5ffff..281a9b093b9 100644
--- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs
+++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
@@ -80,8 +80,5 @@ fn create_synthetic_target(
     customize(spec_map);
 
     std::fs::write(&path, serde_json::to_vec_pretty(&spec).unwrap()).unwrap();
-    let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap());
-    crate::utils::cc_detect::find_target(builder, target);
-
-    target
+    TargetSelection::create_synthetic(&name, path.to_str().unwrap())
 }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 21344a4224e..2db3f8f7936 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,6 +1,6 @@
 use std::env;
 use std::fs;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use crate::core::build_steps::compile;
@@ -313,10 +313,47 @@ bootstrap_tool!(
     SuggestTests, "src/tools/suggest-tests", "suggest-tests";
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
     RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
-    OptimizedDist, "src/tools/opt-dist", "opt-dist";
     CoverageDump, "src/tools/coverage-dump", "coverage-dump";
 );
 
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct OptimizedDist {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for OptimizedDist {
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/opt-dist")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(OptimizedDist {
+            compiler: run.builder.compiler(0, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        // We need to ensure the rustc-perf submodule is initialized when building opt-dist since
+        // the tool requires it to be in place to run.
+        builder.update_submodule(Path::new("src/tools/rustc-perf"));
+
+        builder.ensure(ToolBuild {
+            compiler: self.compiler,
+            target: self.target,
+            tool: "opt-dist",
+            mode: Mode::ToolBootstrap,
+            path: "src/tools/opt-dist",
+            source_type: SourceType::InTree,
+            extra_features: Vec::new(),
+            allow_features: "",
+        })
+    }
+}
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
 pub struct ErrorIndex {
     pub compiler: Compiler,
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 493ad99cc70..9c3df6fa9e3 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -8,7 +8,7 @@
 //! In theory if we get past this phase it's a bug if a build fails, but in
 //! practice that's likely not true!
 
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs;
@@ -33,8 +33,6 @@ pub struct Finder {
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
-    "aarch64-apple-visionos",
-    "aarch64-apple-visionos-sim",
 ];
 
 impl Finder {
@@ -169,6 +167,12 @@ than building it.
         .map(|p| cmd_finder.must_have(p))
         .or_else(|| cmd_finder.maybe_have("reuse"));
 
+    let stage0_supported_target_list: HashSet<String> =
+        output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]))
+            .lines()
+            .map(|s| s.to_string())
+            .collect();
+
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
     for target in &build.targets {
@@ -195,11 +199,19 @@ than building it.
         if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) {
             let mut has_target = false;
 
-            let supported_target_list =
-                output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]));
+            let missing_targets_hashset: HashSet<_> = STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect();
+            let duplicated_targets: Vec<_> = stage0_supported_target_list.intersection(&missing_targets_hashset).collect();
+
+            if !duplicated_targets.is_empty() {
+                println!("Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list.");
+                for duplicated_target in duplicated_targets {
+                    println!("  {duplicated_target}");
+                }
+                std::process::exit(1);
+            }
 
             // Check if it's a built-in target.
-            has_target |= supported_target_list.contains(&target_str);
+            has_target |= stage0_supported_target_list.contains(&target_str);
             has_target |= STAGE0_MISSING_TARGETS.contains(&target_str.as_str());
 
             if !has_target {
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 fe84c23a11c..4e1aae98221 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
@@ -58,14 +58,6 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
-# rustc-perf version from 2023-10-22
-# Should also be changed in the opt-dist tool for other environments.
-ENV PERF_COMMIT 4f313add609f43e928e98132358e8426ed3969ae
-RUN curl -LS -o perf.zip https://ci-mirrors.rust-lang.org/rustc/rustc-perf-$PERF_COMMIT.zip && \
-    unzip perf.zip && \
-    mv rustc-perf-$PERF_COMMIT rustc-perf && \
-    rm perf.zip
-
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
index 2eb751ca376..876b300d35c 100755
--- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh
+++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
@@ -23,6 +23,10 @@ if [[ -z "${PR_CI_JOB}" ]]; then
     # Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0
     # compiler, and is sensitive to the addition of new flags.
     ../x.py --stage 1 test tests/ui-fulldeps
+
+    # The tests are run a second time with the size optimizations enabled.
+    ../x.py --stage 1 test library/std library/alloc library/core \
+        --rustc-args "--cfg feature=\"optimize_for_size\""
 fi
 
 # When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 04888dc09b5..05470eebf01 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -50,8 +50,6 @@ envs:
   production:
     &production
     DEPLOY_BUCKET: rust-lang-ci2
-    TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
-    TOOLSTATE_PUBLISH: 1
     # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named
     # AWS_SECRET_ACCESS_KEY_<keyid>. Including the key id in the name allows to
     # rotate them in a single branch while keeping the old key in another
@@ -108,66 +106,66 @@ auto:
     <<: *job-aarch64-linux
 
   - image: arm-android
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: armhf-gnu
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-aarch64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-android
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-arm-linux
-    <<: *job-linux-16c
+    <<: *job-linux-8c
 
   - image: dist-armhf-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-armv7-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-i586-gnu-i586-i686-musl
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-i686-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-loongarch64-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-ohos
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-powerpc-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-powerpc64-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-powerpc64le-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-riscv64-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-s390x-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-various-1
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-various-2
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-x86_64-freebsd
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-x86_64-illumos
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-x86_64-linux
     env:
@@ -186,7 +184,7 @@ auto:
     <<: *job-linux-8c
 
   - image: dist-x86_64-netbsd
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: i686-gnu
     <<: *job-linux-8c
@@ -198,7 +196,7 @@ auto:
     <<: *job-linux-4c
 
   - image: test-various
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: x86_64-gnu
     <<: *job-linux-4c
@@ -229,7 +227,7 @@ auto:
     <<: *job-linux-8c
 
   - image: x86_64-gnu-debug
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: x86_64-gnu-distcheck
     <<: *job-linux-8c
diff --git a/src/doc/book b/src/doc/book
-Subproject bebcf527e67755a989a1739b7cfaa8f0e6b3004
+Subproject 5e9051f71638aa941cd5dda465e25c61cde9594
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 17842ebb050f62e40a4618edeb8e8ee86e75870
+Subproject dd962bb82865a5284f2404e5234f1e3222b9c02
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 51817951d0d213a0011f82b62aae02c3b3f2472
+Subproject e356977fceaa8591c762312d8d446769166d4b3
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 229ad13b64d919b12e548d560f06d88963b25cd
+Subproject 20482893d1a502df72f76762c97aed88854cdf8
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 2d1947ff34d50ca46dfe242ad75531a4c429bb5
+Subproject b6d4a4940bab85cc91eec70cc2e3096dd48da62
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index c7e3293e35a..6f814955857 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -16,13 +16,17 @@
 - [Platform Support](platform-support.md)
     - [Target Tier Policy](target-tier-policy.md)
     - [Template for Target-specific Documentation](platform-support/TEMPLATE.md)
-    - [arm64e-apple-ios.md](platform-support/arm64e-apple-ios.md)
-    - [arm64e-apple-darwin.md](platform-support/arm64e-apple-darwin.md)
-    - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
     - [arm64ec-pc-windows-msvc](platform-support/arm64ec-pc-windows-msvc.md)
+    - [\*-apple-darwin](platform-support/apple-darwin.md)
+        - [i686-apple-darwin](platform-support/i686-apple-darwin.md)
+        - [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md)
+        - [arm64e-apple-darwin.md](platform-support/arm64e-apple-darwin.md)
+    - [\*-apple-ios](platform-support/apple-ios.md)
+        - [\*-apple-ios-macabi](platform-support/apple-ios-macabi.md)
+        - [arm64e-apple-ios.md](platform-support/arm64e-apple-ios.md)
     - [\*-apple-tvos](platform-support/apple-tvos.md)
-    - [\*-apple-watchos\*](platform-support/apple-watchos.md)
-    - [aarch64-apple-visionos\*](platform-support/apple-visionos.md)
+    - [\*-apple-watchos](platform-support/apple-watchos.md)
+    - [\*-apple-visionos](platform-support/apple-visionos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
     - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
     - [arm-none-eabi](platform-support/arm-none-eabi.md)
@@ -76,7 +80,6 @@
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
     - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
-    - [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
     - [Custom Targets](targets/custom.md)
@@ -84,7 +87,8 @@
 - [Profile-guided Optimization](profile-guided-optimization.md)
 - [Instrumentation-based Code Coverage](instrument-coverage.md)
 - [Linker-plugin-based LTO](linker-plugin-lto.md)
-- [Checking conditional configurations](check-cfg.md)
+- [Checking Conditional Configurations](check-cfg.md)
+    - [Cargo Specifics](check-cfg/cargo-specifics.md)
 - [Exploit Mitigations](exploit-mitigations.md)
 - [Symbol Mangling](symbol-mangling/index.md)
     - [v0 Symbol Format](symbol-mangling/v0.md)
diff --git a/src/doc/rustc/src/check-cfg/cargo-specifics.md b/src/doc/rustc/src/check-cfg/cargo-specifics.md
new file mode 100644
index 00000000000..bfa60161926
--- /dev/null
+++ b/src/doc/rustc/src/check-cfg/cargo-specifics.md
@@ -0,0 +1,73 @@
+# Cargo Specifics - Checking Conditional Configurations
+
+<!--
+This page is currently (as of May 2024) the canonical place for describing the interaction
+between Cargo and --check-cfg. It is placed in the rustc book rather than the Cargo book
+since check-cfg is primarely a Rust/rustc feature and is therefor consider by T-cargo to
+be an implementation detail, at least --check-cfg and the unexpected_cfgs are owned by
+rustc, not Cargo.
+-->
+
+This document is intented to summarize the principal ways Cargo interacts with
+the `unexpected_cfgs` lint and `--check-cfg` flag. It is not intended to provide
+individual details, for that refer to the [`--check-cfg` documentation](../check-cfg.md) and
+to the [Cargo book](../../cargo/index.html).
+
+## Cargo feature
+
+*See the [`[features]` section in the Cargo book][cargo-features] for more details.*
+
+With the `[features]` table Cargo provides a mechanism to express conditional compilation and
+optional dependencies. Cargo *automatically* declares corresponding cfgs for every feature as
+expected.
+
+`Cargo.toml`:
+```toml
+[features]
+serde = ["dep:serde"]
+my_feature = []
+```
+
+[cargo-features]: ../../cargo/reference/features.html
+
+## `check-cfg` in `[lints.rust]` table
+
+<!-- Note that T-Cargo considers `[lints.rust.unexpected_cfgs.check-cfg]` to be an
+implementation detail and is therefor not documented in Cargo, we therefor do that ourself -->
+
+*See the [`[lints]` section in the Cargo book][cargo-lints-table] for more details.*
+
+When using a staticlly known custom config (ie. not dependant on a build-script), Cargo provides
+the custom lint config `check-cfg` under `[lints.rust.unexpected_cfgs]`.
+
+It can be used to set custom static [`--check-cfg`](../check-cfg.md) args, it is mainly useful when
+the list of expected cfgs is known is advance.
+
+`Cargo.toml`:
+```toml
+[lints.rust]
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(has_foo)'] }
+```
+
+[cargo-lints-table]: ../../cargo/reference/manifest.html#the-lints-section
+
+## `cargo::rustc-check-cfg` for `build.rs`/build-script
+
+*See the [`cargo::rustc-check-cfg` section in the Cargo book][cargo-rustc-check-cfg] for more details.*
+
+When setting a custom config with [`cargo::rustc-cfg`][cargo-rustc-cfg], Cargo provides the
+corollary instruction: [`cargo::rustc-check-cfg`][cargo-rustc-check-cfg] to expect custom configs.
+
+`build.rs`:
+```rust,ignore (cannot-test-this-because-has_foo-isnt-declared)
+fn main() {
+    println!("cargo::rustc-check-cfg=cfg(has_foo)");
+    //        ^^^^^^^^^^^^^^^^^^^^^^ new with Cargo 1.80
+    if has_foo() {
+        println!("cargo::rustc-cfg=has_foo");
+    }
+}
+```
+
+[cargo-rustc-cfg]: ../../cargo/reference/build-scripts.html#rustc-cfg
+[cargo-rustc-check-cfg]: ../../cargo/reference/build-scripts.html#rustc-check-cfg
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 8adc410455e..77859956c95 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -36,7 +36,7 @@ target | notes
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+) [^x86_32-floats-return-ABI]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
-`x86_64-apple-darwin` | 64-bit macOS (10.12+, Sierra+)
+[`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+)
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
@@ -86,7 +86,7 @@ so Rustup may install the documentation for a similar tier 1 target instead.
 
 target | notes
 -------|-------
-`aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+)
+[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-pc-windows-msvc` | ARM64 Windows MSVC
 `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17)
@@ -133,8 +133,8 @@ so Rustup may install the documentation for a similar tier 1 target instead.
 
 target | std | notes
 -------|:---:|-------
-`aarch64-apple-ios` | ✓ | ARM64 iOS
-[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64
+[`aarch64-apple-ios`](platform-support/apple-ios.md) | ✓ | ARM64 iOS
+[`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64
 `aarch64-fuchsia` | ✓ | Alias for `aarch64-unknown-fuchsia`
 [`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
@@ -192,7 +192,7 @@ target | std | notes
 `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename])
 [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI
 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ |  | WebAssembly with WASI Preview 1 and threads
-`x86_64-apple-ios` | ✓ | 64-bit x86 iOS
+[`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia`
 [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
@@ -241,9 +241,9 @@ target | std | host | notes
 [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
 [`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md)  | ✓ | ✓ | ARM64e Apple Darwin
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ? | | Arm64EC Windows MSVC
-`aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
-[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | ARM64 tvOS
-[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ? |  | ARM64 tvOS Simulator
+[`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ |  | Apple Catalyst on ARM64
+[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | ARM64 tvOS
+[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ |  | ARM64 tvOS Simulator
 [`aarch64-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS
 [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS Simulator
 [`aarch64-apple-visionos`](platform-support/apple-visionos.md) | ✓ |  | ARM64 Apple visionOS
@@ -283,7 +283,7 @@ target | std | host | notes
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
 [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare Armv7-A, hardfloat
 [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | Armv7-A Apple WatchOS
-`armv7s-apple-ios` | ✓ |  | Armv7-A Apple-A6 Apple iOS
+[`armv7s-apple-ios`](platform-support/apple-ios.md) | ✓ |  | Armv7-A Apple-A6 Apple iOS
 [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * |  | Bare Armv8-R, hardfloat
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `bpfeb-unknown-none` | * |  | BPF (big endian)
@@ -292,10 +292,10 @@ target | std | host | notes
 `csky-unknown-linux-gnuabiv2hf` | ✓ |  | C-SKY abiv2 Linux, hardfloat (little endian)
 [`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX)
 [`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3
-`i386-apple-ios` | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
+[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
 [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS  [^x86_32-floats-return-ABI]
 [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ |  | 32-bit x86, restricted to Pentium
-`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
+[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku [^x86_32-floats-return-ABI]
 [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI]
 [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI]
@@ -367,8 +367,8 @@ target | std | host | notes
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.3
 [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ |  | WebAssembly
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
-`x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
-[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | x86 64-bit tvOS
+[`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ |  | Apple Catalyst on x86_64
+[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | x86 64-bit tvOS
 [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
 [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | x86 64-bit QNX Neutrino 7.1 RTOS |
 [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ |   | 64-bit Unikraft with musl 1.2.3
diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
deleted file mode 100644
index 3f29e2c5e1f..00000000000
--- a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# aarch64-apple-ios-sim
-
-**Tier: 2**
-
-Apple iOS Simulator on ARM64.
-
-## Designated Developers
-
-* [@badboy](https://github.com/badboy)
-* [@deg4uss3r](https://github.com/deg4uss3r)
-
-## Requirements
-
-This target is cross-compiled.
-To build this target Xcode 12 or higher on macOS is required.
-
-## Building
-
-The target can be built by enabling it for a `rustc` build:
-
-```toml
-[build]
-build-stage = 1
-target = ["aarch64-apple-ios-sim"]
-```
-
-## Cross-compilation
-
-This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts.
-
-Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
-
-## Testing
-
-Currently there is no support to run the rustc test suite for this target.
-
-
-## Building Rust programs
-
-*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
-
-From Rust Nightly 1.56.0 (2021-08-03) on the artifacts are shipped pre-compiled:
-
-```text
-rustup target add aarch64-apple-ios-sim --toolchain nightly
-```
-
-Rust programs can be built for that target:
-
-```text
-rustc --target aarch64-apple-ios-sim your-code.rs
-```
-
-There is no easy way to run simple programs in the iOS simulator.
-Static library builds can be embedded into iOS applications.
diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md
new file mode 100644
index 00000000000..0fb86949a4b
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/apple-darwin.md
@@ -0,0 +1,59 @@
+# `*-apple-darwin`
+
+Apple macOS targets.
+
+**Tier: 1**
+
+- `x86_64-apple-darwin`: macOS on 64-bit x86.
+
+**Tier: 2 (with Host Tools)**
+
+- `aarch64-apple-darwin`: macOS on ARM64 (M1-family or later Apple Silicon CPUs).
+
+## Target maintainers
+
+- [@thomcc](https://github.com/thomcc)
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+### OS version
+
+The minimum supported version is macOS 10.12 Sierra on x86, and macOS 11.0 Big
+Sur on ARM64.
+
+This version can be raised per-binary by changing the [deployment target],
+which might yield more performance optimizations. `rustc` respects the common
+environment variables used by Xcode to do so, in this case
+`MACOSX_DEPLOYMENT_TARGET`.
+
+The current default deployment target for `rustc` can be retrieved with
+[`rustc --print=deployment-target`][rustc-print].
+
+[deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html
+[rustc-print]: ../command-line-arguments.md#option-print
+
+### Binary format
+
+The default binary format is Mach-O, the executable format used on Apple's
+platforms.
+
+## Building
+
+These targets are distributed through `rustup`, and otherwise require no
+special configuration.
+
+## Testing
+
+There are no special requirements for testing and running this target.
+
+x86 binaries can be run on Apple Silicon by using Rosetta.
+
+## Cross-compilation toolchains and C code
+
+Cross-compilation of these targets are supported using Clang, but may require
+Xcode or the macOS SDK (`MacOSX.sdk`) to be available to compile C code and
+to link.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
new file mode 100644
index 00000000000..278ee94b6d4
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
@@ -0,0 +1,58 @@
+# `*-apple-ios-macabi`
+
+Apple Mac Catalyst targets.
+
+**Tier: 3**
+
+- `aarch64-apple-ios-macabi`: Mac Catalyst on ARM64.
+- `x86_64-apple-ios-macabi`: Mac Catalyst on 64-bit x86.
+
+## Target maintainers
+
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+These targets are cross-compiled, and require the corresponding macOS SDK
+(`MacOSX.sdk`) which contain `./System/iOSSupport` headers to allow linking to
+iOS-specific headers, as provided by Xcode 11 or higher.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is iOS 13.1.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `IPHONEOS_DEPLOYMENT_TARGET`.
+
+## Building the target
+
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
+
+```toml
+[build]
+target = ["aarch64-apple-ios-macabi", "x86_64-apple-ios-macabi"]
+```
+
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+## Building Rust programs
+
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
+
+```console
+$ rustc --target aarch64-apple-ios-macabi your-code.rs
+```
+
+## Testing
+
+Mac Catalyst binaries can be run directly on macOS 10.15 Catalina or newer.
+
+x86 binaries can be run on Apple Silicon by using Rosetta.
+
+Note that using certain UIKit functionality requires the binary to be bundled.
diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md
new file mode 100644
index 00000000000..5045f810400
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/apple-ios.md
@@ -0,0 +1,74 @@
+# `*-apple-ios`
+
+Apple iOS / iPadOS targets.
+
+**Tier: 2 (without Host Tools)**
+
+- `aarch64-apple-ios`: Apple iOS on ARM64.
+- `aarch64-apple-ios-sim`: Apple iOS Simulator on ARM64.
+- `x86_64-apple-ios`: Apple iOS Simulator on 64-bit x86.
+
+**Tier: 3**
+
+- `armv7s-apple-ios`: Apple iOS on Armv7-A.
+- `i386-apple-ios`: Apple iOS Simulator on 32-bit x86.
+
+## Target maintainers
+
+- [@badboy](https://github.com/badboy)
+- [@deg4uss3r](https://github.com/deg4uss3r)
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+These targets are cross-compiled, and require the corresponding iOS SDK
+(`iPhoneOS.sdk` or `iPhoneSimulator.sdk`), as provided by Xcode. To build the
+ARM64 targets, Xcode 12 or higher is required.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is iOS 10.0.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `IPHONEOS_DEPLOYMENT_TARGET`.
+
+## Building the target
+
+The tier 2 targets are distributed through `rustup`, and can be installed
+using one of:
+```console
+$ rustup target add aarch64-apple-ios
+$ rustup target add aarch64-apple-ios-sim
+$ rustup target add x86_64-apple-ios
+```
+
+The tier 3 targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
+
+```toml
+[build]
+target = ["armv7s-apple-ios", "i386-apple-ios"]
+```
+
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+## Building Rust programs
+
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
+
+```console
+$ rustc --target aarch64-apple-ios your-code.rs
+```
+
+## Testing
+
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
+
+It hopefully will be possible to improve this in the future.
diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md
index e7ea109df1b..7a3b601579a 100644
--- a/src/doc/rustc/src/platform-support/apple-tvos.md
+++ b/src/doc/rustc/src/platform-support/apple-tvos.md
@@ -1,40 +1,44 @@
 # `*-apple-tvos`
-- aarch64-apple-tvos
-- x86_64-apple-tvos
+
+Apple tvOS targets.
 
 **Tier: 3**
 
-Apple tvOS targets:
-- Apple tvOS on aarch64
-- Apple tvOS Simulator on x86_64
+- `aarch64-apple-tvos`: Apple tvOS on ARM64.
+- `aarch64-apple-tvos-sim`: Apple tvOS Simulator on ARM64.
+- `x86_64-apple-tvos`: Apple tvOS Simulator on x86_64.
 
 ## Target maintainers
 
-* [@thomcc](https://github.com/thomcc)
+- [@thomcc](https://github.com/thomcc)
+- [@madsmtm](https://github.com/madsmtm)
 
 ## Requirements
 
-These targets are cross-compiled. You will need appropriate versions of Xcode
-and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator
-(`AppleTVSimulator.sdk`) to build a toolchain and target these platforms.
+These targets are cross-compiled, and require the corresponding tvOS SDK
+(`AppleTVOS.sdk` or `AppleTVSimulator.sdk`), as provided by Xcode. To build the
+ARM64 targets, Xcode 12 or higher is required.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
 
-The targets support most (see below) of the standard library including the
-allocator to the best of my knowledge, however they are very new, not yet
-well-tested, and it is possible that there are various bugs.
+### OS version
 
-In theory we support back to tvOS version 7.0, although the actual minimum
-version you can target may be newer than this, for example due to the versions
-of Xcode and your SDKs.
+The minimum supported version is tvOS 10.0, although the actual minimum version
+you can target may be newer than this, for example due to the versions of Xcode
+and your SDKs.
 
-As with the other Apple targets, `rustc` respects the common environment
-variables used by Xcode to configure this, in this case
-`TVOS_DEPLOYMENT_TARGET`.
+The version can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `TVOS_DEPLOYMENT_TARGET`.
 
-#### Incompletely supported library functionality
+### Incompletely supported library functionality
 
-As mentioned, "most" of the standard library is supported, which means that some portions
-are known to be unsupported. The following APIs are currently known to have
-missing or incomplete support:
+The targets support most of the standard library including the allocator to the
+best of my knowledge, however they are very new, not yet well-tested, and it is
+possible that there are various bugs.
+
+The following APIs are currently known to have missing or incomplete support:
 
 - `std::process::Command`'s API will return an error if it is configured in a
   manner which cannot be performed using `posix_spawn` -- this is because the
@@ -47,41 +51,30 @@ missing or incomplete support:
 
 ## Building the target
 
-The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example:
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
 
 ```toml
 [build]
 build-stage = 1
-target = ["aarch64-apple-tvos", "x86_64-apple-tvos", "aarch64-apple-tvos-sim"]
+target = ["aarch64-apple-tvos", "aarch64-apple-tvos-sim"]
 ```
 
-It's possible that cargo under `-Zbuild-std` may also be used to target them.
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
 
 ## Building Rust programs
 
-*Note: Building for this target requires the corresponding TVOS SDK, as provided by Xcode.*
-
-Rust programs can be built for these targets
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
 
-```text
+```console
 $ rustc --target aarch64-apple-tvos your-code.rs
-...
-$ rustc --target x86_64-apple-tvos your-code.rs
-...
-$ rustc --target aarch64-apple-tvos-sim your-code.rs
 ```
 
 ## Testing
 
-There is no support for running the Rust or standard library testsuite on tvOS
-or the simulators at the moment. Testing has mostly been done manually with
-builds of static libraries called from Xcode or a simulator.
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
 
 It hopefully will be possible to improve this in the future.
-
-## Cross-compilation toolchains and C code
-
-This target can be cross-compiled from x86_64 or aarch64 macOS hosts.
-
-Other hosts are not supported for cross-compilation, but might work when also
-providing the required Xcode SDK.
diff --git a/src/doc/rustc/src/platform-support/apple-visionos.md b/src/doc/rustc/src/platform-support/apple-visionos.md
index 9874126e42f..56224d7e20d 100644
--- a/src/doc/rustc/src/platform-support/apple-visionos.md
+++ b/src/doc/rustc/src/platform-support/apple-visionos.md
@@ -1,53 +1,67 @@
-# aarch64-apple-visionos\*
+# `*-apple-visionos`
 
--   aarch64-apple-visionos
--   aarch64-apple-visionos-sim
+Apple visionOS / xrOS targets.
 
 **Tier: 3**
 
-Apple visionOS targets:
-
--   Apple visionOS on arm64
--   Apple visionOS Simulator on arm64
+- `aarch64-apple-visionos`: Apple visionOS on arm64.
+- `aarch64-apple-visionos-sim`: Apple visionOS Simulator on arm64.
 
 ## Target maintainers
 
--   [@agg23](https://github.com/agg23)
--   [@madsmtm](https://github.com/madsmtm)
+- [@agg23](https://github.com/agg23)
+- [@madsmtm](https://github.com/madsmtm)
 
 ## Requirements
 
-These targets are cross-compiled.
-To build these targets Xcode 15 or higher on macOS is required, along with LLVM 18.
+These targets are cross-compiled, and require the corresponding visionOS SDK
+(`XROS.sdk` or `XRSimulator.sdk`), as provided by Xcode 15 or newer.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is visionOS 1.0.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `XROS_DEPLOYMENT_TARGET`.
 
 ## Building the target
 
-The targets can be built by enabling them for a `rustc` build, for example:
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
 
 ```toml
 [build]
-build-stage = 1
-target = ["aarch64-apple-visionos-sim"]
+target = ["aarch64-apple-visionos", "aarch64-apple-visionos-sim"]
 ```
 
-## Building Rust programs
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
 
-_Note: Building for this target requires the corresponding visionOS SDK, as provided by Xcode 15+._
+Note: Currently, a newer version of `libc` and `cc` may be required, this will
+be fixed in [#124560](https://github.com/rust-lang/rust/pull/124560).
+
+## Building Rust programs
 
-Rust programs can be built for these targets, if `rustc` has been built with support for them, for example:
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
 
-```text
-rustc --target aarch64-apple-visionos-sim your-code.rs
+```console
+$ rustc --target aarch64-apple-visionos-sim your-code.rs
 ```
 
 ## Testing
 
-There is no support for running the Rust testsuite on visionOS or the simulators.
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
 
-There is no easy way to run simple programs on visionOS or the visionOS simulators. Static library builds can be embedded into visionOS applications.
+It hopefully will be possible to improve this in the future.
 
 ## Cross-compilation toolchains and C code
 
-This target can be cross-compiled from x86_64 or aarch64 macOS hosts.
+The Clang target is suffixed with `-xros` for historical reasons.
 
-Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+LLVM 18 or newer is required to build this target.
diff --git a/src/doc/rustc/src/platform-support/apple-watchos.md b/src/doc/rustc/src/platform-support/apple-watchos.md
index 7be2467352c..8ba35f70b85 100644
--- a/src/doc/rustc/src/platform-support/apple-watchos.md
+++ b/src/doc/rustc/src/platform-support/apple-watchos.md
@@ -1,58 +1,65 @@
-# *-apple-watchos
-- arm64_32-apple-watchos
-- armv7k-apple-watchos
-- aarch64-apple-watchos
-- aarch64-apple-watchos-sim
-- x86_64-apple-watchos-sim
+# `*-apple-watchos`
+
+Apple watchOS targets.
 
 **Tier: 3**
 
-Apple WatchOS targets:
-- Apple WatchOS on Arm 64_32
-- Apple WatchOS on Arm v7k
-- Apple WatchOS on Arm 64
-- Apple WatchOS Simulator on arm64
-- Apple WatchOS Simulator on x86_64
+- `aarch64-apple-watchos`: Apple WatchOS on ARM64.
+- `aarch64-apple-watchos-sim`: Apple WatchOS Simulator on ARM64.
+- `x86_64-apple-watchos-sim`: Apple WatchOS Simulator on 64-bit x86.
+- `arm64_32-apple-watchos`: Apple WatchOS on Arm 64_32.
+- `armv7k-apple-watchos`: Apple WatchOS on Armv7k.
 
 ## Target maintainers
 
-* [@deg4uss3r](https://github.com/deg4uss3r)
-* [@vladimir-ea](https://github.com/vladimir-ea)
-* [@leohowell](https://github.com/leohowell)
+- [@deg4uss3r](https://github.com/deg4uss3r)
+- [@vladimir-ea](https://github.com/vladimir-ea)
+- [@leohowell](https://github.com/leohowell)
+- [@madsmtm](https://github.com/madsmtm)
 
 ## Requirements
 
-These targets are cross-compiled.
-To build these targets Xcode 12 or higher on macOS is required.
+These targets are cross-compiled, and require the corresponding watchOS SDK
+(`WatchOS.sdk` or `WatchSimulator.sdk`), as provided by Xcode. To build the
+ARM64 targets, Xcode 12 or higher is required.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is watchOS 5.0.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `WATCHOS_DEPLOYMENT_TARGET`.
 
 ## Building the target
 
-The targets can be built by enabling them for a `rustc` build, for example:
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
 
 ```toml
 [build]
 build-stage = 1
-target = ["aarch64-apple-watchos-sim"]
+target = ["aarch64-apple-watchos", "aarch64-apple-watchos-sim"]
 ```
 
-## Building Rust programs
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
 
-*Note: Building for this target requires the corresponding WatchOS SDK, as provided by Xcode 12+.*
+## Building Rust programs
 
-Rust programs can be built for these targets, if `rustc` has been built with support for them, for example:
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
 
-```text
-rustc --target aarch64-apple-watchos-sim your-code.rs
+```console
+$ rustc --target aarch64-apple-watchos-sim your-code.rs
 ```
 
 ## Testing
 
-There is no support for running the Rust testsuite on WatchOS or the simulators.
-
-There is no easy way to run simple programs on WatchOS or the WatchOS simulators. Static library builds can be embedded into WatchOS applications.
-
-## Cross-compilation toolchains and C code
-
-This target can be cross-compiled from x86_64 or aarch64 macOS hosts.
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
 
-Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+It hopefully will be possible to improve this in the future.
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
index d9b9aeae1ae..4d98b3a6098 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
@@ -12,6 +12,8 @@ ARM64e macOS (11.0+, Big Sur+)
 
 Target for `macOS` on late-generation `M` series Apple chips.
 
+See the docs on [`*-apple-darwin`](apple-darwin.md) for general macOS requirements.
+
 ## Building the target
 
 You can build Rust with support for the targets by adding it to the `target` list in `config.toml`:
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
index 0215621be3d..3c878f7250e 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
@@ -10,8 +10,7 @@ ARM64e iOS (12.0+)
 
 ## Requirements
 
-These targets only support cross-compilation.
-The targets do support `std`.
+See the docs on [`*-apple-ios`](apple-ios.md) for general iOS requirements.
 
 ## Building the target
 
diff --git a/src/doc/rustc/src/platform-support/i686-apple-darwin.md b/src/doc/rustc/src/platform-support/i686-apple-darwin.md
new file mode 100644
index 00000000000..d69fa97ce63
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/i686-apple-darwin.md
@@ -0,0 +1,41 @@
+# `i686-apple-darwin`
+
+Apple macOS on 32-bit x86.
+
+## Target maintainers
+
+- [@thomcc](https://github.com/thomcc)
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+See the docs on [`*-apple-darwin`](apple-darwin.md) for general macOS requirements.
+
+## Building the target
+
+You'll need the macOS 10.13 SDK shipped with Xcode 9. The location of the SDK
+can be passed to `rustc` using the common `SDKROOT` environment variable.
+
+Once you have that, you can build Rust with support for the target by adding
+it to the `target` list in `config.toml`:
+
+```toml
+[build]
+target = ["i686-apple-darwin"]
+```
+
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+## Building Rust programs
+
+Rust [no longer] ships pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy using `build-std` or
+similar.
+
+[no longer]: https://blog.rust-lang.org/2020/01/03/reducing-support-for-32-bit-apple-targets.html
+
+## Testing
+
+Running this target requires an Intel Macbook running macOS 10.14 or earlier,
+as later versions removed support for running 32-bit binaries.
diff --git a/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md b/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
index 0fe9d4edaca..6c2a6a41101 100644
--- a/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
@@ -23,9 +23,8 @@ default or user-defined allocators). This target is probably most useful when
 targeted via cross-compilation (including from `x86_64-apple-darwin`), but if
 built manually, the host tools work.
 
-It is similar to `x86_64-apple-darwin` in nearly all respects, although the
-minimum supported OS version is slightly higher (it requires 10.8 rather than
-`x86_64-apple-darwin`'s 10.7).
+It is similar to [`x86_64-apple-darwin`](apple-darwin.md) in nearly all
+respects.
 
 ## Building the target
 
diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs
index 848cbd5ed99..ac7d422ec80 100644
--- a/src/librustdoc/passes/strip_aliased_non_local.rs
+++ b/src/librustdoc/passes/strip_aliased_non_local.rs
@@ -46,8 +46,13 @@ impl<'tcx> DocFolder for NonLocalStripper<'tcx> {
         // the field and not the one given by the user for the currrent crate.
         //
         // FIXME(#125009): Not-local should probably consider same Cargo workspace
-        if !i.def_id().map_or(true, |did| did.is_local()) {
-            if i.visibility(self.tcx) != Some(Visibility::Public) || i.is_doc_hidden() {
+        if let Some(def_id) = i.def_id()
+            && !def_id.is_local()
+        {
+            if i.is_doc_hidden()
+                // Default to *not* stripping items with inherited visibility.
+                || i.visibility(self.tcx).map_or(false, |viz| viz != Visibility::Public)
+            {
                 return Some(strip_item(i));
             }
         }
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 5399a24c66cb6164cf32280e7d300488c90d576
+Subproject b31c30a9bb4dbbd13c359d0e2bea7f65d20adf3
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 0de7f2ec6c39d68022e6b97a39559d2f4dbf393
+Subproject 84dc5dc11a9007a08f27170454da6097265e510
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index 2eafdd0fbc8..09202b1878b 100755
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -2,15 +2,18 @@
 
 set -ex
 
+sysroot="$(rustc --print sysroot)"
+case $OS in
+    Linux) export LD_LIBRARY_PATH="$sysroot/lib" ;;
+    macOS) export DYLD_FALLBACK_LIBRARY_PATH="$sysroot/lib" ;;
+    Windows) export PATH="$(cygpath "$sysroot")/bin:$PATH" ;;
+    *) exit 1
+esac
+
 # Check sysroot handling
-sysroot=$(./target/debug/clippy-driver --print sysroot)
-test "$sysroot" = "$(rustc --print sysroot)"
-
-if [[ ${OS} == "Windows" ]]; then
-	desired_sysroot=C:/tmp
-else
-	desired_sysroot=/tmp
-fi
+test "$(./target/debug/clippy-driver --print sysroot)" = "$sysroot"
+
+desired_sysroot="target/sysroot"
 # Set --sysroot in command line
 sysroot=$(./target/debug/clippy-driver --sysroot $desired_sysroot --print sysroot)
 test "$sysroot" = $desired_sysroot
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 8179e3e65b5..06bf3b6fdbf 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -69,6 +69,6 @@ jobs:
       working-directory: clippy_dev
 
     - name: Test clippy-driver
-      run: |
-        TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
-        rustup run $TOOLCHAIN bash .github/driver.sh
+      run: .github/driver.sh
+      env:
+        OS: ${{ runner.os }}
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 94515987eba..1f4bec92918 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -116,9 +116,7 @@ jobs:
       working-directory: clippy_dev
 
     - name: Test clippy-driver
-      run: |
-        TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
-        rustup run $TOOLCHAIN bash .github/driver.sh
+      run: .github/driver.sh
       env:
         OS: ${{ runner.os }}
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 9c9ea114081..d5115f70f66 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5249,6 +5249,7 @@ Released 2018-09-13
 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
+[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
 [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
@@ -5447,6 +5448,7 @@ Released 2018-09-13
 [`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes
 [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
+[`macro_metavars_in_unsafe`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe
 [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
@@ -5702,6 +5704,7 @@ Released 2018-09-13
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
+[`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
@@ -5908,6 +5911,7 @@ Released 2018-09-13
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 [`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
+[`while_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_float
 [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
@@ -5939,8 +5943,10 @@ Released 2018-09-13
 [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests
 [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args
 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
+[`allow-panic-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-tests
 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests
 [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception
+[`allow-renamed-params-for`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-renamed-params-for
 [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests
 [`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests
 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
@@ -6002,4 +6008,5 @@ Released 2018-09-13
 [`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold
 [`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold
 [`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports
+[`warn-unsafe-macro-metavars-in-private-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-unsafe-macro-metavars-in-private-macros
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index f6af9810ca1..c8223007df7 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -101,6 +101,16 @@ Whether to allow `r#""#` when `r""` can be used
 * [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
 
 
+## `allow-panic-in-tests`
+Whether `panic` should be allowed in test functions or `#[cfg(test)]`
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`panic`](https://rust-lang.github.io/rust-clippy/master/index.html#panic)
+
+
 ## `allow-print-in-tests`
 Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
 
@@ -122,6 +132,28 @@ Whether to allow module inception if it's not public.
 * [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception)
 
 
+## `allow-renamed-params-for`
+List of trait paths to ignore when checking renamed function parameters.
+
+#### Example
+
+```toml
+allow-renamed-params-for = [ "std::convert::From" ]
+```
+
+#### Noteworthy
+
+- By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
+- `".."` can be used as part of the list to indicate that the configured values should be appended to the
+default configuration of Clippy. By default, any configuration will replace the default value.
+
+**Default Value:** `["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"]`
+
+---
+**Affected lints:**
+* [`renamed_function_params`](https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params)
+
+
 ## `allow-unwrap-in-tests`
 Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
 
@@ -900,3 +932,13 @@ Whether to allow certain wildcard imports (prelude, super in tests).
 * [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
 
 
+## `warn-unsafe-macro-metavars-in-private-macros`
+Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`macro_metavars_in_unsafe`](https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe)
+
+
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 5cfcbdb57d7..cfdf620b7d0 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -40,6 +40,8 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
 const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
 const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
 const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
+const DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS: &[&str] =
+    &["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"];
 
 /// Conf with parse errors
 #[derive(Default)]
@@ -455,6 +457,10 @@ define_Conf! {
     ///
     /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
     (allow_unwrap_in_tests: bool = false),
+    /// Lint: PANIC.
+    ///
+    /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
+    (allow_panic_in_tests: bool = false),
     /// Lint: DBG_MACRO.
     ///
     /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
@@ -613,6 +619,27 @@ define_Conf! {
     /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value
     (allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
+    /// Lint: RENAMED_FUNCTION_PARAMS.
+    ///
+    /// List of trait paths to ignore when checking renamed function parameters.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allow-renamed-params-for = [ "std::convert::From" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
+    /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value.
+    (allow_renamed_params_for: Vec<String> =
+        DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()),
+    /// Lint: MACRO_METAVARS_IN_UNSAFE.
+    ///
+    /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
+    (warn_unsafe_macro_metavars_in_private_macros: bool = false),
 }
 
 /// Search for the configuration file.
@@ -674,6 +701,10 @@ fn deserialize(file: &SourceFile) -> TryConf {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
             extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES);
+            extend_vec_if_indicator_present(
+                &mut conf.conf.allow_renamed_params_for,
+                DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS,
+            );
             // TODO: THIS SHOULD BE TESTED, this comment will be gone soon
             if conf.conf.allowed_idents_below_min_chars.contains("..") {
                 conf.conf
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 14808440d48..a3e7d0c3fa5 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -26,7 +26,8 @@ msrv_aliases! {
     1,63,0 { CLONE_INTO }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
-    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
+    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
+    1,56,0 { CONST_FN_UNION }
     1,55,0 { SEEK_REWIND }
     1,54,0 { INTO_KEYS }
     1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 42a953039b1..4104e7d94f1 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -1,11 +1,12 @@
 [package]
 name = "clippy_dev"
+description = "Clippy developer tooling"
 version = "0.0.1"
 edition = "2021"
 
 [dependencies]
 aho-corasick = "1.0"
-clap = "4.1.4"
+clap = { version = "4.4", features = ["derive"] }
 indoc = "1.0"
 itertools = "0.12"
 opener = "0.6"
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 397a0e99082..366b52b25df 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -2,350 +2,292 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use clap::{Arg, ArgAction, ArgMatches, Command};
+use clap::{Args, Parser, Subcommand};
 use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints};
-use indoc::indoc;
 use std::convert::Infallible;
 
 fn main() {
-    let matches = get_clap_config();
+    let dev = Dev::parse();
 
-    match matches.subcommand() {
-        Some(("bless", _)) => {
+    match dev.command {
+        DevCommand::Bless => {
             eprintln!("use `cargo bless` to automatically replace `.stderr` and `.fixed` files as tests are being run");
         },
-        Some(("dogfood", matches)) => {
-            dogfood::dogfood(
-                matches.get_flag("fix"),
-                matches.get_flag("allow-dirty"),
-                matches.get_flag("allow-staged"),
-            );
-        },
-        Some(("fmt", matches)) => {
-            fmt::run(matches.get_flag("check"), matches.get_flag("verbose"));
-        },
-        Some(("update_lints", matches)) => {
-            if matches.get_flag("print-only") {
+        DevCommand::Dogfood {
+            fix,
+            allow_dirty,
+            allow_staged,
+        } => dogfood::dogfood(fix, allow_dirty, allow_staged),
+        DevCommand::Fmt { check, verbose } => fmt::run(check, verbose),
+        DevCommand::UpdateLints { print_only, check } => {
+            if print_only {
                 update_lints::print_lints();
-            } else if matches.get_flag("check") {
+            } else if check {
                 update_lints::update(update_lints::UpdateMode::Check);
             } else {
                 update_lints::update(update_lints::UpdateMode::Change);
             }
         },
-        Some(("new_lint", matches)) => {
-            match new_lint::create(
-                matches.get_one::<String>("pass").unwrap(),
-                matches.get_one::<String>("name"),
-                matches.get_one::<String>("category").map(String::as_str),
-                matches.get_one::<String>("type").map(String::as_str),
-                matches.get_flag("msrv"),
-            ) {
-                Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
-                Err(e) => eprintln!("Unable to create lint: {e}"),
-            }
+        DevCommand::NewLint {
+            pass,
+            name,
+            category,
+            r#type,
+            msrv,
+        } => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) {
+            Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
+            Err(e) => eprintln!("Unable to create lint: {e}"),
         },
-        Some(("setup", sub_command)) => match sub_command.subcommand() {
-            Some(("git-hook", matches)) => {
-                if matches.get_flag("remove") {
-                    setup::git_hook::remove_hook();
+        DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
+            SetupSubcommand::Intellij { remove, repo_path } => {
+                if remove {
+                    setup::intellij::remove_rustc_src();
                 } else {
-                    setup::git_hook::install_hook(matches.get_flag("force-override"));
+                    setup::intellij::setup_rustc_src(&repo_path);
                 }
             },
-            Some(("intellij", matches)) => {
-                if matches.get_flag("remove") {
-                    setup::intellij::remove_rustc_src();
+            SetupSubcommand::GitHook { remove, force_override } => {
+                if remove {
+                    setup::git_hook::remove_hook();
                 } else {
-                    setup::intellij::setup_rustc_src(
-                        matches
-                            .get_one::<String>("rustc-repo-path")
-                            .expect("this field is mandatory and therefore always valid"),
-                    );
+                    setup::git_hook::install_hook(force_override);
                 }
             },
-            Some(("toolchain", matches)) => {
-                setup::toolchain::create(
-                    matches.get_flag("force"),
-                    matches.get_flag("release"),
-                    matches.get_one::<String>("name").unwrap(),
-                );
-            },
-            Some(("vscode-tasks", matches)) => {
-                if matches.get_flag("remove") {
+            SetupSubcommand::Toolchain { force, release, name } => setup::toolchain::create(force, release, &name),
+            SetupSubcommand::VscodeTasks { remove, force_override } => {
+                if remove {
                     setup::vscode::remove_tasks();
                 } else {
-                    setup::vscode::install_tasks(matches.get_flag("force-override"));
+                    setup::vscode::install_tasks(force_override);
                 }
             },
-            _ => {},
-        },
-        Some(("remove", sub_command)) => match sub_command.subcommand() {
-            Some(("git-hook", _)) => setup::git_hook::remove_hook(),
-            Some(("intellij", _)) => setup::intellij::remove_rustc_src(),
-            Some(("vscode-tasks", _)) => setup::vscode::remove_tasks(),
-            _ => {},
-        },
-        Some(("serve", matches)) => {
-            let port = *matches.get_one::<u16>("port").unwrap();
-            let lint = matches.get_one::<String>("lint");
-            serve::run(port, lint);
         },
-        Some(("lint", matches)) => {
-            let path = matches.get_one::<String>("path").unwrap();
-            let args = matches.get_many::<String>("args").into_iter().flatten();
-            lint::run(path, args);
+        DevCommand::Remove(RemoveCommand { subcommand }) => match subcommand {
+            RemoveSubcommand::Intellij => setup::intellij::remove_rustc_src(),
+            RemoveSubcommand::GitHook => setup::git_hook::remove_hook(),
+            RemoveSubcommand::VscodeTasks => setup::vscode::remove_tasks(),
         },
-        Some(("rename_lint", matches)) => {
-            let old_name = matches.get_one::<String>("old_name").unwrap();
-            let new_name = matches.get_one::<String>("new_name").unwrap_or(old_name);
-            let uplift = matches.get_flag("uplift");
-            update_lints::rename(old_name, new_name, uplift);
-        },
-        Some(("deprecate", matches)) => {
-            let name = matches.get_one::<String>("name").unwrap();
-            let reason = matches.get_one("reason");
-            update_lints::deprecate(name, reason);
-        },
-        _ => {},
+        DevCommand::Serve { port, lint } => serve::run(port, lint),
+        DevCommand::Lint { path, args } => lint::run(&path, args.iter()),
+        DevCommand::RenameLint {
+            old_name,
+            new_name,
+            uplift,
+        } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
+        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, reason.as_deref()),
     }
 }
 
-fn get_clap_config() -> ArgMatches {
-    Command::new("Clippy developer tooling")
-        .arg_required_else_help(true)
-        .subcommands([
-            Command::new("bless").about("bless the test output changes").arg(
-                Arg::new("ignore-timestamp")
-                    .long("ignore-timestamp")
-                    .action(ArgAction::SetTrue)
-                    .help("Include files updated before clippy was built"),
-            ),
-            Command::new("dogfood").about("Runs the dogfood test").args([
-                Arg::new("fix")
-                    .long("fix")
-                    .action(ArgAction::SetTrue)
-                    .help("Apply the suggestions when possible"),
-                Arg::new("allow-dirty")
-                    .long("allow-dirty")
-                    .action(ArgAction::SetTrue)
-                    .help("Fix code even if the working directory has changes")
-                    .requires("fix"),
-                Arg::new("allow-staged")
-                    .long("allow-staged")
-                    .action(ArgAction::SetTrue)
-                    .help("Fix code even if the working directory has staged changes")
-                    .requires("fix"),
-            ]),
-            Command::new("fmt")
-                .about("Run rustfmt on all projects and tests")
-                .args([
-                    Arg::new("check")
-                        .long("check")
-                        .action(ArgAction::SetTrue)
-                        .help("Use the rustfmt --check option"),
-                    Arg::new("verbose")
-                        .short('v')
-                        .long("verbose")
-                        .action(ArgAction::SetTrue)
-                        .help("Echo commands run"),
-                ]),
-            Command::new("update_lints")
-                .about("Updates lint registration and information from the source code")
-                .long_about(
-                    "Makes sure that:\n \
-                    * the lint count in README.md is correct\n \
-                    * the changelog contains markdown link references at the bottom\n \
-                    * all lint groups include the correct lints\n \
-                    * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
-                    * all lints are registered in the lint store",
-                )
-                .args([
-                    Arg::new("print-only")
-                        .long("print-only")
-                        .action(ArgAction::SetTrue)
-                        .help(
-                            "Print a table of lints to STDOUT. \
-                            This does not include deprecated and internal lints. \
-                            (Does not modify any files)",
-                        ),
-                    Arg::new("check")
-                        .long("check")
-                        .action(ArgAction::SetTrue)
-                        .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
-                ]),
-            Command::new("new_lint")
-                .about("Create new lint and run `cargo dev update_lints`")
-                .args([
-                    Arg::new("pass")
-                        .short('p')
-                        .long("pass")
-                        .help("Specify whether the lint runs during the early or late pass")
-                        .value_parser(["early", "late"])
-                        .conflicts_with("type")
-                        .default_value("late"),
-                    Arg::new("name")
-                        .short('n')
-                        .long("name")
-                        .help("Name of the new lint in snake case, ex: fn_too_long")
-                        .required(true)
-                        .value_parser(|name: &str| Ok::<_, Infallible>(name.replace('-', "_"))),
-                    Arg::new("category")
-                        .short('c')
-                        .long("category")
-                        .help("What category the lint belongs to")
-                        .default_value("nursery")
-                        .value_parser([
-                            "style",
-                            "correctness",
-                            "suspicious",
-                            "complexity",
-                            "perf",
-                            "pedantic",
-                            "restriction",
-                            "cargo",
-                            "nursery",
-                            "internal",
-                        ]),
-                    Arg::new("type").long("type").help("What directory the lint belongs in"),
-                    Arg::new("msrv")
-                        .long("msrv")
-                        .action(ArgAction::SetTrue)
-                        .help("Add MSRV config code to the lint"),
-                ]),
-            Command::new("setup")
-                .about("Support for setting up your personal development environment")
-                .arg_required_else_help(true)
-                .subcommands([
-                    Command::new("git-hook")
-                        .about("Add a pre-commit git hook that formats your code to make it look pretty")
-                        .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
-                            Arg::new("force-override")
-                                .long("force-override")
-                                .short('f')
-                                .action(ArgAction::SetTrue)
-                                .help("Forces the override of an existing git pre-commit hook"),
-                        ]),
-                    Command::new("intellij")
-                        .about("Alter dependencies so Intellij Rust can find rustc internals")
-                        .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the dependencies added with 'cargo dev setup intellij'"),
-                            Arg::new("rustc-repo-path")
-                                .long("repo-path")
-                                .short('r')
-                                .help("The path to a rustc repo that will be used for setting the dependencies")
-                                .value_name("path")
-                                .conflicts_with("remove")
-                                .required(true),
-                        ]),
-                    Command::new("toolchain")
-                        .about("Install a rustup toolchain pointing to the local clippy build")
-                        .args([
-                            Arg::new("force")
-                                .long("force")
-                                .short('f')
-                                .action(ArgAction::SetTrue)
-                                .help("Override an existing toolchain"),
-                            Arg::new("release")
-                                .long("release")
-                                .short('r')
-                                .action(ArgAction::SetTrue)
-                                .help("Point to --release clippy binaries"),
-                            Arg::new("name")
-                                .long("name")
-                                .default_value("clippy")
-                                .help("The name of the created toolchain"),
-                        ]),
-                    Command::new("vscode-tasks")
-                        .about("Add several tasks to vscode for formatting, validation and testing")
-                        .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the tasks added with 'cargo dev setup vscode-tasks'"),
-                            Arg::new("force-override")
-                                .long("force-override")
-                                .short('f')
-                                .action(ArgAction::SetTrue)
-                                .help("Forces the override of existing vscode tasks"),
-                        ]),
-                ]),
-            Command::new("remove")
-                .about("Support for undoing changes done by the setup command")
-                .arg_required_else_help(true)
-                .subcommands([
-                    Command::new("git-hook").about("Remove any existing pre-commit git hook"),
-                    Command::new("vscode-tasks").about("Remove any existing vscode tasks"),
-                    Command::new("intellij").about("Removes rustc source paths added via `cargo dev setup intellij`"),
-                ]),
-            Command::new("serve")
-                .about("Launch a local 'ALL the Clippy Lints' website in a browser")
-                .args([
-                    Arg::new("port")
-                        .long("port")
-                        .short('p')
-                        .help("Local port for the http server")
-                        .default_value("8000")
-                        .value_parser(clap::value_parser!(u16)),
-                    Arg::new("lint").help("Which lint's page to load initially (optional)"),
-                ]),
-            Command::new("lint")
-                .about("Manually run clippy on a file or package")
-                .after_help(indoc! {"
-                    EXAMPLES
-                        Lint a single file:
-                            cargo dev lint tests/ui/attrs.rs
+#[derive(Parser)]
+#[command(name = "dev", about)]
+struct Dev {
+    #[command(subcommand)]
+    command: DevCommand,
+}
 
-                        Lint a package directory:
-                            cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
-                            cargo dev lint ~/my-project
+#[derive(Subcommand)]
+enum DevCommand {
+    /// Bless the test output changes
+    Bless,
+    /// Runs the dogfood test
+    Dogfood {
+        #[arg(long)]
+        /// Apply the suggestions when possible
+        fix: bool,
+        #[arg(long, requires = "fix")]
+        /// Fix code even if the working directory has changes
+        allow_dirty: bool,
+        #[arg(long, requires = "fix")]
+        /// Fix code even if the working directory has staged changes
+        allow_staged: bool,
+    },
+    /// Run rustfmt on all projects and tests
+    Fmt {
+        #[arg(long)]
+        /// Use the rustfmt --check option
+        check: bool,
+        #[arg(short, long)]
+        /// Echo commands run
+        verbose: bool,
+    },
+    #[command(name = "update_lints")]
+    /// Updates lint registration and information from the source code
+    ///
+    /// Makes sure that: {n}
+    /// * the lint count in README.md is correct {n}
+    /// * the changelog contains markdown link references at the bottom {n}
+    /// * all lint groups include the correct lints {n}
+    /// * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod` {n}
+    /// * all lints are registered in the lint store
+    UpdateLints {
+        #[arg(long)]
+        /// Print a table of lints to STDOUT
+        ///
+        /// This does not include deprecated and internal lints. (Does not modify any files)
+        print_only: bool,
+        #[arg(long)]
+        /// Checks that `cargo dev update_lints` has been run. Used on CI.
+        check: bool,
+    },
+    #[command(name = "new_lint")]
+    /// Create a new lint and run `cargo dev update_lints`
+    NewLint {
+        #[arg(short, long, value_parser = ["early", "late"], conflicts_with = "type", default_value = "late")]
+        /// Specify whether the lint runs during the early or late pass
+        pass: String,
+        #[arg(
+            short,
+            long,
+            value_parser = |name: &str| Ok::<_, Infallible>(name.replace('-', "_")),
+        )]
+        /// Name of the new lint in snake case, ex: `fn_too_long`
+        name: String,
+        #[arg(
+            short,
+            long,
+            value_parser = [
+                "style",
+                "correctness",
+                "suspicious",
+                "complexity",
+                "perf",
+                "pedantic",
+                "restriction",
+                "cargo",
+                "nursery",
+                "internal",
+            ],
+            default_value = "nursery",
+        )]
+        /// What category the lint belongs to
+        category: String,
+        #[arg(long)]
+        /// What directory the lint belongs in
+        r#type: Option<String>,
+        #[arg(long)]
+        /// Add MSRV config code to the lint
+        msrv: bool,
+    },
+    /// Support for setting up your personal development environment
+    Setup(SetupCommand),
+    /// Support for removing changes done by the setup command
+    Remove(RemoveCommand),
+    /// Launch a local 'ALL the Clippy Lints' website in a browser
+    Serve {
+        #[arg(short, long, default_value = "8000")]
+        /// Local port for the http server
+        port: u16,
+        #[arg(long)]
+        /// Which lint's page to load initially (optional)
+        lint: Option<String>,
+    },
+    #[allow(clippy::doc_markdown)]
+    /// Manually run clippy on a file or package
+    ///
+    /// ## Examples
+    ///
+    /// Lint a single file: {n}
+    ///     cargo dev lint tests/ui/attrs.rs
+    ///
+    /// Lint a package directory: {n}
+    ///     cargo dev lint tests/ui-cargo/wildcard_dependencies/fail {n}
+    ///     cargo dev lint ~/my-project
+    ///
+    /// Run rustfix: {n}
+    ///     cargo dev lint ~/my-project -- --fix
+    ///
+    /// Set lint levels: {n}
+    ///     cargo dev lint file.rs -- -W clippy::pedantic {n}
+    ///     cargo dev lint ~/my-project -- -- -W clippy::pedantic
+    Lint {
+        /// The path to a file or package directory to lint
+        path: String,
+        /// Pass extra arguments to cargo/clippy-driver
+        args: Vec<String>,
+    },
+    #[command(name = "rename_lint")]
+    /// Rename a lint
+    RenameLint {
+        /// The name of the lint to rename
+        old_name: String,
+        #[arg(required_unless_present = "uplift")]
+        /// The new name of the lint
+        new_name: Option<String>,
+        #[arg(long)]
+        /// This lint will be uplifted into rustc
+        uplift: bool,
+    },
+    /// Deprecate the given lint
+    Deprecate {
+        /// The name of the lint to deprecate
+        name: String,
+        #[arg(long, short)]
+        /// The reason for deprecation
+        reason: Option<String>,
+    },
+}
 
-                        Run rustfix:
-                            cargo dev lint ~/my-project -- --fix
+#[derive(Args)]
+struct SetupCommand {
+    #[command(subcommand)]
+    subcommand: SetupSubcommand,
+}
+
+#[derive(Subcommand)]
+enum SetupSubcommand {
+    /// Alter dependencies so Intellij Rust can find rustc internals
+    Intellij {
+        #[arg(long)]
+        /// Remove the dependencies added with 'cargo dev setup intellij'
+        remove: bool,
+        #[arg(long, short, conflicts_with = "remove")]
+        /// The path to a rustc repo that will be used for setting the dependencies
+        repo_path: String,
+    },
+    /// Add a pre-commit git hook that formats your code to make it look pretty
+    GitHook {
+        #[arg(long)]
+        /// Remove the pre-commit hook added with 'cargo dev setup git-hook'
+        remove: bool,
+        #[arg(long, short)]
+        /// Forces the override of an existing git pre-commit hook
+        force_override: bool,
+    },
+    /// Install a rustup toolchain pointing to the local clippy build
+    Toolchain {
+        #[arg(long, short)]
+        /// Override an existing toolchain
+        force: bool,
+        #[arg(long, short)]
+        /// Point to --release clippy binary
+        release: bool,
+        #[arg(long, default_value = "clippy")]
+        /// Name of the toolchain
+        name: String,
+    },
+    /// Add several tasks to vscode for formatting, validation and testing
+    VscodeTasks {
+        #[arg(long)]
+        /// Remove the tasks added with 'cargo dev setup vscode-tasks'
+        remove: bool,
+        #[arg(long, short)]
+        /// Forces the override of existing vscode tasks
+        force_override: bool,
+    },
+}
+
+#[derive(Args)]
+struct RemoveCommand {
+    #[command(subcommand)]
+    subcommand: RemoveSubcommand,
+}
 
-                        Set lint levels:
-                            cargo dev lint file.rs -- -W clippy::pedantic
-                            cargo dev lint ~/my-project -- -- -W clippy::pedantic
-                "})
-                .args([
-                    Arg::new("path")
-                        .required(true)
-                        .help("The path to a file or package directory to lint"),
-                    Arg::new("args")
-                        .action(ArgAction::Append)
-                        .help("Pass extra arguments to cargo/clippy-driver"),
-                ]),
-            Command::new("rename_lint").about("Renames the given lint").args([
-                Arg::new("old_name")
-                    .index(1)
-                    .required(true)
-                    .help("The name of the lint to rename"),
-                Arg::new("new_name")
-                    .index(2)
-                    .required_unless_present("uplift")
-                    .help("The new name of the lint"),
-                Arg::new("uplift")
-                    .long("uplift")
-                    .action(ArgAction::SetTrue)
-                    .help("This lint will be uplifted into rustc"),
-            ]),
-            Command::new("deprecate").about("Deprecates the given lint").args([
-                Arg::new("name")
-                    .index(1)
-                    .required(true)
-                    .help("The name of the lint to deprecate"),
-                Arg::new("reason")
-                    .long("reason")
-                    .short('r')
-                    .help("The reason for deprecation"),
-            ]),
-        ])
-        .get_matches()
+#[derive(Subcommand)]
+enum RemoveSubcommand {
+    /// Remove the dependencies added with 'cargo dev setup intellij'
+    Intellij,
+    /// Remove the pre-commit git hook
+    GitHook,
+    /// Remove the tasks added with 'cargo dev setup vscode-tasks'
+    VscodeTasks,
 }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 2940d56350f..b6481dde4dd 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -36,22 +36,16 @@ impl<T> Context for io::Result<T> {
 /// # Errors
 ///
 /// This function errors out if the files couldn't be created or written to.
-pub fn create(
-    pass: &String,
-    lint_name: Option<&String>,
-    category: Option<&str>,
-    mut ty: Option<&str>,
-    msrv: bool,
-) -> io::Result<()> {
-    if category == Some("cargo") && ty.is_none() {
+pub fn create(pass: &str, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> {
+    if category == "cargo" && ty.is_none() {
         // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo`
         ty = Some("cargo");
     }
 
     let lint = LintData {
         pass,
-        name: lint_name.expect("`name` argument is validated by clap"),
-        category: category.expect("`category` argument is validated by clap"),
+        name,
+        category,
         ty,
         project_root: clippy_project_root(),
     };
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index ea925f6709f..4a4261d1a1e 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -8,7 +8,7 @@ use std::{env, thread};
 /// # Panics
 ///
 /// Panics if the python commands could not be spawned
-pub fn run(port: u16, lint: Option<&String>) -> ! {
+pub fn run(port: u16, lint: Option<String>) -> ! {
     let mut url = Some(match lint {
         None => format!("http://localhost:{port}"),
         Some(lint) => format!("http://localhost:{port}/#{lint}"),
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 625b1339591..45353901c98 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -314,7 +314,7 @@ const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note";
 /// # Panics
 ///
 /// If a file path could not read from or written to
-pub fn deprecate(name: &str, reason: Option<&String>) {
+pub fn deprecate(name: &str, reason: Option<&str>) {
     fn finish(
         (lints, mut deprecated_lints, renamed_lints): (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>),
         name: &str,
@@ -335,7 +335,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) {
         println!("note: you must run `cargo uitest` to update the test results");
     }
 
-    let reason = reason.map_or(DEFAULT_DEPRECATION_REASON, String::as_str);
+    let reason = reason.unwrap_or(DEFAULT_DEPRECATION_REASON);
     let name_lower = name.to_lowercase();
     let name_upper = name.to_uppercase();
 
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index f0dafb1ae0d..e94a6f3e3fc 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -2,15 +2,15 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::HirNode;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_trait_method, path_to_local};
+use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, Expr, ExprKind, Node};
+use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
-use rustc_span::ExpnKind;
+use rustc_span::{ExpnKind, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,6 +36,7 @@ declare_clippy_lint! {
     /// Use instead:
     /// ```rust
     /// struct Thing;
+    ///
     /// impl Clone for Thing {
     ///     fn clone(&self) -> Self { todo!() }
     ///     fn clone_from(&mut self, other: &Self) { todo!() }
@@ -47,7 +48,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.78.0"]
     pub ASSIGNING_CLONES,
-    perf,
+    pedantic,
     "assigning the result of cloning may be inefficient"
 }
 
@@ -67,7 +68,8 @@ impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
         // Do not fire the lint in macros
-        let expn_data = assign_expr.span().ctxt().outer_expn_data();
+        let ctxt = assign_expr.span().ctxt();
+        let expn_data = ctxt.outer_expn_data();
         match expn_data.kind {
             ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return,
             ExpnKind::Root => {},
@@ -82,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
         };
 
         if is_ok_to_suggest(cx, lhs, &call, &self.msrv) {
-            suggest(cx, assign_expr, lhs, &call);
+            suggest(cx, ctxt, assign_expr, lhs, &call);
         }
     }
 
@@ -163,9 +165,7 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
         // TODO: This check currently bails if the local variable has no initializer.
         // That is overly conservative - the lint should fire even if there was no initializer,
         // but the variable has been initialized before `lhs` was evaluated.
-        if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p))
-            && local.init.is_none()
-        {
+        if !local_is_initialized(cx, local) {
             return false;
         }
     }
@@ -222,14 +222,20 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
     implemented_fns.contains_key(&provided_fn.def_id)
 }
 
-fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) {
+fn suggest<'tcx>(
+    cx: &LateContext<'tcx>,
+    ctxt: SyntaxContext,
+    assign_expr: &Expr<'tcx>,
+    lhs: &Expr<'tcx>,
+    call: &CallCandidate<'tcx>,
+) {
     span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
         let mut applicability = Applicability::Unspecified;
 
         diag.span_suggestion(
             assign_expr.span,
             call.suggestion_msg(),
-            call.suggested_replacement(cx, lhs, &mut applicability),
+            call.suggested_replacement(cx, ctxt, lhs, &mut applicability),
             applicability,
         );
     });
@@ -275,6 +281,7 @@ impl<'tcx> CallCandidate<'tcx> {
     fn suggested_replacement(
         &self,
         cx: &LateContext<'tcx>,
+        ctxt: SyntaxContext,
         lhs: &Expr<'tcx>,
         applicability: &mut Applicability,
     ) -> String {
@@ -294,7 +301,7 @@ impl<'tcx> CallCandidate<'tcx> {
                         // Determine whether we need to reference the argument to clone_from().
                         let clone_receiver_type = cx.typeck_results().expr_ty(receiver);
                         let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver);
-                        let mut arg_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability);
+                        let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
                         if clone_receiver_type != clone_receiver_adj_type {
                             // The receiver may have been a value type, so we need to add an `&` to
                             // be sure the argument to clone_from will be a reference.
@@ -312,7 +319,7 @@ impl<'tcx> CallCandidate<'tcx> {
                             Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr()
                         };
                         // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
-                        let rhs_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability);
+                        let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
 
                         format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
                     },
@@ -341,11 +348,11 @@ impl<'tcx> CallCandidate<'tcx> {
 
                 match self.kind {
                     CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability);
+                        let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
                         format!("{receiver_sugg}.clone_into({rhs_sugg})")
                     },
                     CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability);
+                        let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
                         format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
                     },
                 }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
index 736ee48641d..40a1c4e2884 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -36,9 +36,10 @@ fn check_duplicated_attr(
     }
     let Some(ident) = attr.ident() else { return };
     let name = ident.name;
-    if name == sym::doc || name == sym::cfg_attr {
+    if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented {
         // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
         // conditions are the same.
+        // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected.
         return;
     }
     if let Some(direct_parent) = parent.last()
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 8f47bc7653b..39f40607799 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -61,11 +61,21 @@ declare_clippy_lint! {
     ///
     /// This lint permits lint attributes for lints emitted on the items themself.
     /// For `use` items these lints are:
+    /// * ambiguous_glob_reexports
+    /// * dead_code
     /// * deprecated
+    /// * hidden_glob_reexports
     /// * unreachable_pub
-    /// * unused_imports
+    /// * unused
+    /// * unused_braces
+    /// * unused_import_braces
+    /// * clippy::disallowed_types
     /// * clippy::enum_glob_use
     /// * clippy::macro_use_imports
+    /// * clippy::module_name_repetitions
+    /// * clippy::redundant_pub_crate
+    /// * clippy::single_component_path_imports
+    /// * clippy::unsafe_removed_from_name
     /// * clippy::wildcard_imports
     ///
     /// For `extern crate` items these lints are:
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index 7575f502a7c..f0868231d01 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -2,6 +2,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word};
 use super::{Attribute, USELESS_ATTRIBUTE};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{first_line_of_span, snippet_opt};
+use rustc_ast::NestedMetaItem;
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LintContext};
@@ -20,26 +21,40 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute])
                 for lint in lint_list {
                     match item.kind {
                         ItemKind::Use(..) => {
-                            if is_word(lint, sym::unused_imports)
-                                || is_word(lint, sym::deprecated)
-                                || is_word(lint, sym!(unreachable_pub))
-                                || is_word(lint, sym!(unused))
-                                || is_word(lint, sym!(unused_import_braces))
-                                || extract_clippy_lint(lint).map_or(false, |s| {
-                                    matches!(
-                                        s.as_str(),
-                                        "wildcard_imports"
-                                            | "enum_glob_use"
-                                            | "redundant_pub_crate"
-                                            | "macro_use_imports"
-                                            | "unsafe_removed_from_name"
-                                            | "module_name_repetitions"
-                                            | "single_component_path_imports"
-                                    )
-                                })
+                            if let NestedMetaItem::MetaItem(meta_item) = lint
+                                && meta_item.is_word()
+                                && let Some(ident) = meta_item.ident()
+                                && matches!(
+                                    ident.name.as_str(),
+                                    "ambiguous_glob_reexports"
+                                        | "dead_code"
+                                        | "deprecated"
+                                        | "hidden_glob_reexports"
+                                        | "unreachable_pub"
+                                        | "unused"
+                                        | "unused_braces"
+                                        | "unused_import_braces"
+                                        | "unused_imports"
+                                )
                             {
                                 return;
                             }
+
+                            if extract_clippy_lint(lint).is_some_and(|symbol| {
+                                matches!(
+                                    symbol.as_str(),
+                                    "wildcard_imports"
+                                        | "enum_glob_use"
+                                        | "redundant_pub_crate"
+                                        | "macro_use_imports"
+                                        | "unsafe_removed_from_name"
+                                        | "module_name_repetitions"
+                                        | "single_component_path_imports"
+                                        | "disallowed_types"
+                                )
+                            }) {
+                                return;
+                            }
                         },
                         ItemKind::ExternCrate(..) => {
                             if is_word(lint, sym::unused_imports) && skip_unused_imports {
diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
index a3291c9da10..0d9eaac882f 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
@@ -49,7 +49,7 @@ impl LintConfig {
 
 type LintTable = BTreeMap<Spanned<String>, Spanned<LintConfig>>;
 
-#[derive(Deserialize, Debug)]
+#[derive(Deserialize, Debug, Default)]
 struct Lints {
     #[serde(default)]
     rust: LintTable,
@@ -57,9 +57,18 @@ struct Lints {
     clippy: LintTable,
 }
 
+#[derive(Deserialize, Debug, Default)]
+struct Workspace {
+    #[serde(default)]
+    lints: Lints,
+}
+
 #[derive(Deserialize, Debug)]
 struct CargoToml {
+    #[serde(default)]
     lints: Lints,
+    #[serde(default)]
+    workspace: Workspace,
 }
 
 #[derive(Default, Debug)]
@@ -164,5 +173,7 @@ pub fn check(cx: &LateContext<'_>) {
 
         check_table(cx, cargo_toml.lints.rust, &rustc_groups, &file);
         check_table(cx, cargo_toml.lints.clippy, &clippy_groups, &file);
+        check_table(cx, cargo_toml.workspace.lints.rust, &rustc_groups, &file);
+        check_table(cx, cargo_toml.workspace.lints.clippy, &clippy_groups, &file);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 2b6e17dc103..864489ee3fc 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -255,8 +255,10 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
 
 /// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`],
 /// where the result depends on:
+///
 /// - the number of negative values in the entire expression, or
 /// - the number of negative values on the left hand side of the expression.
+///
 /// Ignores overflow.
 ///
 ///
@@ -303,8 +305,10 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> {
 }
 
 /// Peels binary operators such as [`BinOpKind::Add`], where the result depends on:
+///
 /// - all the expressions being positive, or
 /// - all the expressions being negative.
+///
 /// Ignores overflow.
 ///
 /// Expressions using other operators are preserved, so we can try to evaluate them later.
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 5ff7d8e5134..df2ef465700 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -140,6 +140,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::disallowed_names::DISALLOWED_NAMES_INFO,
     crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
     crate::disallowed_types::DISALLOWED_TYPES_INFO,
+    crate::doc::DOC_LAZY_CONTINUATION_INFO,
     crate::doc::DOC_LINK_WITH_QUOTES_INFO,
     crate::doc::DOC_MARKDOWN_INFO,
     crate::doc::EMPTY_DOCS_INFO,
@@ -205,6 +206,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::functions::MUST_USE_CANDIDATE_INFO,
     crate::functions::MUST_USE_UNIT_INFO,
     crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
+    crate::functions::RENAMED_FUNCTION_PARAMS_INFO,
     crate::functions::RESULT_LARGE_ERR_INFO,
     crate::functions::RESULT_UNIT_ERR_INFO,
     crate::functions::TOO_MANY_ARGUMENTS_INFO,
@@ -291,9 +293,11 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::loops::SAME_ITEM_PUSH_INFO,
     crate::loops::SINGLE_ELEMENT_LOOP_INFO,
     crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
+    crate::loops::WHILE_FLOAT_INFO,
     crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
     crate::loops::WHILE_LET_LOOP_INFO,
     crate::loops::WHILE_LET_ON_ITERATOR_INFO,
+    crate::macro_metavars_in_unsafe::MACRO_METAVARS_IN_UNSAFE_INFO,
     crate::macro_use::MACRO_USE_IMPORTS_INFO,
     crate::main_recursion::MAIN_RECURSION_INFO,
     crate::manual_assert::MANUAL_ASSERT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
new file mode 100644
index 00000000000..38bc58a5501
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
@@ -0,0 +1,95 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use itertools::Itertools;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_lint::LateContext;
+use rustc_span::{BytePos, Span};
+use std::ops::Range;
+
+use super::DOC_LAZY_CONTINUATION;
+
+fn map_container_to_text(c: &super::Container) -> &'static str {
+    match c {
+        super::Container::Blockquote => "> ",
+        // numbered list can have up to nine digits, plus the dot, plus four spaces on either side
+        super::Container::List(indent) => &"                  "[0..*indent],
+    }
+}
+
+// TODO: Adjust the parameters as necessary
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    doc: &str,
+    range: Range<usize>,
+    mut span: Span,
+    containers: &[super::Container],
+) {
+    if doc[range.clone()].contains('\t') {
+        // We don't do tab stops correctly.
+        return;
+    }
+
+    let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count();
+    let blockquote_level = containers
+        .iter()
+        .filter(|c| matches!(c, super::Container::Blockquote))
+        .count();
+    let lcount = doc[range.clone()].chars().filter(|c| *c == ' ').count();
+    let list_indentation = containers
+        .iter()
+        .map(|c| {
+            if let super::Container::List(indent) = c {
+                *indent
+            } else {
+                0
+            }
+        })
+        .sum();
+    if ccount < blockquote_level || lcount < list_indentation {
+        let msg = if ccount < blockquote_level {
+            "doc quote missing `>` marker"
+        } else {
+            "doc list item missing indentation"
+        };
+        span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
+            if ccount == 0 && blockquote_level == 0 {
+                // simpler suggestion style for indentation
+                let indent = list_indentation - lcount;
+                diag.span_suggestion_with_style(
+                    span.shrink_to_hi(),
+                    "indent this line",
+                    std::iter::repeat(" ").take(indent).join(""),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+                diag.help("if this is supposed to be its own paragraph, add a blank line");
+                return;
+            }
+            let mut doc_start_range = &doc[range];
+            let mut suggested = String::new();
+            for c in containers {
+                let text = map_container_to_text(c);
+                if doc_start_range.starts_with(text) {
+                    doc_start_range = &doc_start_range[text.len()..];
+                    span = span
+                        .with_lo(span.lo() + BytePos(u32::try_from(text.len()).expect("text is not 2**32 or bigger")));
+                } else if matches!(c, super::Container::Blockquote)
+                    && let Some(i) = doc_start_range.find('>')
+                {
+                    doc_start_range = &doc_start_range[i + 1..];
+                    span =
+                        span.with_lo(span.lo() + BytePos(u32::try_from(i).expect("text is not 2**32 or bigger") + 1));
+                } else {
+                    suggested.push_str(text);
+                }
+            }
+            diag.span_suggestion_with_style(
+                span,
+                "add markers to start of line",
+                suggested,
+                Applicability::MachineApplicable,
+                SuggestionStyle::ShowAlways,
+            );
+            diag.help("if this not intended to be a quote at all, escape it with `\\>`");
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 36ba19698c7..010fab803d9 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,3 +1,4 @@
+use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_doc_hidden, return_ty};
@@ -6,15 +7,13 @@ use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::{sym, Span};
 
-use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
-
 pub fn check(
     cx: &LateContext<'_>,
     owner_id: OwnerId,
     sig: FnSig<'_>,
     headers: DocHeaders,
     body_id: Option<BodyId>,
-    panic_span: Option<Span>,
+    panic_info: Option<(Span, bool)>,
     check_private_items: bool,
 ) {
     if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) {
@@ -48,13 +47,13 @@ pub fn check(
         ),
         _ => (),
     }
-    if !headers.panics && panic_span.is_some() {
+    if !headers.panics && panic_info.map_or(false, |el| !el.1) {
         span_lint_and_note(
             cx,
             MISSING_PANICS_DOC,
             span,
             "docs for function which may panic missing `# Panics` section",
-            panic_span,
+            panic_info.map(|el| el.0),
             "first possible panic found here",
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 7fdb582e640..9f08973948a 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -1,13 +1,14 @@
+mod lazy_continuation;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
-use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
+use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
     Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
-use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph};
+use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
 use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
@@ -362,6 +363,63 @@ declare_clippy_lint! {
     "docstrings exist but documentation is empty"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// In CommonMark Markdown, the language used to write doc comments, a
+    /// paragraph nested within a list or block quote does not need any line
+    /// after the first one to be indented or marked. The specification calls
+    /// this a "lazy paragraph continuation."
+    ///
+    /// ### Why is this bad?
+    ///
+    /// This is easy to write but hard to read. Lazy continuations makes
+    /// unintended markers hard to see, and make it harder to deduce the
+    /// document's intended structure.
+    ///
+    /// ### Example
+    ///
+    /// This table is probably intended to have two rows,
+    /// but it does not. It has zero rows, and is followed by
+    /// a block quote.
+    /// ```no_run
+    /// /// Range | Description
+    /// /// ----- | -----------
+    /// /// >= 1  | fully opaque
+    /// /// < 1   | partially see-through
+    /// fn set_opacity(opacity: f32) {}
+    /// ```
+    ///
+    /// Fix it by escaping the marker:
+    /// ```no_run
+    /// /// Range | Description
+    /// /// ----- | -----------
+    /// /// \>= 1 | fully opaque
+    /// /// < 1   | partially see-through
+    /// fn set_opacity(opacity: f32) {}
+    /// ```
+    ///
+    /// This example is actually intended to be a list:
+    /// ```no_run
+    /// /// * Do nothing.
+    /// /// * Then do something. Whatever it is needs done,
+    /// /// it should be done right now.
+    /// # fn do_stuff() {}
+    /// ```
+    ///
+    /// Fix it by indenting the list contents:
+    /// ```no_run
+    /// /// * Do nothing.
+    /// /// * Then do something. Whatever it is needs done,
+    /// ///   it should be done right now.
+    /// # fn do_stuff() {}
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub DOC_LAZY_CONTINUATION,
+    style,
+    "require every line of a paragraph to be indented and marked"
+}
+
 #[derive(Clone)]
 pub struct Documentation {
     valid_idents: FxHashSet<String>,
@@ -388,6 +446,7 @@ impl_lint_pass!(Documentation => [
     UNNECESSARY_SAFETY_DOC,
     SUSPICIOUS_DOC_COMMENTS,
     EMPTY_DOCS,
+    DOC_LAZY_CONTINUATION,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Documentation {
@@ -402,14 +461,14 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                     if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
                         let body = cx.tcx.hir().body(body_id);
 
-                        let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
+                        let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
                         missing_headers::check(
                             cx,
                             item.owner_id,
                             sig,
                             headers,
                             Some(body_id),
-                            panic_span,
+                            panic_info,
                             self.check_private_items,
                         );
                     }
@@ -551,6 +610,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         cx,
         valid_idents,
         parser.into_offset_iter(),
+        &doc,
         Fragments {
             fragments: &fragments,
             doc: &doc,
@@ -560,6 +620,11 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
 const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
 
+enum Container {
+    Blockquote,
+    List(usize),
+}
+
 /// Checks parsed documentation.
 /// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
 /// so lints here will generally access that information.
@@ -569,6 +634,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     cx: &LateContext<'_>,
     valid_idents: &FxHashSet<String>,
     events: Events,
+    doc: &str,
     fragments: Fragments<'_>,
 ) -> DocHeaders {
     // true if a safety header was found
@@ -576,6 +642,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut in_code = false;
     let mut in_link = None;
     let mut in_heading = false;
+    let mut in_footnote_definition = false;
     let mut is_rust = false;
     let mut no_test = false;
     let mut ignore = false;
@@ -586,7 +653,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut code_level = 0;
     let mut blockquote_level = 0;
 
-    for (event, range) in events {
+    let mut containers = Vec::new();
+
+    let mut events = events.peekable();
+
+    while let Some((event, range)) = events.next() {
         match event {
             Html(tag) => {
                 if tag.starts_with("<code") {
@@ -599,8 +670,14 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     blockquote_level -= 1;
                 }
             },
-            Start(BlockQuote) => blockquote_level += 1,
-            End(BlockQuote) => blockquote_level -= 1,
+            Start(BlockQuote) => {
+                blockquote_level += 1;
+                containers.push(Container::Blockquote);
+            },
+            End(BlockQuote) => {
+                blockquote_level -= 1;
+                containers.pop();
+            },
             Start(CodeBlock(ref kind)) => {
                 in_code = true;
                 if let CodeBlockKind::Fenced(lang) = kind {
@@ -633,6 +710,13 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 if let Start(Heading(_, _, _)) = event {
                     in_heading = true;
                 }
+                if let Start(Item) = event {
+                    if let Some((_next_event, next_range)) = events.peek() {
+                        containers.push(Container::List(next_range.start - range.start));
+                    } else {
+                        containers.push(Container::List(0));
+                    }
+                }
                 ticks_unbalanced = false;
                 paragraph_range = range;
             },
@@ -640,6 +724,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 if let End(Heading(_, _, _)) = event {
                     in_heading = false;
                 }
+                if let End(Item) = event {
+                    containers.pop();
+                }
                 if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) {
                     span_lint_and_help(
                         cx,
@@ -658,8 +745,27 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 }
                 text_to_check = Vec::new();
             },
+            Start(FootnoteDefinition(..)) => in_footnote_definition = true,
+            End(FootnoteDefinition(..)) => in_footnote_definition = false,
             Start(_tag) | End(_tag) => (), // We don't care about other tags
-            SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
+            SoftBreak | HardBreak => {
+                if !containers.is_empty()
+                    && let Some((next_event, next_range)) = events.peek()
+                    && let Some(next_span) = fragments.span(cx, next_range.clone())
+                    && let Some(span) = fragments.span(cx, range.clone())
+                    && !in_footnote_definition
+                    && !matches!(next_event, End(_))
+                {
+                    lazy_continuation::check(
+                        cx,
+                        doc,
+                        range.end..next_range.start,
+                        Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
+                        &containers[..],
+                    );
+                }
+            },
+            TaskListMarker(_) | Code(_) | Rule => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
                 ticks_unbalanced |= text.contains('`') && !in_code;
@@ -701,6 +807,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
 
 struct FindPanicUnwrap<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
+    is_const: bool,
     panic_span: Option<Span>,
     typeck_results: &'tcx ty::TypeckResults<'tcx>,
 }
@@ -710,14 +817,15 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> {
         cx: &'a LateContext<'tcx>,
         typeck_results: &'tcx ty::TypeckResults<'tcx>,
         body: impl Visitable<'tcx>,
-    ) -> Option<Span> {
+    ) -> Option<(Span, bool)> {
         let mut vis = Self {
             cx,
+            is_const: false,
             panic_span: None,
             typeck_results,
         };
         body.visit(&mut vis);
-        vis.panic_span
+        vis.panic_span.map(|el| (el, vis.is_const))
     }
 }
 
@@ -736,6 +844,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
                     "assert" | "assert_eq" | "assert_ne"
                 )
             {
+                self.is_const = in_constant(self.cx, expr.hir_id);
                 self.panic_span = Some(macro_call.span);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 6715de52649..8d6e27700d8 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -104,7 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
             too_large_for_stack: self.too_large_for_stack,
         };
 
-        ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v).consume_body(body).into_ok();
+        ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v)
+            .consume_body(body)
+            .into_ok();
 
         for node in v.set {
             span_lint_hir(
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 724e1843359..3c4a043a732 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::{find_format_args, format_args_inputs_span};
+use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_expn_of, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::{sym, ExpnId};
 
 declare_clippy_lint! {
@@ -38,7 +38,17 @@ declare_clippy_lint! {
     "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
 }
 
-declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);
+pub struct ExplicitWrite {
+    format_args: FormatArgsStorage,
+}
+
+impl ExplicitWrite {
+    pub fn new(format_args: FormatArgsStorage) -> Self {
+        Self { format_args }
+    }
+}
+
+impl_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);
 
 impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -57,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
                 Some(sym::io_stderr) => ("stderr", "e"),
                 _ => return,
             };
-            let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else {
+            let Some(format_args) = self.format_args.get(cx, write_arg, ExpnId::root()) else {
                 return;
             };
 
@@ -83,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
             };
             let mut applicability = Applicability::MachineApplicable;
             let inputs_snippet =
-                snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability);
+                snippet_with_applicability(cx, format_args_inputs_span(format_args), "..", &mut applicability);
             span_lint_and_sugg(
                 cx,
                 EXPLICIT_WRITE,
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 8a0cd155d21..0b248f784b7 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node};
+use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -39,13 +39,24 @@ declare_clippy_lint! {
     "useless use of `format!`"
 }
 
-declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
+#[allow(clippy::module_name_repetitions)]
+pub struct UselessFormat {
+    format_args: FormatArgsStorage,
+}
+
+impl UselessFormat {
+    pub fn new(format_args: FormatArgsStorage) -> Self {
+        Self { format_args }
+    }
+}
+
+impl_lint_pass!(UselessFormat => [USELESS_FORMAT]);
 
 impl<'tcx> LateLintPass<'tcx> for UselessFormat {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Some(macro_call) = root_macro_call_first_node(cx, expr)
             && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
-            && let Some(format_args) = find_format_args(cx, expr, macro_call.expn)
+            && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn)
         {
             let mut applicability = Applicability::MachineApplicable;
             let call_site = macro_call.span;
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 003a9995c15..86115807aa4 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -3,8 +3,8 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::{
-    find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro,
-    is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall,
+    find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro,
+    is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall,
 };
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
@@ -167,15 +167,18 @@ impl_lint_pass!(FormatArgs => [
     UNUSED_FORMAT_SPECS,
 ]);
 
+#[allow(clippy::struct_field_names)]
 pub struct FormatArgs {
+    format_args: FormatArgsStorage,
     msrv: Msrv,
     ignore_mixed: bool,
 }
 
 impl FormatArgs {
     #[must_use]
-    pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
+    pub fn new(format_args: FormatArgsStorage, msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
         Self {
+            format_args,
             msrv,
             ignore_mixed: allow_mixed_uninlined_format_args,
         }
@@ -186,13 +189,13 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(macro_call) = root_macro_call_first_node(cx, expr)
             && is_format_macro(cx, macro_call.def_id)
-            && let Some(format_args) = find_format_args(cx, expr, macro_call.expn)
+            && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn)
         {
             let linter = FormatArgsExpr {
                 cx,
                 expr,
                 macro_call: &macro_call,
-                format_args: &format_args,
+                format_args,
                 ignore_mixed: self.ignore_mixed,
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 0a52347940a..09be7237b5c 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node};
+use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage};
 use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
 use rustc_ast::{FormatArgsPiece, FormatTrait};
 use rustc_errors::Applicability;
@@ -99,13 +99,15 @@ struct FormatTraitNames {
 
 #[derive(Default)]
 pub struct FormatImpl {
+    format_args: FormatArgsStorage,
     // Whether we are inside Display or Debug trait impl - None for neither
     format_trait_impl: Option<FormatTraitNames>,
 }
 
 impl FormatImpl {
-    pub fn new() -> Self {
+    pub fn new(format_args: FormatArgsStorage) -> Self {
         Self {
+            format_args,
             format_trait_impl: None,
         }
     }
@@ -129,6 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
         if let Some(format_trait_impl) = self.format_trait_impl {
             let linter = FormatImplExpr {
                 cx,
+                format_args: &self.format_args,
                 expr,
                 format_trait_impl,
             };
@@ -141,6 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
 
 struct FormatImplExpr<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
+    format_args: &'a FormatArgsStorage,
     expr: &'tcx Expr<'tcx>,
     format_trait_impl: FormatTraitNames,
 }
@@ -175,7 +179,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
         if let Some(outer_macro) = root_macro_call_first_node(self.cx, self.expr)
             && let macro_def_id = outer_macro.def_id
             && is_format_macro(self.cx, macro_def_id)
-            && let Some(format_args) = find_format_args(self.cx, self.expr, outer_macro.expn)
+            && let Some(format_args) = self.format_args.get(self.cx, self.expr, outer_macro.expn)
         {
             for piece in &format_args.template {
                 if let FormatArgsPiece::Placeholder(placeholder) = piece
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 633ed96d6a6..82ce501bac5 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_integer_literal;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::{in_constant, is_integer_literal};
 use rustc_errors::Applicability;
 use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -47,6 +47,9 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind
+            // do not lint in constant context, because the suggestion won't work.
+            // NB: keep this check until a new `const_trait_impl` is available and stablized.
+            && !in_constant(cx, exp.hir_id)
 
             // check if the first part of the path is some integer primitive
             && let TyKind::Path(ty_qpath) = &ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 9cc51fa8cd5..dfcaac9abef 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -2,15 +2,17 @@ mod impl_trait_in_params;
 mod misnamed_getters;
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
+mod renamed_function_params;
 mod result;
 mod too_many_arguments;
 mod too_many_lines;
 
+use clippy_utils::def_path_def_ids;
 use rustc_hir as hir;
 use rustc_hir::intravisit;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{DefIdSet, LocalDefId};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -359,13 +361,51 @@ declare_clippy_lint! {
     "`impl Trait` is used in the function's parameters"
 }
 
-#[derive(Copy, Clone)]
-#[allow(clippy::struct_field_names)]
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints when the name of function parameters from trait impl is
+    /// different than its default implementation.
+    ///
+    /// ### Why is this bad?
+    /// Using the default name for parameters of a trait method is often
+    /// more desirable for consistency's sake.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct A(u32);
+    ///
+    /// impl PartialEq for A {
+    ///     fn eq(&self, b: &Self) -> bool {
+    ///         self.0 == b.0
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct A(u32);
+    ///
+    /// impl PartialEq for A {
+    ///     fn eq(&self, other: &Self) -> bool {
+    ///         self.0 == other.0
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.74.0"]
+    pub RENAMED_FUNCTION_PARAMS,
+    restriction,
+    "renamed function parameters in trait implementation"
+}
+
+#[derive(Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
     large_error_threshold: u64,
     avoid_breaking_exported_api: bool,
+    allow_renamed_params_for: Vec<String>,
+    /// A set of resolved `def_id` of traits that are configured to allow
+    /// function params renaming.
+    trait_ids: DefIdSet,
 }
 
 impl Functions {
@@ -374,12 +414,15 @@ impl Functions {
         too_many_lines_threshold: u64,
         large_error_threshold: u64,
         avoid_breaking_exported_api: bool,
+        allow_renamed_params_for: Vec<String>,
     ) -> Self {
         Self {
             too_many_arguments_threshold,
             too_many_lines_threshold,
             large_error_threshold,
             avoid_breaking_exported_api,
+            allow_renamed_params_for,
+            trait_ids: DefIdSet::default(),
         }
     }
 }
@@ -395,6 +438,7 @@ impl_lint_pass!(Functions => [
     RESULT_LARGE_ERR,
     MISNAMED_GETTERS,
     IMPL_TRAIT_IN_PARAMS,
+    RENAMED_FUNCTION_PARAMS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -424,6 +468,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         must_use::check_impl_item(cx, item);
         result::check_impl_item(cx, item, self.large_error_threshold);
         impl_trait_in_params::check_impl_item(cx, item);
+        renamed_function_params::check_impl_item(cx, item, &self.trait_ids);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -433,4 +478,12 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         result::check_trait_item(cx, item, self.large_error_threshold);
         impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
     }
+
+    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+        for path in &self.allow_renamed_params_for {
+            let path_segments: Vec<&str> = path.split("::").collect();
+            let ids = def_path_def_ids(cx, &path_segments);
+            self.trait_ids.extend(ids);
+        }
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
new file mode 100644
index 00000000000..c7de0385c02
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -0,0 +1,110 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::{Applicability, MultiSpan};
+use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_hir::hir_id::OwnerId;
+use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef};
+use rustc_lint::LateContext;
+use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::Span;
+
+use super::RENAMED_FUNCTION_PARAMS;
+
+pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored_traits: &DefIdSet) {
+    if !item.span.from_expansion()
+        && let ImplItemKind::Fn(_, body_id) = item.kind
+        && let parent_node = cx.tcx.parent_hir_node(item.hir_id())
+        && let Node::Item(parent_item) = parent_node
+        && let ItemKind::Impl(Impl {
+            items,
+            of_trait: Some(trait_ref),
+            ..
+        }) = &parent_item.kind
+        && let Some(did) = trait_item_def_id_of_impl(items, item.owner_id)
+        && !is_from_ignored_trait(trait_ref, ignored_traits)
+    {
+        let mut param_idents_iter = cx.tcx.hir().body_param_names(body_id);
+        let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied();
+
+        let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter);
+        if !renames.0.is_empty() {
+            let multi_span = renames.multi_span();
+            let plural = if renames.0.len() == 1 { "" } else { "s" };
+            span_lint_and_then(
+                cx,
+                RENAMED_FUNCTION_PARAMS,
+                multi_span,
+                format!("renamed function parameter{plural} of trait impl"),
+                |diag| {
+                    diag.multipart_suggestion(
+                        format!("consider using the default name{plural}"),
+                        renames.0,
+                        Applicability::Unspecified,
+                    );
+                },
+            );
+        }
+    }
+}
+
+struct RenamedFnArgs(Vec<(Span, String)>);
+
+impl RenamedFnArgs {
+    /// Comparing between an iterator of default names and one with current names,
+    /// then collect the ones that got renamed.
+    fn new<I, T>(default_names: &mut I, current_names: &mut T) -> Self
+    where
+        I: Iterator<Item = Ident>,
+        T: Iterator<Item = Ident>,
+    {
+        let mut renamed: Vec<(Span, String)> = vec![];
+
+        debug_assert!(default_names.size_hint() == current_names.size_hint());
+        while let (Some(def_name), Some(cur_name)) = (default_names.next(), current_names.next()) {
+            let current_name = cur_name.name;
+            let default_name = def_name.name;
+            if is_unused_or_empty_symbol(current_name) || is_unused_or_empty_symbol(default_name) {
+                continue;
+            }
+            if current_name != default_name {
+                renamed.push((cur_name.span, default_name.to_string()));
+            }
+        }
+
+        Self(renamed)
+    }
+
+    fn multi_span(&self) -> MultiSpan {
+        self.0
+            .iter()
+            .map(|(span, _)| span)
+            .copied()
+            .collect::<Vec<Span>>()
+            .into()
+    }
+}
+
+fn is_unused_or_empty_symbol(symbol: Symbol) -> bool {
+    // FIXME: `body_param_names` currently returning empty symbols for `wild` as well,
+    // so we need to check if the symbol is empty first.
+    // Therefore the check of whether it's equal to [`kw::Underscore`] has no use for now,
+    // but it would be nice to keep it here just to be future-proof.
+    symbol.is_empty() || symbol == kw::Underscore || symbol.as_str().starts_with('_')
+}
+
+/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item.
+fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option<DefId> {
+    items.iter().find_map(|item| {
+        if item.id.owner_id == target {
+            item.trait_item_def_id
+        } else {
+            None
+        }
+    })
+}
+
+fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool {
+    let Some(trait_did) = of_trait.trait_def_id() else {
+        return false;
+    };
+    ignored_traits.contains(&trait_did)
+}
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 2c2daac0234..192fb611c2d 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
 use rustc_middle::ty::print::PrintTraitRefExt;
+use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index a75dfaf286f..601d0e151aa 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -225,7 +225,7 @@ impl {self_ty_without_ref} {{
             && let ImplItemKind::Fn(sig, _) = item.kind
             && let FnRetTy::Return(ret) = sig.decl.output
             && is_nameable_in_impl_trait(ret)
-            && cx.tcx.generics_of(item_did).own_params.is_empty()
+            && cx.tcx.generics_of(item_did).is_own_empty()
             && sig.decl.implicit_self == expected_implicit_self
             && sig.decl.inputs.len() == 1
             && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index a8bfbbdd9ec..3328d642bd8 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -61,11 +61,6 @@ extern crate clippy_utils;
 #[macro_use]
 extern crate declare_clippy_lint;
 
-use std::collections::BTreeMap;
-
-use rustc_data_structures::fx::FxHashSet;
-use rustc_lint::{Lint, LintId};
-
 #[cfg(feature = "internal")]
 pub mod deprecated_lints;
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
@@ -199,6 +194,7 @@ mod lifetimes;
 mod lines_filter_map_ok;
 mod literal_representation;
 mod loops;
+mod macro_metavars_in_unsafe;
 mod macro_use;
 mod main_recursion;
 mod manual_assert;
@@ -385,6 +381,10 @@ mod zero_sized_map_values;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
 use clippy_config::{get_configuration_metadata, Conf};
+use clippy_utils::macros::FormatArgsStorage;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_lint::{Lint, LintId};
+use std::collections::BTreeMap;
 
 /// Register all pre expansion lints
 ///
@@ -533,6 +533,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         allow_expect_in_tests,
         allow_mixed_uninlined_format_args,
         allow_one_hash_in_raw_strings,
+        allow_panic_in_tests,
         allow_print_in_tests,
         allow_private_module_inception,
         allow_unwrap_in_tests,
@@ -597,9 +598,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         ref allowed_duplicate_crates,
         allow_comparison_to_zero,
         ref allowed_prefixes,
+        ref allow_renamed_params_for,
 
         blacklisted_names: _,
         cyclomatic_complexity_threshold: _,
+        warn_unsafe_macro_metavars_in_private_macros,
     } = *conf;
     let msrv = || msrv.clone();
 
@@ -616,6 +619,14 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         }
     }
 
+    let format_args_storage = FormatArgsStorage::default();
+    let format_args = format_args_storage.clone();
+    store.register_early_pass(move || {
+        Box::new(utils::format_args_collector::FormatArgsCollector::new(
+            format_args.clone(),
+        ))
+    });
+
     // all the internal lints
     #[cfg(feature = "internal")]
     {
@@ -656,7 +667,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
                 .collect(),
         ))
     });
-    store.register_early_pass(|| Box::<utils::format_args_collector::FormatArgsCollector>::default());
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|_| Box::new(utils::author::Author));
     store.register_late_pass(move |_| {
@@ -698,6 +708,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
     store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
+    let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
             avoid_breaking_exported_api,
@@ -705,6 +716,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             allow_expect_in_tests,
             allow_unwrap_in_tests,
             allowed_dotfiles.clone(),
+            format_args.clone(),
         ))
     });
     store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
@@ -759,7 +771,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             allow_in_test: allow_useless_vec_in_tests,
         })
     });
-    store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
+    store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented { allow_panic_in_tests }));
     store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
     store.register_late_pass(|_| Box::new(derive::Derive));
     store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv())));
@@ -769,7 +781,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::<regex::Regex>::default());
     store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
     store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
-    store.register_late_pass(|_| Box::new(format::UselessFormat));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(swap::Swap));
     store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
@@ -780,6 +793,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             too_many_lines_threshold,
             large_error_threshold,
             avoid_breaking_exported_api,
+            allow_renamed_params_for.clone(),
         ))
     });
     store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items)));
@@ -793,7 +807,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
     store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
     store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
-    store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
     store.register_late_pass(move |tcx| {
         Box::new(pass_by_ref_or_value::PassByRefOrValue::new(
@@ -835,7 +850,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
     store.register_early_pass(|| Box::new(reference::DerefAddrOf));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
-    store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone())));
     store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
     store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
     store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
@@ -961,8 +977,14 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             accept_comment_above_attributes,
         ))
     });
-    store
-        .register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined_format_args)));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| {
+        Box::new(format_args::FormatArgs::new(
+            format_args.clone(),
+            msrv(),
+            allow_mixed_uninlined_format_args,
+        ))
+    });
     store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
     store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
@@ -973,7 +995,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
     store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
-    store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(write::Write::new(format_args.clone(), allow_print_in_tests)));
     store.register_late_pass(move |_| {
         Box::new(cargo::Cargo {
             ignore_publish: cargo_ignore_publish,
@@ -1136,6 +1159,12 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
     store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
     store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
+    store.register_late_pass(move |_| {
+        Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe {
+            warn_unsafe_macro_metavars_in_private_macros,
+            ..Default::default()
+        })
+    });
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index b5e39b33c6a..3dcb050d77e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -17,6 +17,7 @@ mod same_item_push;
 mod single_element_loop;
 mod unused_enumerate_index;
 mod utils;
+mod while_float;
 mod while_immutable_condition;
 mod while_let_loop;
 mod while_let_on_iterator;
@@ -418,6 +419,39 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for while loops comparing floating point values.
+    ///
+    /// ### Why is this bad?
+    /// If you increment floating point values, errors can compound,
+    /// so, use integers instead if possible.
+    ///
+    /// ### Known problems
+    /// The lint will catch all while loops comparing floating point
+    /// values without regarding the increment.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let mut x = 0.0;
+    /// while x < 42.0 {
+    ///     x += 1.0;
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// let mut x = 0;
+    /// while x < 42 {
+    ///     x += 1;
+    /// }
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub WHILE_FLOAT,
+    nursery,
+    "while loops comaparing floating point values"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks whether a for loop is being used to push a constant
     /// value into a Vec.
     ///
@@ -706,6 +740,7 @@ impl_lint_pass!(Loops => [
     NEVER_LOOP,
     MUT_RANGE_BOUND,
     WHILE_IMMUTABLE_CONDITION,
+    WHILE_FLOAT,
     SAME_ITEM_PUSH,
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
@@ -762,6 +797,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
+            while_float::check(cx, condition);
             missing_spin_loop::check(cx, condition, body);
             manual_while_let_some::check(cx, condition, body, span);
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 6b9ecf5f141..6c6a9a1a2e0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -60,12 +60,9 @@ fn check_for_mutation(
         span_low: None,
         span_high: None,
     };
-    ExprUseVisitor::for_clippy(
-        cx,
-        body.hir_id.owner.def_id,
-        &mut delegate,
-    )
-    .walk_expr(body).into_ok();
+    ExprUseVisitor::for_clippy(cx, body.hir_id.owner.def_id, &mut delegate)
+        .walk_expr(body)
+        .into_ok();
 
     delegate.mutation_span()
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_float.rs b/src/tools/clippy/clippy_lints/src/loops/while_float.rs
new file mode 100644
index 00000000000..cf62ce29f0c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/while_float.rs
@@ -0,0 +1,20 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_hir::ExprKind;
+
+pub(super) fn check(cx: &rustc_lint::LateContext<'_>, condition: &rustc_hir::Expr<'_>) {
+    if let ExprKind::Binary(_op, left, right) = condition.kind
+        && is_float_type(cx, left)
+        && is_float_type(cx, right)
+    {
+        span_lint(
+            cx,
+            super::WHILE_FLOAT,
+            condition.span,
+            "while condition comparing floats",
+        );
+    }
+}
+
+fn is_float_type(cx: &rustc_lint::LateContext<'_>, expr: &rustc_hir::Expr<'_>) -> bool {
+    cx.typeck_results().expr_ty(expr).is_floating_point()
+}
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
new file mode 100644
index 00000000000..aea3d26e187
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -0,0 +1,256 @@
+use std::collections::btree_map::Entry;
+use std::collections::BTreeMap;
+
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::is_lint_allowed;
+use itertools::Itertools;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
+use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::impl_lint_pass;
+use rustc_span::{sym, Span, SyntaxContext};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for macros that expand metavariables in an unsafe block.
+    ///
+    /// ### Why is this bad?
+    /// This hides an unsafe block and allows the user of the macro to write unsafe code without an explicit
+    /// unsafe block at callsite, making it possible to perform unsafe operations in seemingly safe code.
+    ///
+    /// The macro should be restructured so that these metavariables are referenced outside of unsafe blocks
+    /// and that the usual unsafety checks apply to the macro argument.
+    ///
+    /// This is usually done by binding it to a variable outside of the unsafe block
+    /// and then using that variable inside of the block as shown in the example, or by referencing it a second time
+    /// in a safe context, e.g. `if false { $expr }`.
+    ///
+    /// ### Known limitations
+    /// Due to how macros are represented in the compiler at the time Clippy runs its lints,
+    /// it's not possible to look for metavariables in macro definitions directly.
+    ///
+    /// Instead, this lint looks at expansions of macros.
+    /// This leads to false negatives for macros that are never actually invoked.
+    ///
+    /// By default, this lint is rather conservative and will only emit warnings on publicly-exported
+    /// macros from the same crate, because oftentimes private internal macros are one-off macros where
+    /// this lint would just be noise (e.g. macros that generate `impl` blocks).
+    /// The default behavior should help with preventing a high number of such false positives,
+    /// however it can be configured to also emit warnings in private macros if desired.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// /// Gets the first element of a slice
+    /// macro_rules! first {
+    ///     ($slice:expr) => {
+    ///         unsafe {
+    ///             let slice = $slice; // ⚠️ expansion inside of `unsafe {}`
+    ///
+    ///             assert!(!slice.is_empty());
+    ///             // SAFETY: slice is checked to have at least one element
+    ///             slice.first().unwrap_unchecked()
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(*first!(&[1i32]), 1);
+    ///
+    /// // This will compile as a consequence (note the lack of `unsafe {}`)
+    /// assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1);
+    /// ```
+    /// Use instead:
+    /// ```compile_fail
+    /// macro_rules! first {
+    ///     ($slice:expr) => {{
+    ///         let slice = $slice; // ✅ outside of `unsafe {}`
+    ///         unsafe {
+    ///             assert!(!slice.is_empty());
+    ///             // SAFETY: slice is checked to have at least one element
+    ///             slice.first().unwrap_unchecked()
+    ///         }
+    ///     }}
+    /// }
+    ///
+    /// assert_eq!(*first!(&[1]), 1);
+    ///
+    /// // This won't compile:
+    /// assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1);
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub MACRO_METAVARS_IN_UNSAFE,
+    suspicious,
+    "expanding macro metavariables in an unsafe block"
+}
+impl_lint_pass!(ExprMetavarsInUnsafe => [MACRO_METAVARS_IN_UNSAFE]);
+
+#[derive(Clone, Debug)]
+pub enum MetavarState {
+    ReferencedInUnsafe { unsafe_blocks: Vec<HirId> },
+    ReferencedInSafe,
+}
+
+#[derive(Default)]
+pub struct ExprMetavarsInUnsafe {
+    pub warn_unsafe_macro_metavars_in_private_macros: bool,
+    /// A metavariable can be expanded more than once, potentially across multiple bodies, so it
+    /// requires some state kept across HIR nodes to make it possible to delay a warning
+    /// and later undo:
+    ///
+    /// ```ignore
+    /// macro_rules! x {
+    ///     ($v:expr) => {
+    ///         unsafe { $v; } // unsafe context, it might be possible to emit a warning here, so add it to the map
+    ///
+    ///         $v;            // `$v` expanded another time but in a safe context, set to ReferencedInSafe to suppress
+    ///     }
+    /// }
+    /// ```
+    pub metavar_expns: BTreeMap<Span, MetavarState>,
+}
+
+struct BodyVisitor<'a, 'tcx> {
+    /// Stack of unsafe blocks -- the top item always represents the last seen unsafe block from
+    /// within a relevant macro.
+    macro_unsafe_blocks: Vec<HirId>,
+    /// When this is >0, it means that the node currently being visited is "within" a
+    /// macro definition. This is not necessary for correctness, it merely helps reduce the number
+    /// of spans we need to insert into the map, since only spans from macros are relevant.
+    expn_depth: u32,
+    cx: &'a LateContext<'tcx>,
+    lint: &'a mut ExprMetavarsInUnsafe,
+}
+
+fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    (cx.effective_visibilities.is_exported(def_id) || cx.tcx.has_attr(def_id, sym::macro_export))
+        && !cx.tcx.is_doc_hidden(def_id)
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> {
+    fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
+        let from_expn = s.span.from_expansion();
+        if from_expn {
+            self.expn_depth += 1;
+        }
+        walk_stmt(self, s);
+        if from_expn {
+            self.expn_depth -= 1;
+        }
+    }
+
+    fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
+        let ctxt = e.span.ctxt();
+
+        if let ExprKind::Block(block, _) = e.kind
+            && let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules
+            && !ctxt.is_root()
+            && let Some(macro_def_id) = ctxt.outer_expn_data().macro_def_id
+            && let Some(macro_def_id) = macro_def_id.as_local()
+            && (self.lint.warn_unsafe_macro_metavars_in_private_macros || is_public_macro(self.cx, macro_def_id))
+        {
+            self.macro_unsafe_blocks.push(block.hir_id);
+            walk_block(self, block);
+            self.macro_unsafe_blocks.pop();
+        } else if ctxt.is_root() && self.expn_depth > 0 {
+            let unsafe_block = self.macro_unsafe_blocks.last().copied();
+
+            match (self.lint.metavar_expns.entry(e.span), unsafe_block) {
+                (Entry::Vacant(e), None) => {
+                    e.insert(MetavarState::ReferencedInSafe);
+                },
+                (Entry::Vacant(e), Some(unsafe_block)) => {
+                    e.insert(MetavarState::ReferencedInUnsafe {
+                        unsafe_blocks: vec![unsafe_block],
+                    });
+                },
+                (Entry::Occupied(mut e), None) => {
+                    if let MetavarState::ReferencedInUnsafe { .. } = *e.get() {
+                        e.insert(MetavarState::ReferencedInSafe);
+                    }
+                },
+                (Entry::Occupied(mut e), Some(unsafe_block)) => {
+                    if let MetavarState::ReferencedInUnsafe { unsafe_blocks } = e.get_mut()
+                        && !unsafe_blocks.contains(&unsafe_block)
+                    {
+                        unsafe_blocks.push(unsafe_block);
+                    }
+                },
+            }
+
+            // NB: No need to visit descendant nodes. They're guaranteed to represent the same
+            // metavariable
+        } else {
+            walk_expr(self, e);
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe {
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx rustc_hir::Body<'tcx>) {
+        if is_lint_allowed(cx, MACRO_METAVARS_IN_UNSAFE, body.value.hir_id) {
+            return;
+        }
+
+        // This BodyVisitor is separate and not part of the lint pass because there is no
+        // `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span
+
+        let mut vis = BodyVisitor {
+            #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+            expn_depth: if body.value.span.from_expansion() { 1 } else { 0 },
+            macro_unsafe_blocks: Vec::new(),
+            lint: self,
+            cx
+        };
+        vis.visit_body(body);
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        // Aggregate all unsafe blocks from all spans:
+        // ```
+        // macro_rules! x {
+        //   ($w:expr, $x:expr, $y:expr) => { $w; unsafe { $w; $x; }; unsafe { $x; $y; }; }
+        // }
+        // $w: []  (unsafe#0 is never added because it was referenced in a safe context)
+        // $x: [unsafe#0, unsafe#1]
+        // $y: [unsafe#1]
+        // ```
+        // We want to lint unsafe blocks #0 and #1
+        let bad_unsafe_blocks = self
+            .metavar_expns
+            .iter()
+            .filter_map(|(_, state)| match state {
+                MetavarState::ReferencedInUnsafe { unsafe_blocks } => Some(unsafe_blocks.as_slice()),
+                MetavarState::ReferencedInSafe => None,
+            })
+            .flatten()
+            .copied()
+            .map(|id| {
+                // Remove the syntax context to hide "in this macro invocation" in the diagnostic.
+                // The invocation doesn't matter. Also we want to dedupe by the unsafe block and not by anything
+                // related to the callsite.
+                let span = cx.tcx.hir().span(id);
+
+                (id, Span::new(span.lo(), span.hi(), SyntaxContext::root(), None))
+            })
+            .dedup_by(|&(_, a), &(_, b)| a == b);
+
+        for (id, span) in bad_unsafe_blocks {
+            span_lint_hir_and_then(
+                cx,
+                MACRO_METAVARS_IN_UNSAFE,
+                id,
+                span,
+                "this macro expands metavariables in an unsafe block",
+                |diag| {
+                    diag.note("this allows the user of the macro to write unsafe code outside of an unsafe block");
+                    diag.help(
+                            "consider expanding any metavariables outside of this block, e.g. by storing them in a variable",
+                        );
+                    diag.help(
+                            "... or also expand referenced metavariables in a safe context to require an unsafe block at callsite",
+                        );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 1eadc200bed..e2ab4415518 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -611,15 +611,22 @@ impl<'tcx> BinaryOp<'tcx> {
 
 /// The clamp meta pattern is a pattern shared between many (but not all) patterns.
 /// In summary, this pattern consists of two if statements that meet many criteria,
+///
 /// - binary operators that are one of [`>`, `<`, `>=`, `<=`].
+///
 /// - Both binary statements must have a shared argument
+///
 ///     - Which can appear on the left or right side of either statement
+///
 ///     - The binary operators must define a finite range for the shared argument. To put this in
 ///       the terms of Rust `std` library, the following ranges are acceptable
+///
 ///         - `Range`
 ///         - `RangeInclusive`
+///
 ///       And all other range types are not accepted. For the purposes of `clamp` it's irrelevant
 ///       whether the range is inclusive or not, the output is the same.
+///
 /// - The result of each if statement must be equal to the argument unique to that if statement. The
 ///   result can not be the shared argument in either case.
 fn is_clamp_meta_pattern<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index cd61e733694..da8c918a62b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash};
 use core::cmp::Ordering;
 use core::{iter, slice};
@@ -9,9 +9,9 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
-use rustc_lint::LateContext;
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
-use rustc_span::{ErrorGuaranteed, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 use super::MATCH_SAME_ARMS;
 
@@ -110,20 +110,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
             && check_same_body()
     };
 
+    let mut appl = Applicability::MaybeIncorrect;
     let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
     for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
         if matches!(arm2.pat.kind, PatKind::Wild) {
             if !cx.tcx.features().non_exhaustive_omitted_patterns_lint
                 || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
             {
+                let arm_span = adjusted_arm_span(cx, arm1.span);
                 span_lint_hir_and_then(
                     cx,
                     MATCH_SAME_ARMS,
                     arm1.hir_id,
-                    arm1.span,
+                    arm_span,
                     "this match arm has an identical body to the `_` wildcard arm",
                     |diag| {
-                        diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect)
+                        diag.span_suggestion(arm_span, "try removing the arm", "", appl)
                             .help("or try changing either arm body")
                             .span_note(arm2.span, "`_` wildcard arm here");
                     },
@@ -144,23 +146,36 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
                 keep_arm.span,
                 "this match arm has an identical body to another arm",
                 |diag| {
-                    let move_pat_snip = snippet(cx, move_arm.pat.span, "<pat2>");
-                    let keep_pat_snip = snippet(cx, keep_arm.pat.span, "<pat1>");
+                    let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "<pat2>", &mut appl);
+                    let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "<pat1>", &mut appl);
 
                     diag.span_suggestion(
                         keep_arm.pat.span,
-                        "try merging the arm patterns",
+                        "or try merging the arm patterns",
                         format!("{keep_pat_snip} | {move_pat_snip}"),
-                        Applicability::MaybeIncorrect,
+                        appl,
                     )
-                    .help("or try changing either arm body")
-                    .span_note(move_arm.span, "other arm here");
+                    .span_suggestion(
+                        adjusted_arm_span(cx, move_arm.span),
+                        "and remove this obsolete arm",
+                        "",
+                        appl,
+                    )
+                    .help("try changing either arm body");
                 },
             );
         }
     }
 }
 
+/// Extend arm's span to include the comma and whitespaces after it.
+fn adjusted_arm_span(cx: &LateContext<'_>, span: Span) -> Span {
+    let source_map = cx.sess().source_map();
+    source_map
+        .span_extend_while(span, |c| c == ',' || c.is_ascii_whitespace())
+        .unwrap_or(span)
+}
+
 #[derive(Clone, Copy)]
 enum NormalizedPat<'a> {
     Wild,
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index f775ea072e1..6ac0705abb2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -115,45 +115,60 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
         }
     }
 
-    fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> {
-        self.cx.typeck_results().expr_ty(ex)
+    fn is_sig_drop_expr(&mut self, ex: &'tcx Expr<'_>) -> bool {
+        !ex.is_syntactic_place_expr() && self.has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex))
     }
 
-    fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool {
-        !self.seen_types.insert(ty)
+    fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+        self.seen_types.clear();
+        self.has_sig_drop_attr_impl(ty)
     }
 
-    fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    fn has_sig_drop_attr_impl(&mut self, ty: Ty<'tcx>) -> bool {
         if let Some(adt) = ty.ty_adt_def() {
-            if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 {
+            if get_attr(
+                self.cx.sess(),
+                self.cx.tcx.get_attrs_unchecked(adt.did()),
+                "has_significant_drop",
+            )
+            .count()
+                > 0
+            {
                 return true;
             }
         }
 
-        match ty.kind() {
-            rustc_middle::ty::Adt(a, b) => {
-                for f in a.all_fields() {
-                    let ty = f.ty(cx.tcx, b);
-                    if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) {
-                        return true;
-                    }
-                }
+        if !self.seen_types.insert(ty) {
+            return false;
+        }
 
-                for generic_arg in *b {
-                    if let GenericArgKind::Type(ty) = generic_arg.unpack() {
-                        if self.has_sig_drop_attr(cx, ty) {
-                            return true;
-                        }
-                    }
-                }
-                false
+        let result = match ty.kind() {
+            rustc_middle::ty::Adt(adt, args) => {
+                // if some field has significant drop,
+                adt.all_fields()
+                    .map(|field| field.ty(self.cx.tcx, args))
+                    .any(|ty| self.has_sig_drop_attr_impl(ty))
+                    // or if there is no generic lifetime and..
+                    // (to avoid false positive on `Ref<'a, MutexGuard<Foo>>`)
+                    || (args
+                        .iter()
+                        .all(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+                        // some generic parameter has significant drop
+                        // (to avoid false negative on `Box<MutexGuard<Foo>>`)
+                        && args
+                            .iter()
+                            .filter_map(|arg| match arg.unpack() {
+                                GenericArgKind::Type(ty) => Some(ty),
+                                _ => None,
+                            })
+                            .any(|ty| self.has_sig_drop_attr_impl(ty)))
             },
-            rustc_middle::ty::Array(ty, _)
-            | rustc_middle::ty::RawPtr(ty, _)
-            | rustc_middle::ty::Ref(_, ty, _)
-            | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
+            rustc_middle::ty::Tuple(tys) => tys.iter().any(|ty| self.has_sig_drop_attr_impl(ty)),
+            rustc_middle::ty::Array(ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr_impl(*ty),
             _ => false,
-        }
+        };
+
+        result
     }
 }
 
@@ -232,7 +247,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
         if self.current_sig_drop.is_some() {
             return;
         }
-        let ty = self.sig_drop_checker.get_type(expr);
+        let ty = self.cx.typeck_results().expr_ty(expr);
         if ty.is_ref() {
             // We checked that the type was ref, so builtin_deref will return Some,
             // but let's avoid any chance of an ICE.
@@ -279,11 +294,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
-        if !self.is_chain_end
-            && self
-                .sig_drop_checker
-                .has_sig_drop_attr(self.cx, self.sig_drop_checker.get_type(ex))
-        {
+        if !self.is_chain_end && self.sig_drop_checker.is_sig_drop_expr(ex) {
             self.has_significant_drop = true;
             return;
         }
@@ -387,10 +398,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'
 
 impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-        if self
-            .sig_drop_checker
-            .has_sig_drop_attr(self.sig_drop_checker.cx, self.sig_drop_checker.get_type(ex))
-        {
+        if self.sig_drop_checker.is_sig_drop_expr(ex) {
             self.found_sig_drop_spans.insert(ex.span);
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index fba76852344..c9f56e1d980 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node};
+use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_errors::Applicability;
@@ -16,6 +16,7 @@ use super::EXPECT_FUN_CALL;
 #[allow(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
+    format_args_storage: &FormatArgsStorage,
     expr: &hir::Expr<'_>,
     method_span: Span,
     name: &str,
@@ -134,9 +135,9 @@ pub(super) fn check<'tcx>(
     // Special handling for `format!` as arg_root
     if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
         if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
-            && let Some(format_args) = find_format_args(cx, arg_root, macro_call.expn)
+            && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn)
         {
-            let span = format_args_inputs_span(&format_args);
+            let span = format_args_inputs_span(format_args);
             let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index 12647ea1ffc..b93d51eac64 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -126,15 +126,15 @@ enum FilterType {
 ///
 /// How this is done:
 /// 1. we know that this is invoked in a method call with `filter` as the method name via `mod.rs`
-/// 2. we check that we are in a trait method. Therefore we are in an
-/// `(x as Iterator).filter({filter_arg})` method call.
+/// 2. we check that we are in a trait method. Therefore we are in an `(x as
+///    Iterator).filter({filter_arg})` method call.
 /// 3. we check that the parent expression is not a map. This is because we don't want to lint
 ///    twice, and we already have a specialized lint for that.
 /// 4. we check that the span of the filter does not contain a comment.
 /// 5. we get the type of the `Item` in the `Iterator`, and compare against the type of Option and
-///   Result.
+///    Result.
 /// 6. we finally check the contents of the filter argument to see if it is a call to `is_some` or
-///   `is_ok`.
+///    `is_ok`.
 /// 7. if all of the above are true, then we return the `FilterType`
 fn expression_type(
     cx: &LateContext<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 7c852a3768d..05e77386128 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -12,8 +12,10 @@ use rustc_middle::ty;
 use rustc_span::{sym, Span};
 
 /// lint use of:
+///
 /// - `hashmap.iter().map(|(_, v)| v)`
 /// - `hashmap.into_iter().map(|(_, v)| v)`
+///
 /// on `HashMaps` and `BTreeMaps` in std
 
 pub(super) fn check<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index a52d38790a2..5ccb5243e90 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -69,12 +69,9 @@ pub(super) fn check<'tcx>(
                 used_move: HirIdSet::default(),
             };
 
-            ExprUseVisitor::for_clippy(
-                cx,
-                closure.def_id,
-                &mut delegate,
-            )
-            .consume_body(body).into_ok();
+            ExprUseVisitor::for_clippy(cx, closure.def_id, &mut delegate)
+                .consume_body(body)
+                .into_ok();
 
             let mut to_be_discarded = false;
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 2b92bff016d..9d67aa23379 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -133,6 +133,7 @@ use bind_instead_of_map::BindInsteadOfMap;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
 use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
@@ -4087,12 +4088,14 @@ declare_clippy_lint! {
     suspicious,
     "is_empty() called on strings known at compile time"
 }
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
     allow_expect_in_tests: bool,
     allow_unwrap_in_tests: bool,
     allowed_dotfiles: FxHashSet<String>,
+    format_args: FormatArgsStorage,
 }
 
 impl Methods {
@@ -4103,6 +4106,7 @@ impl Methods {
         allow_expect_in_tests: bool,
         allow_unwrap_in_tests: bool,
         mut allowed_dotfiles: FxHashSet<String>,
+        format_args: FormatArgsStorage,
     ) -> Self {
         allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
 
@@ -4112,6 +4116,7 @@ impl Methods {
             allow_expect_in_tests,
             allow_unwrap_in_tests,
             allowed_dotfiles,
+            format_args,
         }
     }
 }
@@ -4281,7 +4286,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
                 or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
-                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                expect_fun_call::check(
+                    cx,
+                    &self.format_args,
+                    expr,
+                    method_span,
+                    method_call.ident.as_str(),
+                    receiver,
+                    args,
+                );
                 clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
                 clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
                 inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 1c695655536..f26f164fa54 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -127,7 +127,7 @@ pub(super) fn check<'tcx>(
     }
 }
 
-/// checks for for collecting into a (generic) method or function argument
+/// checks for collecting into a (generic) method or function argument
 /// taking an `IntoIterator`
 fn check_collect_into_intoiterator<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 520dcb2d52d..7431dc1cf0b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -3,10 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
-use clippy_utils::{fn_def_id, get_parent_expr};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local};
+use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{sym, Symbol};
 
@@ -40,6 +42,53 @@ pub fn check_for_loop_iter(
         && !clone_or_copy_needed
         && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
     {
+        // Issue 12098
+        // https://github.com/rust-lang/rust-clippy/issues/12098
+        // if the assignee have `mut borrow` conflict with the iteratee
+        // the lint should not execute, former didn't consider the mut case
+
+        // check whether `expr` is mutable
+        fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+            if let Some(hir_id) = path_to_local(expr)
+                && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
+            {
+                matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
+            } else {
+                true
+            }
+        }
+
+        fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool {
+            let mut change = false;
+            if let ExprKind::Block(block, ..) = body.kind {
+                for_each_expr(block, |e| {
+                    match e.kind {
+                        ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => {
+                            change |= !can_mut_borrow_both(cx, caller, assignee);
+                        },
+                        _ => {},
+                    }
+                    // the return value has no effect but the function need one return value
+                    ControlFlow::<()>::Continue(())
+                });
+            }
+            change
+        }
+
+        if let ExprKind::Call(_, [child, ..]) = expr.kind {
+            // filter first layer of iterator
+            let mut child = child;
+            // get inner real caller requests for clone
+            while let ExprKind::MethodCall(_, caller, _, _) = child.kind {
+                child = caller;
+            }
+            if is_mutable(cx, child) && is_caller_or_fields_change(cx, body, child) {
+                // skip lint
+                return true;
+            }
+        };
+
+        // the lint should not be executed if no violation happens
         let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind
             && maybe_iter_method_name.ident.name == sym::iter
             && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index c50f24f824a..34d7b9acbe4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -120,6 +120,7 @@ fn pat_bindings(pat: &Pat<'_>) -> Vec<HirId> {
 /// operations performed on `binding_hir_ids` are:
 /// * to take non-mutable references to them
 /// * to use them as non-mutable `&self` in method calls
+///
 /// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true
 /// when `CloneOrCopyVisitor` is done visiting.
 struct CloneOrCopyVisitor<'cx, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index ae6cf992ef7..daf166bad90 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
+use clippy_utils::mir::PossibleBorrowerMap;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
@@ -11,7 +11,6 @@ use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath};
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::{
     self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty,
 };
@@ -106,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
             }
             && let count = needless_borrow_count(
                 cx,
-                &mut self.possible_borrowers,
                 fn_id,
                 cx.typeck_results().node_args(hir_id),
                 i,
@@ -155,11 +153,9 @@ fn path_has_args(p: &QPath<'_>) -> bool {
 /// The following constraints will be checked:
 /// * The borrowed expression meets all the generic type's constraints.
 /// * The generic type appears only once in the functions signature.
-/// * The borrowed value will not be moved if it is used later in the function.
-#[expect(clippy::too_many_arguments)]
+/// * The borrowed value is Copy itself OR not a variable (created by a function call)
 fn needless_borrow_count<'tcx>(
     cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     fn_id: DefId,
     callee_args: ty::GenericArgsRef<'tcx>,
     arg_index: usize,
@@ -234,9 +230,9 @@ fn needless_borrow_count<'tcx>(
 
         let referent_ty = cx.typeck_results().expr_ty(referent);
 
-        if !is_copy(cx, referent_ty)
-            && (referent_ty.has_significant_drop(cx.tcx, cx.param_env)
-                || !referent_used_exactly_once(cx, possible_borrowers, reference))
+        if (!is_copy(cx, referent_ty) && !referent_ty.is_ref())
+            && let ExprKind::AddrOf(_, _, inner) = reference.kind
+            && !matches!(inner.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
         {
             return false;
         }
@@ -339,37 +335,6 @@ fn is_mixed_projection_predicate<'tcx>(
     }
 }
 
-fn referent_used_exactly_once<'tcx>(
-    cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    reference: &Expr<'tcx>,
-) -> bool {
-    if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id)
-        && let Some(local) = expr_local(cx.tcx, reference)
-        && let [location] = *local_assignments(mir, local).as_slice()
-        && let block_data = &mir.basic_blocks[location.block]
-        && let Some(statement) = block_data.statements.get(location.statement_index)
-        && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
-        && !place.is_indirect_first_projection()
-    {
-        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
-        if possible_borrowers
-            .last()
-            .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
-        {
-            possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
-        }
-        let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
-        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
-        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
-        // itself. See the comment in that method for an explanation as to why.
-        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
-            && used_exactly_once(mir, place.local).unwrap_or(false)
-    } else {
-        false
-    }
-}
-
 // Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting
 // projected type that is a type parameter. Returns `false` if replacing the types would have an
 // effect on the function signature beyond substituting `new_ty` for `param_ty`.
@@ -408,7 +373,11 @@ fn replace_types<'tcx>(
                     && let Some(term_ty) = projection_predicate.term.ty()
                     && let ty::Param(term_param_ty) = term_ty.kind()
                 {
-                    let projection = projection_predicate.projection_term.with_self_ty(cx.tcx, new_ty).expect_ty(cx.tcx).to_ty(cx.tcx);
+                    let projection = projection_predicate
+                        .projection_term
+                        .with_self_ty(cx.tcx, new_ty)
+                        .expect_ty(cx.tcx)
+                        .to_ty(cx.tcx);
 
                     if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
                         && args[term_param_ty.index as usize] != GenericArg::from(projected_ty)
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 8b4a12bb766..b97cb4579ca 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -178,8 +178,7 @@ impl EarlyLintPass for NeedlessContinue {
 /// Given an expression, returns true if either of the following is true
 ///
 /// - The expression is a `continue` node.
-/// - The expression node is a block with the first statement being a
-/// `continue`.
+/// - The expression node is a block with the first statement being a `continue`.
 fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
     match else_expr.kind {
         ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 6605d1fa51a..5a0ae1a4d6d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -273,24 +273,16 @@ fn check<'tcx>(
                 msg_span,
                 "unneeded late initialization",
                 |diag| {
-                    diag.tool_only_span_suggestion(
-                        local_stmt.span,
-                        "remove the local",
-                        "",
-                        Applicability::MachineApplicable,
-                    );
-
-                    diag.span_suggestion(
-                        assign.lhs_span,
-                        format!("declare `{binding_name}` here"),
-                        let_snippet,
+                    diag.multipart_suggestion(
+                        format!("move the declaration `{binding_name}` here"),
+                        vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)],
                         Applicability::MachineApplicable,
                     );
                 },
             );
         },
         ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => {
-            let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
+            let (applicability, mut suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
 
             span_lint_and_then(
                 cx,
@@ -298,30 +290,26 @@ fn check<'tcx>(
                 local_stmt.span,
                 "unneeded late initialization",
                 |diag| {
-                    diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
-
-                    diag.span_suggestion_verbose(
-                        usage.stmt.span.shrink_to_lo(),
-                        format!("declare `{binding_name}` here"),
-                        format!("{let_snippet} = "),
-                        applicability,
-                    );
-
-                    diag.multipart_suggestion("remove the assignments from the branches", suggestions, applicability);
+                    suggestions.push((local_stmt.span, String::new()));
+                    suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = ")));
 
                     if usage.needs_semi {
-                        diag.span_suggestion(
-                            usage.stmt.span.shrink_to_hi(),
-                            "add a semicolon after the `if` expression",
-                            ";",
-                            applicability,
-                        );
+                        suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned()));
                     }
+
+                    diag.multipart_suggestion(
+                        format!(
+                            "move the declaration `{binding_name}` here and remove the assignments from the branches"
+                        ),
+                        suggestions,
+                        applicability,
+                    );
                 },
             );
         },
         ExprKind::Match(_, arms, MatchSource::Normal) => {
-            let (applicability, suggestions) = assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
+            let (applicability, mut suggestions) =
+                assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
 
             span_lint_and_then(
                 cx,
@@ -329,29 +317,18 @@ fn check<'tcx>(
                 local_stmt.span,
                 "unneeded late initialization",
                 |diag| {
-                    diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
+                    suggestions.push((local_stmt.span, String::new()));
+                    suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = ")));
 
-                    diag.span_suggestion_verbose(
-                        usage.stmt.span.shrink_to_lo(),
-                        format!("declare `{binding_name}` here"),
-                        format!("{let_snippet} = "),
-                        applicability,
-                    );
+                    if usage.needs_semi {
+                        suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned()));
+                    }
 
                     diag.multipart_suggestion(
-                        "remove the assignments from the `match` arms",
+                        format!("move the declaration `{binding_name}` here and remove the assignments from the `match` arms"),
                         suggestions,
                         applicability,
                     );
-
-                    if usage.needs_semi {
-                        diag.span_suggestion(
-                            usage.stmt.span.shrink_to_hi(),
-                            "add a semicolon after the `match` expression",
-                            ";",
-                            applicability,
-                        );
-                    }
                 },
             );
         },
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 9b852f52ea1..da6ed5fb96f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -117,7 +117,9 @@ fn check_closures<'tcx>(
             .associated_body()
             .map(|(_, body_id)| hir.body(body_id))
         {
-            euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx).consume_body(body).into_ok();
+            euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx)
+                .consume_body(body)
+                .into_ok();
         }
     }
 }
@@ -194,7 +196,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
                 async_closures: FxHashSet::default(),
                 tcx: cx.tcx,
             };
-            euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx).consume_body(body).into_ok();
+            euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx)
+                .consume_body(body)
+                .into_ok();
 
             let mut checked_closures = FxHashSet::default();
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 0986571d0f2..f2e00cef7e9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -133,7 +133,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
         // function body.
         let MovedVariablesCtxt { moved_vars } = {
             let mut ctx = MovedVariablesCtxt::default();
-            euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx).consume_body(body).into_ok();
+            euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx)
+                .consume_body(body)
+                .into_ok();
             ctx
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index f915145e794..87f886b1128 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -94,7 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
 
     fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) {
         for hir_id in self.local_bindings.pop().unwrap() {
-            // FIXME(rust/#120456) - is `swap_remove` correct?
             if let Some(span) = self.underscore_bindings.swap_remove(&hir_id) {
                 span_lint_hir(
                     cx,
@@ -109,7 +108,6 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
 
     fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(def_id) = path_to_local(expr) {
-            // FIXME(rust/#120456) - is `swap_remove` correct?
             self.underscore_bindings.swap_remove(&def_id);
         }
     }
@@ -118,7 +116,11 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
 impl NoEffect {
     fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
         if let StmtKind::Semi(expr) = stmt.kind {
-            // move `expr.span.from_expansion()` ahead
+            // Covered by rustc `path_statements` lint
+            if matches!(expr.kind, ExprKind::Path(_)) {
+                return true;
+            }
+
             if expr.span.from_expansion() {
                 return false;
             }
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index ef51a9a9a1c..75066c1f0d2 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -1,8 +1,14 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
+
+#[derive(Clone)]
+pub struct PanicUnimplemented {
+    pub allow_panic_in_tests: bool,
+}
 
 declare_clippy_lint! {
     /// ### What it does
@@ -77,7 +83,7 @@ declare_clippy_lint! {
     "usage of the `unreachable!` macro"
 }
 
-declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
+impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
 
 impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -85,7 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
             return;
         };
         if is_panic(cx, macro_call.def_id) {
-            if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+            if cx.tcx.hir().is_inside_const_context(expr.hir_id)
+                || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id)
+            {
                 return;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 87a3c3874d7..292124196ff 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -389,6 +389,10 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]);
 
 impl<'tcx> LateLintPass<'tcx> for StrToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
         if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
             && path.ident.name == sym::to_string
             && let ty = cx.typeck_results().expr_ty(self_arg)
@@ -437,6 +441,10 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 
 impl<'tcx> LateLintPass<'tcx> for StringToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
         if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
             && path.ident.name == sym::to_string
             && let ty = cx.typeck_results().expr_ty(self_arg)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
index 7d824ef2139..3729dfd3e86 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
 
     let int_ty = substs.type_at(0);
     if from_ty != int_ty {
-      return false;
+        return false;
     }
 
     span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 5b2841dcd83..c0d9bcdd259 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -251,11 +251,7 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
                 local_id: unwrap_info.local_id,
             };
 
-            let vis = ExprUseVisitor::for_clippy(
-                self.cx,
-                cond.hir_id.owner.def_id,
-                &mut delegate,
-            );
+            let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate);
             vis.walk_expr(cond).into_ok();
             vis.walk_expr(branch).into_ok();
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
index 58e66c9f9b9..5acfd35fd6a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
@@ -1,4 +1,4 @@
-use clippy_utils::macros::AST_FORMAT_ARGS;
+use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::source::snippet_opt;
 use itertools::Itertools;
 use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
@@ -9,13 +9,20 @@ use rustc_session::impl_lint_pass;
 use rustc_span::{hygiene, Span};
 use std::iter::once;
 use std::mem;
-use std::rc::Rc;
 
-/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call
-/// [`clippy_utils::macros::find_format_args`]
-#[derive(Default)]
+/// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes
 pub struct FormatArgsCollector {
-    format_args: FxHashMap<Span, Rc<FormatArgs>>,
+    format_args: FxHashMap<Span, FormatArgs>,
+    storage: FormatArgsStorage,
+}
+
+impl FormatArgsCollector {
+    pub fn new(storage: FormatArgsStorage) -> Self {
+        Self {
+            format_args: FxHashMap::default(),
+            storage,
+        }
+    }
 }
 
 impl_lint_pass!(FormatArgsCollector => []);
@@ -27,16 +34,12 @@ impl EarlyLintPass for FormatArgsCollector {
                 return;
             }
 
-            self.format_args
-                .insert(expr.span.with_parent(None), Rc::new((**args).clone()));
+            self.format_args.insert(expr.span.with_parent(None), (**args).clone());
         }
     }
 
     fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) {
-        AST_FORMAT_ARGS.with(|ast_format_args| {
-            let result = ast_format_args.set(mem::take(&mut self.format_args));
-            debug_assert!(result.is_ok());
-        });
+        self.storage.set(mem::take(&mut self.format_args));
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 26c6859233d..ff6ee0d10ad 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro_call_first_node, MacroCall};
+use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall};
 use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_ast::token::LitKind;
@@ -236,13 +236,15 @@ declare_clippy_lint! {
 
 #[derive(Default)]
 pub struct Write {
+    format_args: FormatArgsStorage,
     in_debug_impl: bool,
     allow_print_in_tests: bool,
 }
 
 impl Write {
-    pub fn new(allow_print_in_tests: bool) -> Self {
+    pub fn new(format_args: FormatArgsStorage, allow_print_in_tests: bool) -> Self {
         Self {
+            format_args,
             allow_print_in_tests,
             ..Default::default()
         }
@@ -307,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
             _ => return,
         }
 
-        if let Some(format_args) = find_format_args(cx, expr, macro_call.expn) {
+        if let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) {
             // ignore `writeln!(w)` and `write!(v, some_macro!())`
             if format_args.span.from_expansion() {
                 return;
@@ -315,15 +317,15 @@ impl<'tcx> LateLintPass<'tcx> for Write {
 
             match diag_name {
                 sym::print_macro | sym::eprint_macro | sym::write_macro => {
-                    check_newline(cx, &format_args, &macro_call, name);
+                    check_newline(cx, format_args, &macro_call, name);
                 },
                 sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
-                    check_empty_string(cx, &format_args, &macro_call, name);
+                    check_empty_string(cx, format_args, &macro_call, name);
                 },
                 _ => {},
             }
 
-            check_literal(cx, &format_args, name);
+            check_literal(cx, format_args, name);
 
             if !self.in_debug_impl {
                 for piece in &format_args.template {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 99d7aba2f7a..4c603bda770 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -193,6 +193,21 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
     None
 }
 
+/// Checks if the given local has an initializer or is from something other than a `let` statement
+///
+/// e.g. returns true for `x` in `fn f(x: usize) { .. }` and `let x = 1;` but false for `let x;`
+pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
+    for (_, node) in cx.tcx.hir().parent_iter(local) {
+        match node {
+            Node::Pat(..) | Node::PatField(..) => {},
+            Node::LetStmt(let_stmt) => return let_stmt.init.is_some(),
+            _ => return true,
+        }
+    }
+
+    false
+}
+
 /// Returns `true` if the given `NodeId` is inside a constant context
 ///
 /// # Example
@@ -1499,15 +1514,18 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 }
 
 /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`.
+///
 /// For the lower bound, this means that:
 /// - either there is none
 /// - or it is the smallest value that can be represented by the range's integer type
+///
 /// For the upper bound, this means that:
 /// - either there is none
 /// - or it is the largest value that can be represented by the range's integer type and is
 ///   inclusive
 /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to
 ///   a method call on that same container (e.g. `v.drain(..v.len())`)
+///
 /// If the given `Expr` is not some kind of range, the function returns `false`.
 pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 257dd76ab15..8daab9b0d92 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -5,15 +5,13 @@ use crate::visitors::{for_each_expr, Descend};
 use arrayvec::ArrayVec;
 use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::{Lrc, OnceLock};
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
 use rustc_lint::LateContext;
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
 use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol};
-use std::cell::OnceCell;
 use std::ops::ControlFlow;
-use std::rc::Rc;
-use std::sync::atomic::{AtomicBool, Ordering};
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
     sym::assert_eq_macro,
@@ -388,50 +386,44 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
     }
 }
 
-thread_local! {
-    /// We preserve the [`FormatArgs`] structs from the early pass for use in the late pass to be
-    /// able to access the many features of a [`LateContext`].
-    ///
-    /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
-    /// assumption that the early pass that populates the map and the later late passes will all be
-    /// running on the same thread.
-    #[doc(hidden)]
-    pub static AST_FORMAT_ARGS: OnceCell<FxHashMap<Span, Rc<FormatArgs>>> = {
-        static CALLED: AtomicBool = AtomicBool::new(false);
-        debug_assert!(
-            !CALLED.swap(true, Ordering::SeqCst),
-            "incorrect assumption: `AST_FORMAT_ARGS` should only be accessed by a single thread",
-        );
-
-        OnceCell::new()
-    };
-}
+/// Stores AST [`FormatArgs`] nodes for use in late lint passes, as they are in a desugared form in
+/// the HIR
+#[derive(Default, Clone)]
+pub struct FormatArgsStorage(Lrc<OnceLock<FxHashMap<Span, FormatArgs>>>);
 
-/// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of
-/// `expn_id`
-pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<Rc<FormatArgs>> {
-    let format_args_expr = for_each_expr(start, |expr| {
-        let ctxt = expr.span.ctxt();
-        if ctxt.outer_expn().is_descendant_of(expn_id) {
-            if macro_backtrace(expr.span)
-                .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
-                .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))
-            {
-                ControlFlow::Break(expr)
+impl FormatArgsStorage {
+    /// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of
+    /// `expn_id`
+    ///
+    /// See also [`find_format_arg_expr`]
+    pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> {
+        let format_args_expr = for_each_expr(start, |expr| {
+            let ctxt = expr.span.ctxt();
+            if ctxt.outer_expn().is_descendant_of(expn_id) {
+                if macro_backtrace(expr.span)
+                    .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
+                    .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))
+                {
+                    ControlFlow::Break(expr)
+                } else {
+                    ControlFlow::Continue(Descend::Yes)
+                }
             } else {
-                ControlFlow::Continue(Descend::Yes)
+                ControlFlow::Continue(Descend::No)
             }
-        } else {
-            ControlFlow::Continue(Descend::No)
-        }
-    })?;
+        })?;
 
-    AST_FORMAT_ARGS.with(|ast_format_args| {
-        ast_format_args
-            .get()?
-            .get(&format_args_expr.span.with_parent(None))
-            .cloned()
-    })
+        debug_assert!(self.0.get().is_some(), "`FormatArgsStorage` not yet populated");
+
+        self.0.get()?.get(&format_args_expr.span.with_parent(None))
+    }
+
+    /// Should only be called by `FormatArgsCollector`
+    pub fn set(&self, format_args: FxHashMap<Span, FormatArgs>) {
+        self.0
+            .set(format_args)
+            .expect("`FormatArgsStorage::set` should only be called once");
+    }
 }
 
 /// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 06229ac938f..7b4fd8a210e 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -149,7 +149,7 @@ impl TypeVisitor<TyCtxt<'_>> for ContainsRegion {
 }
 
 fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
-    use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
+    use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, Repeat, UnaryOp, Use};
 
     let mut visit_op = |op: &mir::Operand<'_>| match op {
         mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
@@ -159,7 +159,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
     match rvalue {
         Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op),
         Aggregate(_, ops) => ops.iter().for_each(visit_op),
-        BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
+        BinaryOp(_, box (lhs, rhs)) => {
             visit_op(lhs);
             visit_op(rhs);
         },
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 95851a2eed8..8ee7d87acb3 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -3,7 +3,7 @@
 // of terminologies might not be relevant in the context of Clippy. Note that its behavior might
 // differ from the time of `rustc` even if the name stays the same.
 
-use clippy_config::msrvs::Msrv;
+use clippy_config::msrvs::{self, Msrv};
 use hir::LangItem;
 use rustc_attr::StableSince;
 use rustc_const_eval::transform::check_consts::ConstCx;
@@ -42,7 +42,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
     for bb in &*body.basic_blocks {
         check_terminator(tcx, body, bb.terminator(), msrv)?;
         for stmt in &bb.statements {
-            check_statement(tcx, body, def_id, stmt)?;
+            check_statement(tcx, body, def_id, stmt, msrv)?;
         }
     }
     Ok(())
@@ -102,13 +102,14 @@ fn check_rvalue<'tcx>(
     def_id: DefId,
     rvalue: &Rvalue<'tcx>,
     span: Span,
+    msrv: &Msrv,
 ) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
         Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
-            check_place(tcx, *place, span, body)
+            check_place(tcx, *place, span, body, msrv)
         },
-        Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body),
+        Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
         | Rvalue::Cast(
@@ -122,7 +123,7 @@ fn check_rvalue<'tcx>(
             | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer),
             operand,
             _,
-        ) => check_operand(tcx, operand, span, body),
+        ) => check_operand(tcx, operand, span, body, msrv),
         Rvalue::Cast(
             CastKind::PointerCoercion(
                 PointerCoercion::UnsafeFnPointer
@@ -133,15 +134,13 @@ fn check_rvalue<'tcx>(
             _,
         ) => Err((span, "function pointer casts are not allowed in const fn".into())),
         Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => {
-            let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
-                deref_ty
-            } else {
+            let Some(pointee_ty) = cast_ty.builtin_deref(true) else {
                 // We cannot allow this for now.
                 return Err((span, "unsizing casts are only allowed for references right now".into()));
             };
             let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
-                check_operand(tcx, op, span, body)?;
+                check_operand(tcx, op, span, body, msrv)?;
                 // Casting/coercing things to slices is fine.
                 Ok(())
             } else {
@@ -161,9 +160,9 @@ fn check_rvalue<'tcx>(
             "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(),
         )),
         // binops are fine on integers
-        Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
-            check_operand(tcx, lhs, span, body)?;
-            check_operand(tcx, rhs, span, body)?;
+        Rvalue::BinaryOp(_, box (lhs, rhs)) => {
+            check_operand(tcx, lhs, span, body, msrv)?;
+            check_operand(tcx, rhs, span, body, msrv)?;
             let ty = lhs.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() || ty.is_char() {
                 Ok(())
@@ -179,14 +178,14 @@ fn check_rvalue<'tcx>(
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
-                check_operand(tcx, operand, span, body)
+                check_operand(tcx, operand, span, body, msrv)
             } else {
                 Err((span, "only int and `bool` operations are stable in const fn".into()))
             }
         },
         Rvalue::Aggregate(_, operands) => {
             for operand in operands {
-                check_operand(tcx, operand, span, body)?;
+                check_operand(tcx, operand, span, body, msrv)?;
             }
             Ok(())
         },
@@ -198,28 +197,29 @@ fn check_statement<'tcx>(
     body: &Body<'tcx>,
     def_id: DefId,
     statement: &Statement<'tcx>,
+    msrv: &Msrv,
 ) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
         StatementKind::Assign(box (place, rval)) => {
-            check_place(tcx, *place, span, body)?;
-            check_rvalue(tcx, body, def_id, rval, span)
+            check_place(tcx, *place, span, body, msrv)?;
+            check_rvalue(tcx, body, def_id, rval, span, msrv)
         },
 
-        StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
+        StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body, msrv),
         // just an assignment
         StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
-            check_place(tcx, **place, span, body)
+            check_place(tcx, **place, span, body, msrv)
         },
 
-        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body, msrv),
 
         StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
             rustc_middle::mir::CopyNonOverlapping { dst, src, count },
         )) => {
-            check_operand(tcx, dst, span, body)?;
-            check_operand(tcx, src, span, body)?;
-            check_operand(tcx, count, span, body)
+            check_operand(tcx, dst, span, body, msrv)?;
+            check_operand(tcx, src, span, body, msrv)?;
+            check_operand(tcx, count, span, body, msrv)
         },
         // These are all NOPs
         StatementKind::StorageLive(_)
@@ -233,7 +233,13 @@ fn check_statement<'tcx>(
     }
 }
 
-fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+fn check_operand<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    operand: &Operand<'tcx>,
+    span: Span,
+    body: &Body<'tcx>,
+    msrv: &Msrv,
+) -> McfResult {
     match operand {
         Operand::Move(place) => {
             if !place.projection.as_ref().is_empty()
@@ -245,9 +251,9 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b
                 ));
             }
 
-            check_place(tcx, *place, span, body)
+            check_place(tcx, *place, span, body, msrv)
         },
-        Operand::Copy(place) => check_place(tcx, *place, span, body),
+        Operand::Copy(place) => check_place(tcx, *place, span, body, msrv),
         Operand::Constant(c) => match c.check_static_ptr(tcx) {
             Some(_) => Err((span, "cannot access `static` items in const fn".into())),
             None => Ok(()),
@@ -255,23 +261,27 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b
     }
 }
 
-fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
     for (base, elem) in place.as_ref().iter_projections() {
         match elem {
             ProjectionElem::Field(..) => {
-                let base_ty = base.ty(body, tcx).ty;
-                if let Some(def) = base_ty.ty_adt_def() {
-                    // No union field accesses in `const fn`
-                    if def.is_union() {
-                        return Err((span, "accessing union fields is unstable".into()));
-                    }
+                if base.ty(body, tcx).ty.is_union() && !msrv.meets(msrvs::CONST_FN_UNION) {
+                    return Err((span, "accessing union fields is unstable".into()));
                 }
             },
+            ProjectionElem::Deref => match base.ty(body, tcx).ty.kind() {
+                ty::RawPtr(_, hir::Mutability::Mut) => {
+                    return Err((span, "dereferencing raw mut pointer in const fn is unstable".into()));
+                },
+                ty::RawPtr(_, hir::Mutability::Not) if !msrv.meets(msrvs::CONST_RAW_PTR_DEREF) => {
+                    return Err((span, "dereferencing raw const pointer in const fn is unstable".into()));
+                },
+                _ => (),
+            },
             ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
-            | ProjectionElem::Deref
             | ProjectionElem::Subtype(_)
             | ProjectionElem::Index(_) => {},
         }
@@ -304,7 +314,7 @@ fn check_terminator<'tcx>(
             }
             Ok(())
         },
-        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
+        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body, msrv),
         TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
             Err((span, "const fn coroutines are unstable".into()))
         },
@@ -341,10 +351,10 @@ fn check_terminator<'tcx>(
                     ));
                 }
 
-                check_operand(tcx, func, span, body)?;
+                check_operand(tcx, func, span, body, msrv)?;
 
                 for arg in args {
-                    check_operand(tcx, &arg.node, span, body)?;
+                    check_operand(tcx, &arg.node, span, body, msrv)?;
                 }
                 Ok(())
             } else {
@@ -357,7 +367,7 @@ fn check_terminator<'tcx>(
             msg: _,
             target: _,
             unwind: _,
-        } => check_operand(tcx, cond, span, body),
+        } => check_operand(tcx, cond, span, body, msrv),
         TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index e72467edeeb..fd67e039c29 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -250,7 +250,7 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<
 /// - Applicability level `Unspecified` will never be changed.
 /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 /// - If the default value is used and the applicability level is `MachineApplicable`, change it to
-/// `HasPlaceholders`
+///   `HasPlaceholders`
 pub fn snippet_with_applicability<'a, T: LintContext>(
     cx: &T,
     span: Span,
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index bf03c6c1601..6319c7bfa6b 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -67,8 +67,7 @@ impl<'a> Sugg<'a> {
     /// - Applicability level `Unspecified` will never be changed.
     /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
     /// - If the default value is used and the applicability level is `MachineApplicable`, change it
-    ///   to
-    /// `HasPlaceholders`
+    ///   to `HasPlaceholders`
     pub fn hir_with_applicability(
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index c29e3feac9a..2dacc34867f 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -273,11 +273,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
     let infcx = tcx.infer_ctxt().build();
     let args = args
         .into_iter()
-        .map(|arg| {
-            arg.into().unwrap_or_else(|| {
-                infcx.next_ty_var(DUMMY_SP).into()
-            })
-        })
+        .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
         .collect::<Vec<_>>();
 
     // If an effect arg was not specified, we need to specify it.
@@ -795,7 +791,8 @@ fn sig_from_bounds<'tcx>(
                 inputs = Some(i);
             },
             ty::ClauseKind::Projection(p)
-                if Some(p.projection_term.def_id) == lang_items.fn_once_output() && p.projection_term.self_ty() == ty =>
+                if Some(p.projection_term.def_id) == lang_items.fn_once_output()
+                    && p.projection_term.self_ty() == ty =>
             {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -956,11 +953,7 @@ pub struct AdtVariantInfo {
 
 impl AdtVariantInfo {
     /// Returns ADT variants ordered by size
-    pub fn new<'tcx>(
-        cx: &LateContext<'tcx>,
-        adt: AdtDef<'tcx>,
-        subst: GenericArgsRef<'tcx>
-    ) -> Vec<Self> {
+    pub fn new<'tcx>(cx: &LateContext<'tcx>, adt: AdtDef<'tcx>, subst: GenericArgsRef<'tcx>) -> Vec<Self> {
         let mut variants_size = adt
             .variants()
             .iter()
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index c2ff19931d5..80219303450 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -176,7 +176,7 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo
             .get(*lang_item)
             .map_or(Certainty::Uncertain, |def_id| {
                 let generics = cx.tcx.generics_of(def_id);
-                if generics.parent_count == 0 && generics.own_params.is_empty() {
+                if generics.is_empty() {
                     Certainty::Certain(if resolves_to_type { Some(def_id) } else { None })
                 } else {
                     Certainty::Uncertain
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 9abb4ef9b8d..2a25d51d8e5 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -16,13 +16,9 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) ->
         used_mutably: HirIdSet::default(),
         skip: false,
     };
-    ExprUseVisitor::for_clippy(
-        cx,
-        expr.hir_id.owner.def_id,
-        &mut delegate,
-    )
-    .walk_expr(expr)
-    .into_ok();
+    ExprUseVisitor::for_clippy(cx, expr.hir_id.owner.def_id, &mut delegate)
+        .walk_expr(expr)
+        .into_ok();
 
     if delegate.skip {
         return None;
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index a828d123704..8c5a409e25b 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -13,7 +13,7 @@ default-run = "lintcheck"
 [dependencies]
 anyhow = "1.0.69"
 cargo_metadata = "0.15.3"
-clap = { version = "4.1.8", features = ["derive", "env"] }
+clap = { version = "4.4", features = ["derive", "env"] }
 crates_io_api = "0.8.1"
 crossbeam-channel = "0.5.6"
 flate2 = "1.0"
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 055f305eb8e..a0585ffdb45 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-05-02"
+channel = "nightly-2024-05-16"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
index 103e60d8484..9177e99f8e6 100644
--- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
@@ -42,4 +42,32 @@ help: to have lints override the group set `pedantic` to a lower priority
 19 | pedantic = { level = "warn", priority = -2 }
    |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: could not compile `fail` (lib) due to 3 previous errors
+error: lint group `rust_2018_idioms` has the same priority (0) as a lint
+  --> Cargo.toml:23:1
+   |
+23 | rust_2018_idioms = "warn"
+   | ^^^^^^^^^^^^^^^^   ------ has an implicit priority of 0
+24 | bare_trait_objects = "allow"
+   | ------------------ has the same priority as this lint
+   |
+   = note: the order of the lints in the table is ignored by Cargo
+help: to have lints override the group set `rust_2018_idioms` to a lower priority
+   |
+23 | rust_2018_idioms = { level = "warn", priority = -1 }
+   |                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: lint group `pedantic` has the same priority (0) as a lint
+  --> Cargo.toml:27:1
+   |
+27 | pedantic = "warn"
+   | ^^^^^^^^   ------ has an implicit priority of 0
+28 | similar_names = "allow"
+   | ------------- has the same priority as this lint
+   |
+   = note: the order of the lints in the table is ignored by Cargo
+help: to have lints override the group set `pedantic` to a lower priority
+   |
+27 | pedantic = { level = "warn", priority = -1 }
+   |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: could not compile `fail` (lib) due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
index 4ce41f78171..e4d4af9cd23 100644
--- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
@@ -18,3 +18,11 @@ deprecated  = "allow"
 [lints.clippy]
 pedantic = { level = "warn", priority = -1 }
 similar_names = { level = "allow", priority = -1 }
+
+[workspace.lints.rust]
+rust_2018_idioms = "warn"
+bare_trait_objects = "allow"
+
+[workspace.lints.clippy]
+pedantic = "warn"
+similar_names = "allow"
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
new file mode 100644
index 00000000000..f5e01b431ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
@@ -0,0 +1,260 @@
+//! Tests macro_metavars_in_unsafe with default configuration
+#![feature(decl_macro, lint_reasons)]
+#![warn(clippy::macro_metavars_in_unsafe)]
+#![allow(clippy::no_effect)]
+
+#[macro_export]
+macro_rules! allow_works {
+    ($v:expr) => {
+        #[expect(clippy::macro_metavars_in_unsafe)]
+        unsafe {
+            $v;
+        };
+    };
+}
+
+#[macro_export]
+macro_rules! simple {
+    ($v:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            dbg!($v);
+        }
+    };
+}
+
+#[macro_export]
+#[rustfmt::skip] // for some reason rustfmt rewrites $r#unsafe to r#u$nsafe, bug?
+macro_rules! raw_symbol {
+    ($r#mod:expr, $r#unsafe:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $r#mod;
+        }
+        $r#unsafe;
+    };
+}
+
+#[macro_export]
+macro_rules! multilevel_unsafe {
+    ($v:expr) => {
+        unsafe {
+            unsafe {
+                //~^ ERROR: this macro expands metavariables in an unsafe block
+                $v;
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! in_function {
+    ($v:expr) => {
+        unsafe {
+            fn f() {
+                // function introduces a new body, so don't lint.
+                $v;
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! in_function_with_unsafe {
+    ($v:expr) => {
+        unsafe {
+            fn f() {
+                unsafe {
+                    //~^ ERROR: this macro expands metavariables in an unsafe block
+                    $v;
+                }
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! const_static {
+    ($c:expr, $s:expr) => {
+        unsafe {
+            // const and static introduces new body, don't lint
+            const _X: i32 = $c;
+            static _Y: i32 = $s;
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! const_generic_in_struct {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            struct Ty<
+                const L: i32 = 1,
+                const M: i32 = {
+                    1;
+                    unsafe { $inside_unsafe }
+                    //~^ ERROR: this macro expands metavariables in an unsafe block
+                },
+                const N: i32 = { $outside_unsafe },
+            >;
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! fn_with_const_generic {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            fn f<const N: usize>() {
+                $outside_unsafe;
+                unsafe {
+                    //~^ ERROR: this macro expands metavariables in an unsafe block
+                    $inside_unsafe;
+                }
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! variables {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $inside_unsafe;
+            let inside_unsafe = 1;
+            inside_unsafe;
+        }
+        $outside_unsafe;
+        let outside_unsafe = 1;
+        outside_unsafe;
+    };
+}
+
+#[macro_export]
+macro_rules! multiple_matchers {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $inside_unsafe;
+        }
+        $outside_unsafe;
+    };
+    ($($v:expr, $x:expr),+) => {
+        $(
+            $v;
+            unsafe {
+                //~^ ERROR: this macro expands metavariables in an unsafe block
+                $x;
+            }
+        );+
+    };
+}
+
+#[macro_export]
+macro_rules! multiple_unsafe_blocks {
+    ($w:expr, $x:expr, $y:expr) => {
+        $w;
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $x;
+        }
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $x;
+            $y;
+        }
+    };
+}
+
+pub macro macro2_0($v:expr) {
+    unsafe {
+        //~^ ERROR: this macro expands metavariables in an unsafe block
+        $v;
+    }
+}
+
+// don't lint private macros with the default configuration
+macro_rules! private_mac {
+    ($v:expr) => {
+        unsafe {
+            $v;
+        }
+    };
+}
+
+// don't lint exported macros that are doc(hidden) because they also aren't part of the public API
+#[macro_export]
+#[doc(hidden)]
+macro_rules! exported_but_hidden {
+    ($v:expr) => {
+        unsafe {
+            $v;
+        }
+    };
+}
+
+// don't lint if the same metavariable is expanded in an unsafe block and then outside of one:
+// unsafe {} is still needed at callsite so not problematic
+#[macro_export]
+macro_rules! does_require_unsafe {
+    ($v:expr) => {
+        unsafe {
+            $v;
+        }
+        $v;
+    };
+}
+
+#[macro_export]
+macro_rules! unsafe_from_root_ctxt {
+    ($v:expr) => {
+        // Expands to unsafe { 1 }, but the unsafe block is from the root ctxt and not this macro,
+        // so no warning.
+        $v;
+    };
+}
+
+// invoked from another macro, should still generate a warning
+#[macro_export]
+macro_rules! nested_macro_helper {
+    ($v:expr) => {{
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $v;
+        }
+    }};
+}
+
+#[macro_export]
+macro_rules! nested_macros {
+    ($v:expr, $v2:expr) => {{
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            nested_macro_helper!($v);
+            $v;
+        }
+    }};
+}
+
+fn main() {
+    allow_works!(1);
+    simple!(1);
+    raw_symbol!(1, 1);
+    multilevel_unsafe!(1);
+    in_function!(1);
+    in_function_with_unsafe!(1);
+    const_static!(1, 1);
+    const_generic_in_struct!(1, 1);
+    fn_with_const_generic!(1, 1);
+    variables!(1, 1);
+    multiple_matchers!(1, 1);
+    multiple_matchers!(1, 1, 1, 1);
+    macro2_0!(1);
+    private_mac!(1);
+    exported_but_hidden!(1);
+    does_require_unsafe!(1);
+    multiple_unsafe_blocks!(1, 1, 1);
+    unsafe_from_root_ctxt!(unsafe { 1 });
+    nested_macros!(1, 1);
+}
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr
new file mode 100644
index 00000000000..d6b97f6fde1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr
@@ -0,0 +1,187 @@
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:19:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             dbg!($v);
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+   = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]`
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:30:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $r#mod;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:42:13
+   |
+LL | /             unsafe {
+LL | |
+LL | |                 $v;
+LL | |             }
+   | |_____________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:67:17
+   |
+LL | /                 unsafe {
+LL | |
+LL | |                     $v;
+LL | |                 }
+   | |_________________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:95:21
+   |
+LL |                     unsafe { $inside_unsafe }
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:110:17
+   |
+LL | /                 unsafe {
+LL | |
+LL | |                     $inside_unsafe;
+LL | |                 }
+   | |_________________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:122:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $inside_unsafe;
+LL | |             let inside_unsafe = 1;
+LL | |             inside_unsafe;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:137:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $inside_unsafe;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:146:13
+   |
+LL | /             unsafe {
+LL | |
+LL | |                 $x;
+LL | |             }
+   | |_____________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:171:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         $v;
+LL | |     }
+   | |_____^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:158:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $x;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:162:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $x;
+LL | |             $y;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:222:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $v;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:232:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             nested_macro_helper!($v);
+LL | |             $v;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml
new file mode 100644
index 00000000000..d4bbc2a1be8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml
@@ -0,0 +1 @@
+warn-unsafe-macro-metavars-in-private-macros = true
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs
new file mode 100644
index 00000000000..2bbe1fa7b7f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs
@@ -0,0 +1,15 @@
+//! Tests macro_metavars_in_unsafe with private (non-exported) macros
+#![warn(clippy::macro_metavars_in_unsafe)]
+
+macro_rules! mac {
+    ($v:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            dbg!($v);
+        }
+    };
+}
+
+fn main() {
+    mac!(1);
+}
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr
new file mode 100644
index 00000000000..f9c418b2218
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr
@@ -0,0 +1,17 @@
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/private/test.rs:6:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             dbg!($v);
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+   = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/panic/clippy.toml b/src/tools/clippy/tests/ui-toml/panic/clippy.toml
new file mode 100644
index 00000000000..5d6230d092c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/panic/clippy.toml
@@ -0,0 +1 @@
+allow-panic-in-tests = true
diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.rs b/src/tools/clippy/tests/ui-toml/panic/panic.rs
new file mode 100644
index 00000000000..618a37ddfc5
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/panic/panic.rs
@@ -0,0 +1,54 @@
+//@compile-flags: --test
+#![warn(clippy::panic)]
+
+fn main() {
+    enum Enam {
+        A,
+    }
+    let a = Enam::A;
+    match a {
+        Enam::A => {},
+        _ => panic!(""),
+    }
+}
+
+#[test]
+fn lonely_test() {
+    enum Enam {
+        A,
+    }
+    let a = Enam::A;
+    match a {
+        Enam::A => {},
+        _ => panic!(""),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // should not lint in `#[cfg(test)]` modules
+    #[test]
+    fn test_fn() {
+        enum Enam {
+            A,
+        }
+        let a = Enam::A;
+        match a {
+            Enam::A => {},
+            _ => panic!(""),
+        }
+
+        bar();
+    }
+
+    fn bar() {
+        enum Enam {
+            A,
+        }
+        let a = Enam::A;
+        match a {
+            Enam::A => {},
+            _ => panic!(""),
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.stderr b/src/tools/clippy/tests/ui-toml/panic/panic.stderr
new file mode 100644
index 00000000000..bf7503e086c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/panic/panic.stderr
@@ -0,0 +1,11 @@
+error: `panic` should not be present in production code
+  --> tests/ui-toml/panic/panic.rs:11:14
+   |
+LL |         _ => panic!(""),
+   |              ^^^^^^^^^^
+   |
+   = note: `-D clippy::panic` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::panic)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml b/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml
new file mode 100644
index 00000000000..5381e70a939
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml
@@ -0,0 +1,2 @@
+# Ignore `From`, `TryFrom`, `FromStr` by default
+# allow-renamed-params-for = []
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml b/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml
new file mode 100644
index 00000000000..9b3853e7696
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml
@@ -0,0 +1,2 @@
+# Ignore `From`, `TryFrom`, `FromStr` by default
+allow-renamed-params-for = [ "..", "std::ops::Add", "renamed_function_params::MyTrait" ]
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr
new file mode 100644
index 00000000000..2d700f60759
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr
@@ -0,0 +1,46 @@
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:30:18
+   |
+LL |     fn eq(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+   |
+   = note: `-D clippy::renamed-function-params` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::renamed_function_params)]`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:34:18
+   |
+LL |     fn ne(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:48:19
+   |
+LL |     fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the default name: `val`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31
+   |
+LL |     fn hash<H: Hasher>(&self, states: &mut H) {
+   |                               ^^^^^^ help: consider using the default name: `state`
+
+error: renamed function parameters of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30
+   |
+LL |     fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) {
+   |                              ^^^^           ^^^^^^
+   |
+help: consider using the default names
+   |
+LL |     fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) {
+   |                              ~~~~           ~~~~~
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:80:18
+   |
+LL |     fn add(self, b: B) -> C {
+   |                  ^ help: consider using the default name: `rhs`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr
new file mode 100644
index 00000000000..e57554fa613
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr
@@ -0,0 +1,34 @@
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:30:18
+   |
+LL |     fn eq(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+   |
+   = note: `-D clippy::renamed-function-params` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::renamed_function_params)]`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:34:18
+   |
+LL |     fn ne(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31
+   |
+LL |     fn hash<H: Hasher>(&self, states: &mut H) {
+   |                               ^^^^^^ help: consider using the default name: `state`
+
+error: renamed function parameters of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30
+   |
+LL |     fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) {
+   |                              ^^^^           ^^^^^^
+   |
+help: consider using the default names
+   |
+LL |     fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) {
+   |                              ~~~~           ~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs
new file mode 100644
index 00000000000..f3eb910abbd
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs
@@ -0,0 +1,110 @@
+//@no-rustfix
+//@revisions: default extend
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/renamed_function_params/default
+//@[extend] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/renamed_function_params/extend
+#![warn(clippy::renamed_function_params)]
+#![allow(clippy::partialeq_ne_impl, clippy::to_string_trait_impl)]
+#![allow(unused)]
+
+use std::hash::{Hash, Hasher};
+
+struct A;
+impl From<A> for String {
+    fn from(_value: A) -> Self {
+        String::new()
+    }
+}
+impl ToString for A {
+    fn to_string(&self) -> String {
+        String::new()
+    }
+}
+
+struct B(u32);
+impl std::convert::From<B> for String {
+    fn from(b: B) -> Self {
+        b.0.to_string()
+    }
+}
+impl PartialEq for B {
+    fn eq(&self, rhs: &Self) -> bool {
+        //~^ ERROR: renamed function parameter of trait impl
+        self.0 == rhs.0
+    }
+    fn ne(&self, rhs: &Self) -> bool {
+        //~^ ERROR: renamed function parameter of trait impl
+        self.0 != rhs.0
+    }
+}
+
+trait MyTrait {
+    fn foo(&self, val: u8);
+    fn bar(a: u8, b: u8);
+    fn baz(self, _val: u8);
+    fn quz(&self, _: u8);
+}
+
+impl MyTrait for B {
+    fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend`
+    fn bar(_a: u8, _: u8) {}
+    fn baz(self, val: u8) {}
+    fn quz(&self, val: u8) {}
+}
+
+impl Hash for B {
+    fn hash<H: Hasher>(&self, states: &mut H) {
+        //~^ ERROR: renamed function parameter of trait impl
+        self.0.hash(states);
+    }
+    fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) {
+        //~^ ERROR: renamed function parameters of trait impl
+        for d in date {
+            d.hash(states);
+        }
+    }
+}
+
+impl B {
+    fn totally_irrelevant(&self, right: bool) {}
+    fn some_fn(&self, other: impl MyTrait) {}
+}
+
+#[derive(Copy, Clone)]
+enum C {
+    A,
+    B(u32),
+}
+
+impl std::ops::Add<B> for C {
+    type Output = C;
+    fn add(self, b: B) -> C {
+        // only lint in `extend`
+        C::B(b.0)
+    }
+}
+
+impl From<A> for C {
+    fn from(_: A) -> C {
+        C::A
+    }
+}
+
+trait CustomTraitA {
+    fn foo(&self, other: u32);
+}
+trait CustomTraitB {
+    fn bar(&self, value: u8);
+}
+
+macro_rules! impl_trait {
+    ($impl_for:ident, $tr:ty, $fn_name:ident, $t:ty) => {
+        impl $tr for $impl_for {
+            fn $fn_name(&self, v: $t) {}
+        }
+    };
+}
+
+impl_trait!(C, CustomTraitA, foo, u32);
+impl_trait!(C, CustomTraitB, bar, u8);
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
index 7f28efd676f..f02bd07cfe7 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
@@ -40,3 +40,9 @@ fn main() {
     let _ = HashMap;
     let _: usize = 64_usize;
 }
+
+mod useless_attribute {
+    // Regression test for https://github.com/rust-lang/rust-clippy/issues/12753
+    #[allow(clippy::disallowed_types)]
+    use std::collections::HashMap;
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 722e9b3bc8d..5cf9c0fb271 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -8,8 +8,10 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
            allow-one-hash-in-raw-strings
+           allow-panic-in-tests
            allow-print-in-tests
            allow-private-module-inception
+           allow-renamed-params-for
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -74,6 +76,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
+           warn-unsafe-macro-metavars-in-private-macros
   --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:2:1
    |
 LL | foobar = 42
@@ -89,8 +92,10 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
            allow-one-hash-in-raw-strings
+           allow-panic-in-tests
            allow-print-in-tests
            allow-private-module-inception
+           allow-renamed-params-for
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -155,6 +160,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
+           warn-unsafe-macro-metavars-in-private-macros
   --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:4:1
    |
 LL | barfoo = 53
@@ -170,8 +176,10 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
            allow-one-hash-in-raw-strings
+           allow-panic-in-tests
            allow-print-in-tests
            allow-private-module-inception
+           allow-renamed-params-for
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -236,6 +244,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
+           warn-unsafe-macro-metavars-in-private-macros
   --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:7:1
    |
 LL | allow_mixed_uninlined_format_args = true
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index 8387c7d6156..70ab43b49b3 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -62,6 +62,16 @@ fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFr
     mut_thing.clone_from(ref_thing + ref_thing);
 }
 
+fn clone_method_macro() {
+    let mut s = String::from("");
+    s.clone_from(&format!("{} {}", "hello", "world"));
+}
+
+fn clone_function_macro() {
+    let mut s = String::from("");
+    Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"));
+}
+
 fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom {
     let mut a = HasCloneFrom;
     for _ in 1..10 {
@@ -86,6 +96,12 @@ fn assign_to_uninit_mut_var(b: HasCloneFrom) {
     a = b.clone();
 }
 
+fn late_init_let_tuple() {
+    let (p, q): (String, String);
+    p = "ghi".to_string();
+    q = p.clone();
+}
+
 #[derive(Clone)]
 pub struct HasDeriveClone;
 
@@ -208,6 +224,16 @@ fn owned_function_val(mut mut_thing: String, ref_str: &str) {
     ToOwned::clone_into(ref_str, &mut mut_thing);
 }
 
+fn owned_method_macro() {
+    let mut s = String::from("");
+    format!("{} {}", "hello", "world").clone_into(&mut s);
+}
+
+fn owned_function_macro() {
+    let mut s = String::from("");
+    ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s);
+}
+
 struct FakeToOwned;
 impl FakeToOwned {
     /// This looks just like `ToOwned::to_owned`
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index 6f4da9f652c..9699fed100c 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -62,6 +62,16 @@ fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFr
     *mut_thing = (ref_thing + ref_thing).clone();
 }
 
+fn clone_method_macro() {
+    let mut s = String::from("");
+    s = format!("{} {}", "hello", "world").clone();
+}
+
+fn clone_function_macro() {
+    let mut s = String::from("");
+    s = Clone::clone(&format!("{} {}", "hello", "world"));
+}
+
 fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom {
     let mut a = HasCloneFrom;
     for _ in 1..10 {
@@ -86,6 +96,12 @@ fn assign_to_uninit_mut_var(b: HasCloneFrom) {
     a = b.clone();
 }
 
+fn late_init_let_tuple() {
+    let (p, q): (String, String);
+    p = "ghi".to_string();
+    q = p.clone();
+}
+
 #[derive(Clone)]
 pub struct HasDeriveClone;
 
@@ -208,6 +224,16 @@ fn owned_function_val(mut mut_thing: String, ref_str: &str) {
     mut_thing = ToOwned::to_owned(ref_str);
 }
 
+fn owned_method_macro() {
+    let mut s = String::from("");
+    s = format!("{} {}", "hello", "world").to_owned();
+}
+
+fn owned_function_macro() {
+    let mut s = String::from("");
+    s = ToOwned::to_owned(&format!("{} {}", "hello", "world"));
+}
+
 struct FakeToOwned;
 impl FakeToOwned {
     /// This looks just like `ToOwned::to_owned`
diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr
index 793927bd1cb..a68516376ab 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.stderr
+++ b/src/tools/clippy/tests/ui/assigning_clones.stderr
@@ -62,64 +62,88 @@ LL |     *mut_thing = (ref_thing + ref_thing).clone();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:68:9
+  --> tests/ui/assigning_clones.rs:67:5
+   |
+LL |     s = format!("{} {}", "hello", "world").clone();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `s.clone_from(&format!("{} {}", "hello", "world"))`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:72:5
+   |
+LL |     s = Clone::clone(&format!("{} {}", "hello", "world"));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"))`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:78:9
    |
 LL |         a = b.clone();
    |         ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:133:5
+  --> tests/ui/assigning_clones.rs:149:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:140:5
+  --> tests/ui/assigning_clones.rs:156:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:141:5
+  --> tests/ui/assigning_clones.rs:157:5
    |
 LL |     a = c.to_owned();
    |     ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:171:5
+  --> tests/ui/assigning_clones.rs:187:5
    |
 LL |     *mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:175:5
+  --> tests/ui/assigning_clones.rs:191:5
    |
 LL |     mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:196:5
+  --> tests/ui/assigning_clones.rs:212:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:200:5
+  --> tests/ui/assigning_clones.rs:216:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:204:5
+  --> tests/ui/assigning_clones.rs:220:5
    |
 LL |     *mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:208:5
+  --> tests/ui/assigning_clones.rs:224:5
    |
 LL |     mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`
 
-error: aborting due to 20 previous errors
+error: assigning the result of `ToOwned::to_owned()` may be inefficient
+  --> tests/ui/assigning_clones.rs:229:5
+   |
+LL |     s = format!("{} {}", "hello", "world").to_owned();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `format!("{} {}", "hello", "world").clone_into(&mut s)`
+
+error: assigning the result of `ToOwned::to_owned()` may be inefficient
+  --> tests/ui/assigning_clones.rs:234:5
+   |
+LL |     s = ToOwned::to_owned(&format!("{} {}", "hello", "world"));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s)`
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
new file mode 100644
index 00000000000..9877991f183
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
@@ -0,0 +1,47 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// > blockquote with
+/// > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn first() {}
+
+/// > blockquote with no
+/// > lazy continuation
+fn first_nowarn() {}
+
+/// > blockquote with no
+///
+/// lazy continuation
+fn two_nowarn() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// > > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn two() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// > > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn three() {}
+
+/// >   * > nest here
+/// >     > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four() {}
+
+/// > * > nest here
+/// >   > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four_point_1() {}
+
+/// * > nest here lazy continuation
+fn five() {}
+
+/// 1. > nest here
+///    > lazy continuation (this results in strange indentation, but still works)
+//~^ ERROR: doc quote missing `>` marker
+fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
new file mode 100644
index 00000000000..587b2fdd533
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
@@ -0,0 +1,47 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// > blockquote with
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn first() {}
+
+/// > blockquote with no
+/// > lazy continuation
+fn first_nowarn() {}
+
+/// > blockquote with no
+///
+/// lazy continuation
+fn two_nowarn() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn two() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn three() {}
+
+/// >   * > nest here
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four() {}
+
+/// > * > nest here
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four_point_1() {}
+
+/// * > nest here lazy continuation
+fn five() {}
+
+/// 1. > nest here
+///  lazy continuation (this results in strange indentation, but still works)
+//~^ ERROR: doc quote missing `>` marker
+fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
new file mode 100644
index 00000000000..975184a01c3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
@@ -0,0 +1,76 @@
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:4:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+   = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
+help: add markers to start of line
+   |
+LL | /// > lazy continuation
+   |     +
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:20:5
+   |
+LL | /// > lazy continuation
+   |     ^^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// > > lazy continuation
+   |       +
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:27:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// > > lazy continuation
+   |     +++
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:32:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// >     > lazy continuation
+   |     +++++++
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:37:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// >   > lazy continuation
+   |     +++++
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:45:5
+   |
+LL | ///  lazy continuation (this results in strange indentation, but still works)
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | ///    > lazy continuation (this results in strange indentation, but still works)
+   |        +
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
new file mode 100644
index 00000000000..409e6b0bc22
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
@@ -0,0 +1,77 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// 1. nest here
+///    lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn one() {}
+
+/// 1. first line
+///    lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+///    because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn two() {}
+
+///   - nest here
+///     lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn three() {}
+
+///   - first line
+///     lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+///     because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn four() {}
+
+///   - nest here
+///     lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn five() {}
+
+///   - - first line
+///       this will warn on the lazy continuation
+//~^ ERROR: doc list item missing indentation
+///       and so should this
+//~^ ERROR: doc list item missing indentation
+fn six() {}
+
+///   - - first line
+///
+///     this is not a lazy continuation
+fn seven() {}
+
+#[rustfmt::skip]
+// https://github.com/rust-lang/rust-clippy/pull/12770#issuecomment-2118601768
+/// Returns a list of ProtocolDescriptors from a Serde JSON input.
+///
+/// Defined Protocol Identifiers for the Protocol Descriptor
+/// We intentionally omit deprecated profile identifiers.
+/// From Bluetooth Assigned Numbers:
+/// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+///
+/// # Arguments
+/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
+///     to set up. Example:
+///   'protocol_descriptors': [
+//~^ ERROR: doc list item missing indentation
+///      {
+///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
+///          'params': [
+///              {
+///                 'data': 0x0103  # to indicate 1.3
+///              },
+///              {
+///                  'data': 0x0105  # to indicate 1.5
+///              }
+///          ]
+///      },
+///      {
+///          'protocol': 1,  # u64 Representation of ProtocolIdentifier::SDP
+///          'params': [{
+///              'data': 0x0019
+///          }]
+///      }
+///   ]
+//~^ ERROR: doc list item missing indentation
+fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
new file mode 100644
index 00000000000..30ab448a113
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
@@ -0,0 +1,77 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// 1. nest here
+/// lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn one() {}
+
+/// 1. first line
+/// lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+/// because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn two() {}
+
+///   - nest here
+/// lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn three() {}
+
+///   - first line
+/// lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+/// because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn four() {}
+
+///   - nest here
+/// lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn five() {}
+
+///   - - first line
+/// this will warn on the lazy continuation
+//~^ ERROR: doc list item missing indentation
+///     and so should this
+//~^ ERROR: doc list item missing indentation
+fn six() {}
+
+///   - - first line
+///
+///     this is not a lazy continuation
+fn seven() {}
+
+#[rustfmt::skip]
+// https://github.com/rust-lang/rust-clippy/pull/12770#issuecomment-2118601768
+/// Returns a list of ProtocolDescriptors from a Serde JSON input.
+///
+/// Defined Protocol Identifiers for the Protocol Descriptor
+/// We intentionally omit deprecated profile identifiers.
+/// From Bluetooth Assigned Numbers:
+/// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+///
+/// # Arguments
+/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
+///     to set up. Example:
+///  'protocol_descriptors': [
+//~^ ERROR: doc list item missing indentation
+///      {
+///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
+///          'params': [
+///              {
+///                 'data': 0x0103  # to indicate 1.3
+///              },
+///              {
+///                  'data': 0x0105  # to indicate 1.5
+///              }
+///          ]
+///      },
+///      {
+///          'protocol': 1,  # u64 Representation of ProtocolIdentifier::SDP
+///          'params': [{
+///              'data': 0x0019
+///          }]
+///      }
+///  ]
+//~^ ERROR: doc list item missing indentation
+fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
new file mode 100644
index 00000000000..ddfdc49340c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
@@ -0,0 +1,136 @@
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:4:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+   = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
+help: indent this line
+   |
+LL | ///    lazy continuation
+   |     +++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:9:5
+   |
+LL | /// lazy list continuations don't make warnings with this lint
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///    lazy list continuations don't make warnings with this lint
+   |     +++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:11:5
+   |
+LL | /// because they don't have the
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///    because they don't have the
+   |     +++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:16:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     lazy continuation
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:21:5
+   |
+LL | /// lazy list continuations don't make warnings with this lint
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     lazy list continuations don't make warnings with this lint
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:23:5
+   |
+LL | /// because they don't have the
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     because they don't have the
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:28:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     lazy continuation
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:33:5
+   |
+LL | /// this will warn on the lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///       this will warn on the lazy continuation
+   |     ++++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:35:5
+   |
+LL | ///     and so should this
+   |     ^^^^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///       and so should this
+   |         ++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:56:5
+   |
+LL | ///  'protocol_descriptors': [
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///   'protocol_descriptors': [
+   |      +
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:75:5
+   |
+LL | ///  ]
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///   ]
+   |      +
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs
index d51e7e37beb..97cf4a69682 100644
--- a/src/tools/clippy/tests/ui/duplicated_attributes.rs
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs
@@ -1,5 +1,5 @@
 //@aux-build:proc_macro_attr.rs
-
+#![feature(rustc_attrs)]
 #![warn(clippy::duplicated_attributes)]
 #![cfg(any(unix, windows))]
 #![allow(dead_code)]
@@ -20,6 +20,10 @@ fn foo() {}
 #[cfg(unix)] // cfgs are not handled
 fn bar() {}
 
+// No warning:
+#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))]
+trait Abc {}
+
 #[proc_macro_attr::duplicated_attr()] // Should not warn!
 fn babar() {}
 
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed
index 8c253bfd99a..f9ce1defda1 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed
@@ -1,3 +1,4 @@
+#![feature(const_int_from_str)]
 #![warn(clippy::from_str_radix_10)]
 
 mod some_mod {
@@ -59,3 +60,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 
     Ok(())
 }
+
+fn issue_12732() {
+    const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
+    const B: () = {
+        let _ = u32::from_str_radix("123", 10);
+    };
+    const fn foo() {
+        let _ = u32::from_str_radix("123", 10);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs
index e9d02215710..2d5b351f8da 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.rs
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs
@@ -1,3 +1,4 @@
+#![feature(const_int_from_str)]
 #![warn(clippy::from_str_radix_10)]
 
 mod some_mod {
@@ -59,3 +60,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 
     Ok(())
 }
+
+fn issue_12732() {
+    const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
+    const B: () = {
+        let _ = u32::from_str_radix("123", 10);
+    };
+    const fn foo() {
+        let _ = u32::from_str_radix("123", 10);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
index 4aa84eca261..01a1bf8940a 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
@@ -1,5 +1,5 @@
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:28:5
+  --> tests/ui/from_str_radix_10.rs:29:5
    |
 LL |     u32::from_str_radix("30", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()`
@@ -8,43 +8,43 @@ LL |     u32::from_str_radix("30", 10)?;
    = help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:31:5
+  --> tests/ui/from_str_radix_10.rs:32:5
    |
 LL |     i64::from_str_radix("24", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::<i64>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:33:5
+  --> tests/ui/from_str_radix_10.rs:34:5
    |
 LL |     isize::from_str_radix("100", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::<isize>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:35:5
+  --> tests/ui/from_str_radix_10.rs:36:5
    |
 LL |     u8::from_str_radix("7", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::<u8>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:37:5
+  --> tests/ui/from_str_radix_10.rs:38:5
    |
 LL |     u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::<u16>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:39:5
+  --> tests/ui/from_str_radix_10.rs:40:5
    |
 LL |     i128::from_str_radix(Test + Test, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::<i128>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:43:5
+  --> tests/ui/from_str_radix_10.rs:44:5
    |
 LL |     i32::from_str_radix(string, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::<i32>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:47:5
+  --> tests/ui/from_str_radix_10.rs:48:5
    |
 LL |     i32::from_str_radix(&stringier, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()`
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
index c03d91c797c..72b39c982bf 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
@@ -11,7 +11,6 @@ fn main() {
 
     let _ = vec![1, 2, 3].into_iter();
     let _ = (&vec![1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter()
-    let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::rc::Rc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::sync::Arc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter()
 
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
index 93c732fd6cc..5ba224720d3 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
@@ -11,7 +11,6 @@ fn main() {
 
     let _ = vec![1, 2, 3].into_iter();
     let _ = (&vec![1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter()
-    let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter()
 
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
index 0e9d485f1a9..64d814074da 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
@@ -8,160 +8,154 @@ LL |     let _ = (&vec![1, 2, 3]).into_iter();
    = help: to override `-D warnings` add `#[allow(clippy::into_iter_on_ref)]`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
-  --> tests/ui/into_iter_on_ref.rs:14:46
-   |
-LL |     let _ = vec![1, 2, 3].into_boxed_slice().into_iter();
-   |                                              ^^^^^^^^^ help: call directly: `iter`
-
-error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
-  --> tests/ui/into_iter_on_ref.rs:15:41
+  --> tests/ui/into_iter_on_ref.rs:14:41
    |
 LL |     let _ = std::rc::Rc::from(&[X][..]).into_iter();
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
-  --> tests/ui/into_iter_on_ref.rs:16:44
+  --> tests/ui/into_iter_on_ref.rs:15:44
    |
 LL |     let _ = std::sync::Arc::from(&[X][..]).into_iter();
    |                                            ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:18:32
+  --> tests/ui/into_iter_on_ref.rs:17:32
    |
 LL |     let _ = (&&&&&&&[1, 2, 3]).into_iter();
    |                                ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:19:36
+  --> tests/ui/into_iter_on_ref.rs:18:36
    |
 LL |     let _ = (&&&&mut &&&[1, 2, 3]).into_iter();
    |                                    ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:20:40
+  --> tests/ui/into_iter_on_ref.rs:19:40
    |
 LL |     let _ = (&mut &mut &mut [1, 2, 3]).into_iter();
    |                                        ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option`
-  --> tests/ui/into_iter_on_ref.rs:22:24
+  --> tests/ui/into_iter_on_ref.rs:21:24
    |
 LL |     let _ = (&Some(4)).into_iter();
    |                        ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option`
-  --> tests/ui/into_iter_on_ref.rs:23:28
+  --> tests/ui/into_iter_on_ref.rs:22:28
    |
 LL |     let _ = (&mut Some(5)).into_iter();
    |                            ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result`
-  --> tests/ui/into_iter_on_ref.rs:24:32
+  --> tests/ui/into_iter_on_ref.rs:23:32
    |
 LL |     let _ = (&Ok::<_, i32>(6)).into_iter();
    |                                ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result`
-  --> tests/ui/into_iter_on_ref.rs:25:37
+  --> tests/ui/into_iter_on_ref.rs:24:37
    |
 LL |     let _ = (&mut Err::<i32, _>(7)).into_iter();
    |                                     ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec`
-  --> tests/ui/into_iter_on_ref.rs:26:34
+  --> tests/ui/into_iter_on_ref.rs:25:34
    |
 LL |     let _ = (&Vec::<i32>::new()).into_iter();
    |                                  ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec`
-  --> tests/ui/into_iter_on_ref.rs:27:38
+  --> tests/ui/into_iter_on_ref.rs:26:38
    |
 LL |     let _ = (&mut Vec::<i32>::new()).into_iter();
    |                                      ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap`
-  --> tests/ui/into_iter_on_ref.rs:28:44
+  --> tests/ui/into_iter_on_ref.rs:27:44
    |
 LL |     let _ = (&BTreeMap::<i32, u64>::new()).into_iter();
    |                                            ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap`
-  --> tests/ui/into_iter_on_ref.rs:29:48
+  --> tests/ui/into_iter_on_ref.rs:28:48
    |
 LL |     let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter();
    |                                                ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque`
-  --> tests/ui/into_iter_on_ref.rs:30:39
+  --> tests/ui/into_iter_on_ref.rs:29:39
    |
 LL |     let _ = (&VecDeque::<i32>::new()).into_iter();
    |                                       ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque`
-  --> tests/ui/into_iter_on_ref.rs:31:43
+  --> tests/ui/into_iter_on_ref.rs:30:43
    |
 LL |     let _ = (&mut VecDeque::<i32>::new()).into_iter();
    |                                           ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList`
-  --> tests/ui/into_iter_on_ref.rs:32:41
+  --> tests/ui/into_iter_on_ref.rs:31:41
    |
 LL |     let _ = (&LinkedList::<i32>::new()).into_iter();
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList`
-  --> tests/ui/into_iter_on_ref.rs:33:45
+  --> tests/ui/into_iter_on_ref.rs:32:45
    |
 LL |     let _ = (&mut LinkedList::<i32>::new()).into_iter();
    |                                             ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap`
-  --> tests/ui/into_iter_on_ref.rs:34:43
+  --> tests/ui/into_iter_on_ref.rs:33:43
    |
 LL |     let _ = (&HashMap::<i32, u64>::new()).into_iter();
    |                                           ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap`
-  --> tests/ui/into_iter_on_ref.rs:35:47
+  --> tests/ui/into_iter_on_ref.rs:34:47
    |
 LL |     let _ = (&mut HashMap::<i32, u64>::new()).into_iter();
    |                                               ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet`
-  --> tests/ui/into_iter_on_ref.rs:37:39
+  --> tests/ui/into_iter_on_ref.rs:36:39
    |
 LL |     let _ = (&BTreeSet::<i32>::new()).into_iter();
    |                                       ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap`
-  --> tests/ui/into_iter_on_ref.rs:38:41
+  --> tests/ui/into_iter_on_ref.rs:37:41
    |
 LL |     let _ = (&BinaryHeap::<i32>::new()).into_iter();
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet`
-  --> tests/ui/into_iter_on_ref.rs:39:38
+  --> tests/ui/into_iter_on_ref.rs:38:38
    |
 LL |     let _ = (&HashSet::<i32>::new()).into_iter();
    |                                      ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path`
-  --> tests/ui/into_iter_on_ref.rs:40:43
+  --> tests/ui/into_iter_on_ref.rs:39:43
    |
 LL |     let _ = std::path::Path::new("12/34").into_iter();
    |                                           ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf`
-  --> tests/ui/into_iter_on_ref.rs:41:47
+  --> tests/ui/into_iter_on_ref.rs:40:47
    |
 LL |     let _ = std::path::PathBuf::from("12/34").into_iter();
    |                                               ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:43:26
+  --> tests/ui/into_iter_on_ref.rs:42:26
    |
 LL |     let _ = (&[1, 2, 3]).into_iter().next();
    |                          ^^^^^^^^^ help: call directly: `iter`
 
-error: aborting due to 27 previous errors
+error: aborting due to 26 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr
index a926570b60a..3c0382767c3 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms.stderr
@@ -2,7 +2,7 @@ error: this match arm has an identical body to the `_` wildcard arm
   --> tests/ui/match_same_arms.rs:12:9
    |
 LL |         Abc::A => 0,
-   |         ^^^^^^^^^^^ help: try removing the arm
+   |         ^^^^^^^^^^^^^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
@@ -17,106 +17,114 @@ error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:18:9
    |
 LL |         (1, .., 3) => 42,
-   |         ----------^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(1, .., 3) | (.., 3)`
+   |         ^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:19:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (1, .., 3) | (.., 3) => 42,
+   |         ~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (.., 3) => 42,
    |
-LL |         (.., 3) => 42,
-   |         ^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:25:9
    |
 LL |         51 => 1,
-   |         --^^^^^
-   |         |
-   |         help: try merging the arm patterns: `51 | 42`
+   |         ^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:24:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         51 | 42 => 1,
+   |         ~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         42 => 1,
    |
-LL |         42 => 1,
-   |         ^^^^^^^
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:26:9
    |
 LL |         41 => 2,
-   |         --^^^^^
-   |         |
-   |         help: try merging the arm patterns: `41 | 52`
+   |         ^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:27:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         41 | 52 => 2,
+   |         ~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         52 => 2,
    |
-LL |         52 => 2,
-   |         ^^^^^^^
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:33:9
    |
 LL |         2 => 2,
-   |         -^^^^^
-   |         |
-   |         help: try merging the arm patterns: `2 | 1`
+   |         ^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:32:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         2 | 1 => 2,
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         1 => 2,
    |
-LL |         1 => 2,
-   |         ^^^^^^
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:35:9
    |
 LL |         3 => 2,
-   |         -^^^^^
-   |         |
-   |         help: try merging the arm patterns: `3 | 1`
+   |         ^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:32:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         3 | 1 => 2,
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         1 => 2,
    |
-LL |         1 => 2,
-   |         ^^^^^^
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:33:9
    |
 LL |         2 => 2,
-   |         -^^^^^
-   |         |
-   |         help: try merging the arm patterns: `2 | 3`
+   |         ^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:35:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         2 | 3 => 2,
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         3 => 2,
+LL +
    |
-LL |         3 => 2,
-   |         ^^^^^^
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:52:17
    |
 LL |                 CommandInfo::External { name, .. } => name.to_string(),
-   |                 ----------------------------------^^^^^^^^^^^^^^^^^^^^
-   |                 |
-   |                 help: try merging the arm patterns: `CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. }`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:51:17
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |                 CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
    |
-LL |                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed
new file mode 100644
index 00000000000..fba0cf33b3c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed
@@ -0,0 +1,241 @@
+#![warn(clippy::match_same_arms)]
+#![allow(
+    clippy::disallowed_names,
+    clippy::diverging_sub_expression,
+    clippy::uninlined_format_args,
+    clippy::match_single_binding,
+    clippy::match_like_matches_macro
+)]
+fn bar<T>(_: T) {}
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn match_same_arms() {
+    let _ = match 42 {
+        _ => {
+            foo();
+            let mut a = 42 + [23].len() as i32;
+            if true {
+                a += 7;
+            }
+            a = -31 - a;
+            a
+        },
+    };
+    //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm
+
+    let _ = match 42 {
+        51 | 42 => foo(), //~ ERROR: this match arm has an identical body to another arm
+        _ => true,
+    };
+
+    let _ = match Some(42) {
+        None | Some(_) => 24, //~ ERROR: this match arm has an identical body to another arm
+    };
+
+    let _ = match Some(42) {
+        Some(foo) => 24,
+        None => 24,
+    };
+
+    let _ = match Some(42) {
+        Some(42) => 24,
+        Some(a) => 24, // bindings are different
+        None => 0,
+    };
+
+    let _ = match Some(42) {
+        Some(a) if a > 0 => 24,
+        Some(a) => 24, // one arm has a guard
+        None => 0,
+    };
+
+    match (Some(42), Some(42)) {
+        (None, Some(a)) | (Some(a), None) => bar(a), //~ ERROR: this match arm has an identical body to another arm
+        _ => (),
+    }
+
+    // No warning because guards are different
+    let _ = match Some(42) {
+        Some(a) if a == 42 => a,
+        Some(a) if a == 24 => a,
+        Some(_) => 24,
+        None => 0,
+    };
+
+    let _ = match (Some(42), Some(42)) {
+        (None, Some(a)) | (Some(a), None) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm
+        _ => 0,
+    };
+
+    match (Some(42), Some(42)) {
+        (Some(a), ..) | (.., Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm
+        _ => (),
+    }
+
+    let _ = match Some(()) {
+        Some(()) => 0.0,
+        None => -0.0,
+    };
+
+    match (Some(42), Some("")) {
+        (Some(a), None) => bar(a),
+        (None, Some(a)) => bar(a), // bindings have different types
+        _ => (),
+    }
+
+    let x: Result<i32, &str> = Ok(3);
+
+    // No warning because of the guard.
+    match x {
+        Ok(x) if x * x == 64 => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    // This used to be a false positive; see issue #1996.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(x) if x * x == 64 => println!("ok 64"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    match (x, Some(1i32)) {
+        (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm
+        _ => println!("err"),
+    }
+
+    // No warning; different types for `x`.
+    match (x, Some(1.0f64)) {
+        (Ok(x), Some(_)) => println!("ok {}", x),
+        (Ok(_), Some(x)) => println!("ok {}", x),
+        _ => println!("err"),
+    }
+
+    // False negative #2251.
+    match x {
+        Ok(_tmp) => println!("ok"),
+        Ok(_) | Ok(3) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm
+        Err(_) => {
+            unreachable!();
+        },
+    }
+
+    // False positive #1390
+    macro_rules! empty {
+        ($e:expr) => {};
+    }
+    match 0 {
+        0 => {
+            empty!(0);
+        },
+        1 => {
+            empty!(1);
+        },
+        x => {
+            empty!(x);
+        },
+    };
+
+    // still lint if the tokens are the same
+    match 0 {
+        1 | 0 => {
+            empty!(0);
+        },
+        x => {
+            empty!(x);
+        },
+    }
+    //~^^^^^^^ ERROR: this match arm has an identical body to another arm
+
+    match_expr_like_matches_macro_priority();
+}
+
+fn match_expr_like_matches_macro_priority() {
+    enum E {
+        A,
+        B,
+        C,
+    }
+    let x = E::A;
+    let _ans = match x {
+        E::A => false,
+        E::B => false,
+        _ => true,
+    };
+}
+
+fn main() {
+    let _ = match Some(0) {
+        Some(0) => 0,
+        Some(1) => 1,
+        #[cfg(feature = "foo")]
+        Some(2) => 2,
+        _ => 1,
+    };
+
+    enum Foo {
+        X(u32),
+        Y(u32),
+        Z(u32),
+    }
+
+    // Don't lint. `Foo::X(0)` and `Foo::Z(_)` overlap with the arm in between.
+    let _ = match Foo::X(0) {
+        Foo::X(0) => 1,
+        Foo::X(_) | Foo::Y(_) | Foo::Z(0) => 2,
+        Foo::Z(_) => 1,
+        _ => 0,
+    };
+
+    // Suggest moving `Foo::Z(_)` up.
+    let _ = match Foo::X(0) {
+        Foo::X(0) | Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm
+        Foo::X(_) | Foo::Y(_) => 2,
+        _ => 0,
+    };
+
+    // Suggest moving `Foo::X(0)` down.
+    let _ = match Foo::X(0) {
+        Foo::Y(_) | Foo::Z(0) => 2,
+        Foo::Z(_) | Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm
+        _ => 0,
+    };
+
+    // Don't lint.
+    let _ = match 0 {
+        -2 => 1,
+        -5..=50 => 2,
+        -150..=88 => 1,
+        _ => 3,
+    };
+
+    struct Bar {
+        x: u32,
+        y: u32,
+        z: u32,
+    }
+
+    // Lint.
+    let _ = match None {
+        Some(Bar { y: 10, z: 0, .. }) => 2,
+        None => 50,
+        Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm
+        _ => 200,
+    };
+
+    let _ = match 0 {
+        0 => todo!(),
+        1 => todo!(),
+        2 => core::convert::identity::<u32>(todo!()),
+        3 => core::convert::identity::<u32>(todo!()),
+        _ => 5,
+    };
+
+    let _ = match 0 {
+        1 | 0 => cfg!(not_enable),
+        _ => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
index 85ad0962eb4..8a4e3b325bb 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -2,9 +2,10 @@
 #![allow(
     clippy::disallowed_names,
     clippy::diverging_sub_expression,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::match_single_binding,
+    clippy::match_like_matches_macro
 )]
-//@no-rustfix
 fn bar<T>(_: T) {}
 fn foo() -> bool {
     unimplemented!()
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
index f4c38c1af89..3d15176ccf9 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -1,18 +1,18 @@
 error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms2.rs:15:9
+  --> tests/ui/match_same_arms2.rs:16:9
    |
 LL | /         42 => {
 LL | |             foo();
 LL | |             let mut a = 42 + [23].len() as i32;
 LL | |             if true {
 ...  |
-LL | |             a
 LL | |         },
-   | |_________^ help: try removing the arm
+LL | |         _ => {
+   | |________^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
-  --> tests/ui/match_same_arms2.rs:24:9
+  --> tests/ui/match_same_arms2.rs:25:9
    |
 LL | /         _ => {
 LL | |             foo();
@@ -26,203 +26,200 @@ LL | |         },
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:38:9
+  --> tests/ui/match_same_arms2.rs:39:9
    |
 LL |         51 => foo(),
-   |         --^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `51 | 42`
+   |         ^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:37:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         51 | 42 => foo(),
+   |         ~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         42 => foo(),
    |
-LL |         42 => foo(),
-   |         ^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:44:9
+  --> tests/ui/match_same_arms2.rs:45:9
    |
 LL |         None => 24,
-   |         ----^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `None | Some(_)`
+   |         ^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:43:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         None | Some(_) => 24,
+   |         ~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Some(_) => 24,
    |
-LL |         Some(_) => 24,
-   |         ^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:66:9
+  --> tests/ui/match_same_arms2.rs:67:9
    |
 LL |         (None, Some(a)) => bar(a),
-   |         ---------------^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:65:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (None, Some(a)) | (Some(a), None) => bar(a),
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (Some(a), None) => bar(a),
    |
-LL |         (Some(a), None) => bar(a),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:80:9
+  --> tests/ui/match_same_arms2.rs:81:9
    |
 LL |         (None, Some(a)) if a == 42 => a,
-   |         ---------------^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:79:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (None, Some(a)) | (Some(a), None) if a == 42 => a,
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (Some(a), None) if a == 42 => a,
    |
-LL |         (Some(a), None) if a == 42 => a,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:85:9
+  --> tests/ui/match_same_arms2.rs:86:9
    |
 LL |         (Some(a), ..) => bar(a),
-   |         -------------^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(Some(a), ..) | (.., Some(a))`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:86:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (Some(a), ..) | (.., Some(a)) => bar(a),
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (.., Some(a)) => bar(a),
    |
-LL |         (.., Some(a)) => bar(a),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:119:9
+  --> tests/ui/match_same_arms2.rs:120:9
    |
 LL |         (Ok(x), Some(_)) => println!("ok {}", x),
-   |         ----------------^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(Ok(x), Some(_)) | (Ok(_), Some(x))`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:120:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x),
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (Ok(_), Some(x)) => println!("ok {}", x),
    |
-LL |         (Ok(_), Some(x)) => println!("ok {}", x),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:135:9
+  --> tests/ui/match_same_arms2.rs:136:9
    |
 LL |         Ok(_) => println!("ok"),
-   |         -----^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Ok(_) | Ok(3)`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:134:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Ok(_) | Ok(3) => println!("ok"),
+   |         ~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Ok(3) => println!("ok"),
    |
-LL |         Ok(3) => println!("ok"),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:162:9
+  --> tests/ui/match_same_arms2.rs:163:9
    |
-LL |           1 => {
-   |           ^ help: try merging the arm patterns: `1 | 0`
-   |  _________|
-   | |
+LL | /         1 => {
 LL | |             empty!(0);
 LL | |         },
    | |_________^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:159:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         1 | 0 => {
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         0 => {
+LL -             empty!(0);
+LL -         },
    |
-LL | /         0 => {
-LL | |             empty!(0);
-LL | |         },
-   | |_________^
-
-error: match expression looks like `matches!` macro
-  --> tests/ui/match_same_arms2.rs:181:16
-   |
-LL |       let _ans = match x {
-   |  ________________^
-LL | |         E::A => false,
-LL | |         E::B => false,
-LL | |         _ => true,
-LL | |     };
-   | |_____^ help: try: `!matches!(x, E::A | E::B)`
-   |
-   = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]`
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:213:9
+  --> tests/ui/match_same_arms2.rs:214:9
    |
 LL |         Foo::X(0) => 1,
-   |         ---------^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Foo::X(0) | Foo::Z(_)`
+   |         ^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:215:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Foo::X(0) | Foo::Z(_) => 1,
+   |         ~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Foo::Z(_) => 1,
    |
-LL |         Foo::Z(_) => 1,
-   |         ^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:223:9
+  --> tests/ui/match_same_arms2.rs:224:9
    |
 LL |         Foo::Z(_) => 1,
-   |         ---------^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Foo::Z(_) | Foo::X(0)`
+   |         ^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:221:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Foo::Z(_) | Foo::X(0) => 1,
+   |         ~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Foo::X(0) => 1,
    |
-LL |         Foo::X(0) => 1,
-   |         ^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:246:9
+  --> tests/ui/match_same_arms2.rs:247:9
    |
 LL |         Some(Bar { y: 0, x: 5, .. }) => 1,
-   |         ----------------------------^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. })`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:243:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1,
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Some(Bar { x: 0, y: 5, .. }) => 1,
    |
-LL |         Some(Bar { x: 0, y: 5, .. }) => 1,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:260:9
+  --> tests/ui/match_same_arms2.rs:261:9
    |
 LL |         1 => cfg!(not_enable),
-   |         -^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `1 | 0`
+   |         ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:259:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         1 | 0 => cfg!(not_enable),
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         0 => cfg!(not_enable),
    |
-LL |         0 => cfg!(not_enable),
-   |         ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
new file mode 100644
index 00000000000..804c0a869a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
@@ -0,0 +1,61 @@
+#![feature(non_exhaustive_omitted_patterns_lint)]
+#![warn(clippy::match_same_arms)]
+#![no_main]
+use std::sync::atomic::Ordering; // #[non_exhaustive] enum
+
+fn repeat() -> ! {
+    panic!()
+}
+
+pub fn f(x: Ordering) {
+    #[deny(non_exhaustive_omitted_patterns)]
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        Ordering::AcqRel | Ordering::SeqCst => repeat(),
+        _ => repeat(),
+    }
+}
+
+mod f {
+    #![deny(non_exhaustive_omitted_patterns)]
+
+    use super::*;
+
+    pub fn f(x: Ordering) {
+        match x {
+            Ordering::Relaxed => println!("relaxed"),
+            Ordering::Release => println!("release"),
+            Ordering::Acquire => println!("acquire"),
+            Ordering::AcqRel | Ordering::SeqCst => repeat(),
+            _ => repeat(),
+        }
+    }
+}
+
+// Below should still lint
+
+pub fn g(x: Ordering) {
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        //~^ ERROR: this match arm has an identical body to the `_` wildcard arm
+        _ => repeat(),
+    }
+}
+
+mod g {
+    use super::*;
+
+    pub fn g(x: Ordering) {
+        match x {
+            Ordering::Relaxed => println!("relaxed"),
+            Ordering::Release => println!("release"),
+            Ordering::Acquire => println!("acquire"),
+            //~^ ERROR: this match arm has an identical body to the `_` wildcard arm
+            _ => repeat(),
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
index 5c277f925a8..e50663932a1 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
@@ -1,7 +1,6 @@
 #![feature(non_exhaustive_omitted_patterns_lint)]
 #![warn(clippy::match_same_arms)]
 #![no_main]
-//@no-rustfix
 use std::sync::atomic::Ordering; // #[non_exhaustive] enum
 
 fn repeat() -> ! {
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
index cf2a75354e1..aa7f8c95dce 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
@@ -1,12 +1,13 @@
 error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:45:9
+  --> tests/ui/match_same_arms_non_exhaustive.rs:44:9
    |
-LL |         Ordering::AcqRel | Ordering::SeqCst => repeat(),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm
+LL | /         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+LL | |
+   | |________^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:47:9
+  --> tests/ui/match_same_arms_non_exhaustive.rs:46:9
    |
 LL |         _ => repeat(),
    |         ^^^^^^^^^^^^^
@@ -14,14 +15,15 @@ LL |         _ => repeat(),
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
 
 error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:59:13
+  --> tests/ui/match_same_arms_non_exhaustive.rs:58:13
    |
-LL |             Ordering::AcqRel | Ordering::SeqCst => repeat(),
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm
+LL | /             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+LL | |
+   | |____________^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:61:13
+  --> tests/ui/match_same_arms_non_exhaustive.rs:60:13
    |
 LL |             _ => repeat(),
    |             ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index d026e009684..2750e0cdf3f 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -161,7 +161,23 @@ union U {
     f: u32,
 }
 
-// Do not lint because accessing union fields from const functions is unstable
+// Do not lint because accessing union fields from const functions is unstable in 1.55
+#[clippy::msrv = "1.55"]
 fn h(u: U) -> u32 {
     unsafe { u.f }
 }
+
+mod msrv {
+    struct Foo(*const u8, *mut u8);
+
+    impl Foo {
+        #[clippy::msrv = "1.57"]
+        fn deref_ptr_cannot_be_const(self) -> usize {
+            unsafe { *self.0 as usize }
+        }
+        #[clippy::msrv = "1.58"]
+        fn deref_mut_ptr_cannot_be_const(self) -> usize {
+            unsafe { *self.1 as usize }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 12a8320c8f3..06dbbeb31c0 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -113,3 +113,31 @@ impl const Drop for D {
 // Lint this, since it can be dropped in const contexts
 // FIXME(effects)
 fn d(this: D) {}
+
+mod msrv {
+    struct Foo(*const u8, &'static u8);
+
+    impl Foo {
+        #[clippy::msrv = "1.58"]
+        fn deref_ptr_can_be_const(self) -> usize {
+            //~^ ERROR: this could be a `const fn`
+            unsafe { *self.0 as usize }
+        }
+
+        fn deref_copied_val(self) -> usize {
+            //~^ ERROR: this could be a `const fn`
+            *self.1 as usize
+        }
+    }
+
+    union Bar {
+        val: u8,
+    }
+
+    #[clippy::msrv = "1.56"]
+    fn union_access_can_be_const() {
+        //~^ ERROR: this could be a `const fn`
+        let bar = Bar { val: 1 };
+        let _ = unsafe { bar.val };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 082459fd821..b2cade30563 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -102,5 +102,33 @@ LL | |     46
 LL | | }
    | |_^
 
-error: aborting due to 11 previous errors
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9
+   |
+LL | /         fn deref_ptr_can_be_const(self) -> usize {
+LL | |
+LL | |             unsafe { *self.0 as usize }
+LL | |         }
+   | |_________^
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9
+   |
+LL | /         fn deref_copied_val(self) -> usize {
+LL | |
+LL | |             *self.1 as usize
+LL | |         }
+   | |_________^
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5
+   |
+LL | /     fn union_access_can_be_const() {
+LL | |
+LL | |         let bar = Bar { val: 1 };
+LL | |         let _ = unsafe { bar.val };
+LL | |     }
+   | |_____^
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs
index 0e1533fc1ab..b0fa8e98859 100644
--- a/src/tools/clippy/tests/ui/missing_panics_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs
@@ -191,3 +191,11 @@ fn from_declared_macro_should_lint_at_macrosite() {
     // Not here.
     some_macro_that_panics!()
 }
+
+pub fn issue_12760<const N: usize>() {
+    const {
+        if N == 0 {
+            panic!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
index bd7a9a0b984..5478372cbe0 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
@@ -141,8 +141,8 @@ fn main() {
         let f = |arg| {
             let loc = "loc".to_owned();
             let _ = std::fs::write("x", &env); // Don't lint. In environment
-            let _ = std::fs::write("x", arg);
-            let _ = std::fs::write("x", loc);
+            let _ = std::fs::write("x", &arg);
+            let _ = std::fs::write("x", &loc);
         };
         let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f`
         f(arg);
@@ -158,13 +158,13 @@ fn main() {
         fn f(_: impl Debug) {}
 
         let x = X;
-        f(&x); // Don't lint. Has significant drop
+        f(&x); // Don't lint, not copy, passed by a reference to a variable
     }
     {
         fn f(_: impl AsRef<str>) {}
 
         let x = String::new();
-        f(x);
+        f(&x);
     }
     {
         fn f(_: impl AsRef<str>) {}
@@ -299,4 +299,38 @@ fn main() {
             check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop
         }
     }
+    {
+        #[derive(Debug)]
+        struct X(Vec<u8>);
+
+        fn f(_: impl Debug) {}
+
+        let x = X(vec![]);
+        f(&x); // Don't lint, makes x unavailable later
+    }
+    {
+        #[derive(Debug)]
+        struct X;
+
+        impl Drop for X {
+            fn drop(&mut self) {}
+        }
+
+        fn f(_: impl Debug) {}
+
+        #[derive(Debug)]
+        struct Y(X);
+
+        let y = Y(X);
+        f(&y); // Don't lint. Not copy, passed by a reference to value
+    }
+    {
+        fn f(_: impl AsRef<str>) {}
+        let x = String::new();
+        f(&x); // Don't lint, not a copy, makes it unavailable later
+        f(String::new()); // Lint, makes no difference
+        let y = "".to_owned();
+        f(&y); // Don't lint
+        f("".to_owned()); // Lint
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
index 5cfd4ce30cc..2643815d939 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
@@ -158,7 +158,7 @@ fn main() {
         fn f(_: impl Debug) {}
 
         let x = X;
-        f(&x); // Don't lint. Has significant drop
+        f(&x); // Don't lint, not copy, passed by a reference to a variable
     }
     {
         fn f(_: impl AsRef<str>) {}
@@ -299,4 +299,38 @@ fn main() {
             check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop
         }
     }
+    {
+        #[derive(Debug)]
+        struct X(Vec<u8>);
+
+        fn f(_: impl Debug) {}
+
+        let x = X(vec![]);
+        f(&x); // Don't lint, makes x unavailable later
+    }
+    {
+        #[derive(Debug)]
+        struct X;
+
+        impl Drop for X {
+            fn drop(&mut self) {}
+        }
+
+        fn f(_: impl Debug) {}
+
+        #[derive(Debug)]
+        struct Y(X);
+
+        let y = Y(X);
+        f(&y); // Don't lint. Not copy, passed by a reference to value
+    }
+    {
+        fn f(_: impl AsRef<str>) {}
+        let x = String::new();
+        f(&x); // Don't lint, not a copy, makes it unavailable later
+        f(&String::new()); // Lint, makes no difference
+        let y = "".to_owned();
+        f(&y); // Don't lint
+        f(&"".to_owned()); // Lint
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr
index 83c076f8d86..fba0755d14b 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr
@@ -50,28 +50,22 @@ LL |         let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap();
    |                                         ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
 
 error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:144:41
-   |
-LL |             let _ = std::fs::write("x", &arg);
-   |                                         ^^^^ help: change this to: `arg`
-
-error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:145:41
+  --> tests/ui/needless_borrows_for_generic_args.rs:247:13
    |
-LL |             let _ = std::fs::write("x", &loc);
-   |                                         ^^^^ help: change this to: `loc`
+LL |         foo(&a);
+   |             ^^ help: change this to: `a`
 
 error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:167:11
+  --> tests/ui/needless_borrows_for_generic_args.rs:331:11
    |
-LL |         f(&x);
-   |           ^^ help: change this to: `x`
+LL |         f(&String::new()); // Lint, makes no difference
+   |           ^^^^^^^^^^^^^^ help: change this to: `String::new()`
 
 error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:247:13
+  --> tests/ui/needless_borrows_for_generic_args.rs:334:11
    |
-LL |         foo(&a);
-   |             ^^ help: change this to: `a`
+LL |         f(&"".to_owned()); // Lint
+   |           ^^^^^^^^^^^^^^ help: change this to: `"".to_owned()`
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
index 1695784030d..ce64861fa40 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.stderr
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -8,10 +8,11 @@ LL |     a = "zero";
    |
    = note: `-D clippy::needless-late-init` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_late_init)]`
-help: declare `a` here
+help: move the declaration `a` here
+   |
+LL ~     
+LL ~     let a = "zero";
    |
-LL |     let a = "zero";
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:30:5
@@ -22,10 +23,12 @@ LL |     let c;
 LL |     b = 1;
    |     ^^^^^ initialised here
    |
-help: declare `b` here
+help: move the declaration `b` here
+   |
+LL ~     
+LL |     let c;
+LL ~     let b = 1;
    |
-LL |     let b = 1;
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:31:5
@@ -36,10 +39,12 @@ LL |     b = 1;
 LL |     c = 2;
    |     ^^^^^ initialised here
    |
-help: declare `c` here
+help: move the declaration `c` here
+   |
+LL ~     
+LL |     b = 1;
+LL ~     let c = 2;
    |
-LL |     let c = 2;
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:35:5
@@ -49,10 +54,11 @@ LL |     let d: usize;
 LL |     d = 1;
    |     ^^^^^ initialised here
    |
-help: declare `d` here
+help: move the declaration `d` here
+   |
+LL ~     
+LL ~     let d: usize = 1;
    |
-LL |     let d: usize = 1;
-   |     ~~~~~~~~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:38:5
@@ -62,10 +68,11 @@ LL |     let e;
 LL |     e = format!("{}", d);
    |     ^^^^^^^^^^^^^^^^^^^^ initialised here
    |
-help: declare `e` here
+help: move the declaration `e` here
+   |
+LL ~     
+LL ~     let e = format!("{}", d);
    |
-LL |     let e = format!("{}", d);
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:43:5
@@ -73,20 +80,17 @@ error: unneeded late initialization
 LL |     let a;
    |     ^^^^^^
    |
-help: declare `a` here
-   |
-LL |     let a = match n {
-   |     +++++++
-help: remove the assignments from the `match` arms
+help: move the declaration `a` here and remove the assignments from the `match` arms
    |
+LL ~     
+LL |     let n = 1;
+LL ~     let a = match n {
 LL ~         1 => "one",
 LL |         _ => {
 LL ~             "two"
+LL |         },
+LL ~     };
    |
-help: add a semicolon after the `match` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:52:5
@@ -94,20 +98,15 @@ error: unneeded late initialization
 LL |     let b;
    |     ^^^^^^
    |
-help: declare `b` here
-   |
-LL |     let b = if n == 3 {
-   |     +++++++
-help: remove the assignments from the branches
+help: move the declaration `b` here and remove the assignments from the branches
    |
+LL ~     
+LL ~     let b = if n == 3 {
 LL ~         "four"
 LL |     } else {
 LL ~         "five"
+LL ~     };
    |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:59:5
@@ -115,20 +114,16 @@ error: unneeded late initialization
 LL |     let d;
    |     ^^^^^^
    |
-help: declare `d` here
-   |
-LL |     let d = if true {
-   |     +++++++
-help: remove the assignments from the branches
+help: move the declaration `d` here and remove the assignments from the branches
    |
+LL ~     
+LL ~     let d = if true {
+LL |         let temp = 5;
 LL ~         temp
 LL |     } else {
 LL ~         15
+LL ~     };
    |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:67:5
@@ -136,20 +131,15 @@ error: unneeded late initialization
 LL |     let e;
    |     ^^^^^^
    |
-help: declare `e` here
-   |
-LL |     let e = if true {
-   |     +++++++
-help: remove the assignments from the branches
+help: move the declaration `e` here and remove the assignments from the branches
    |
+LL ~     
+LL ~     let e = if true {
 LL ~         format!("{} {}", a, b)
 LL |     } else {
 LL ~         format!("{}", n)
+LL ~     };
    |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:74:5
@@ -157,14 +147,11 @@ error: unneeded late initialization
 LL |     let f;
    |     ^^^^^^
    |
-help: declare `f` here
-   |
-LL |     let f = match 1 {
-   |     +++++++
-help: remove the assignments from the `match` arms
+help: move the declaration `f` here and remove the assignments from the `match` arms
    |
-LL -         1 => f = "three",
-LL +         1 => "three",
+LL ~     
+LL ~     let f = match 1 {
+LL ~         1 => "three",
    |
 
 error: unneeded late initialization
@@ -173,19 +160,15 @@ error: unneeded late initialization
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
    |
-help: declare `g` here
-   |
-LL |     let g: usize = if true {
-   |     ++++++++++++++
-help: remove the assignments from the branches
-   |
-LL -         g = 5;
-LL +         5
+help: move the declaration `g` here and remove the assignments from the branches
    |
-help: add a semicolon after the `if` expression
+LL ~     
+LL ~     let g: usize = if true {
+LL ~         5
+LL |     } else {
+LL |         panic!();
+LL ~     };
    |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:88:5
@@ -196,10 +179,12 @@ LL |     let y = SignificantDrop;
 LL |     x = 1;
    |     ^^^^^ initialised here
    |
-help: declare `x` here
+help: move the declaration `x` here
+   |
+LL ~     
+LL |     let y = SignificantDrop;
+LL ~     let x = 1;
    |
-LL |     let x = 1;
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:92:5
@@ -210,10 +195,12 @@ LL |     let y = 1;
 LL |     x = SignificantDrop;
    |     ^^^^^^^^^^^^^^^^^^^ initialised here
    |
-help: declare `x` here
+help: move the declaration `x` here
+   |
+LL ~     
+LL |     let y = 1;
+LL ~     let x = SignificantDrop;
    |
-LL |     let x = SignificantDrop;
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:96:5
@@ -224,10 +211,14 @@ LL |     let x;
 LL |     x = SignificantDrop;
    |     ^^^^^^^^^^^^^^^^^^^ initialised here
    |
-help: declare `x` here
+help: move the declaration `x` here
+   |
+LL ~     
+LL |     // types that should be considered insignificant
+ ...
+LL |     let y = Box::new(4);
+LL ~     let x = SignificantDrop;
    |
-LL |     let x = SignificantDrop;
-   |     ~~~~~
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:115:5
@@ -235,20 +226,17 @@ error: unneeded late initialization
 LL |     let a;
    |     ^^^^^^
    |
-help: declare `a` here
-   |
-LL |     let a = match n {
-   |     +++++++
-help: remove the assignments from the `match` arms
+help: move the declaration `a` here and remove the assignments from the `match` arms
    |
+LL ~     
+LL |     let n = 1;
+LL ~     let a = match n {
 LL ~         1 => f().await,
 LL |         _ => {
 LL ~             "two"
+LL |         },
+LL ~     };
    |
-help: add a semicolon after the `match` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:132:5
@@ -256,20 +244,17 @@ error: unneeded late initialization
 LL |     let a;
    |     ^^^^^^
    |
-help: declare `a` here
-   |
-LL |     let a = match n {
-   |     +++++++
-help: remove the assignments from the `match` arms
+help: move the declaration `a` here and remove the assignments from the `match` arms
    |
+LL ~     
+LL |     let n = 1;
+LL ~     let a = match n {
 LL ~         1 => f(),
 LL |         _ => {
 LL ~             "two"
+LL |         },
+LL ~     };
    |
-help: add a semicolon after the `match` expression
-   |
-LL |     };
-   |      +
 
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index dabeda72f0c..0ea911c3434 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -1,6 +1,5 @@
 #![feature(fn_traits, unboxed_closures)]
 #![warn(clippy::no_effect_underscore_binding)]
-#![allow(dead_code, path_statements)]
 #![allow(
     clippy::deref_addrof,
     clippy::redundant_field_names,
@@ -33,7 +32,6 @@ impl Neg for Cout {
     }
 }
 
-struct Unit;
 struct Tuple(i32);
 struct Struct {
     field: i32,
@@ -42,10 +40,6 @@ enum Enum {
     Tuple(i32),
     Struct { field: i32 },
 }
-struct DropUnit;
-impl Drop for DropUnit {
-    fn drop(&mut self) {}
-}
 struct DropStruct {
     field: i32,
 }
@@ -117,15 +111,9 @@ impl FnOnce<(&str,)> for GreetStruct3 {
 
 fn main() {
     let s = get_struct();
-    let s2 = get_struct();
 
     0;
     //~^ ERROR: statement with no effect
-    //~| NOTE: `-D clippy::no-effect` implied by `-D warnings`
-    s2;
-    //~^ ERROR: statement with no effect
-    Unit;
-    //~^ ERROR: statement with no effect
     Tuple(0);
     //~^ ERROR: statement with no effect
     Struct { field: 0 };
@@ -192,7 +180,6 @@ fn main() {
     unsafe { unsafe_fn() };
     let _used = get_struct();
     let _x = vec![1];
-    DropUnit;
     DropStruct { field: 0 };
     DropTuple(0);
     DropEnum::Tuple(0);
diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr
index c7c8eecd054..48ec997d938 100644
--- a/src/tools/clippy/tests/ui/no_effect.stderr
+++ b/src/tools/clippy/tests/ui/no_effect.stderr
@@ -1,5 +1,5 @@
 error: statement with no effect
-  --> tests/ui/no_effect.rs:122:5
+  --> tests/ui/no_effect.rs:115:5
    |
 LL |     0;
    |     ^^
@@ -8,151 +8,139 @@ LL |     0;
    = help: to override `-D warnings` add `#[allow(clippy::no_effect)]`
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:125:5
-   |
-LL |     s2;
-   |     ^^^
-
-error: statement with no effect
-  --> tests/ui/no_effect.rs:127:5
-   |
-LL |     Unit;
-   |     ^^^^^
-
-error: statement with no effect
-  --> tests/ui/no_effect.rs:129:5
+  --> tests/ui/no_effect.rs:117:5
    |
 LL |     Tuple(0);
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:131:5
+  --> tests/ui/no_effect.rs:119:5
    |
 LL |     Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:133:5
+  --> tests/ui/no_effect.rs:121:5
    |
 LL |     Struct { ..s };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:135:5
+  --> tests/ui/no_effect.rs:123:5
    |
 LL |     Union { a: 0 };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:137:5
+  --> tests/ui/no_effect.rs:125:5
    |
 LL |     Enum::Tuple(0);
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:139:5
+  --> tests/ui/no_effect.rs:127:5
    |
 LL |     Enum::Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:141:5
+  --> tests/ui/no_effect.rs:129:5
    |
 LL |     5 + 6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:143:5
+  --> tests/ui/no_effect.rs:131:5
    |
 LL |     *&42;
    |     ^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:145:5
+  --> tests/ui/no_effect.rs:133:5
    |
 LL |     &6;
    |     ^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:147:5
+  --> tests/ui/no_effect.rs:135:5
    |
 LL |     (5, 6, 7);
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:149:5
+  --> tests/ui/no_effect.rs:137:5
    |
 LL |     ..;
    |     ^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:151:5
+  --> tests/ui/no_effect.rs:139:5
    |
 LL |     5..;
    |     ^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:153:5
+  --> tests/ui/no_effect.rs:141:5
    |
 LL |     ..5;
    |     ^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:155:5
+  --> tests/ui/no_effect.rs:143:5
    |
 LL |     5..6;
    |     ^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:157:5
+  --> tests/ui/no_effect.rs:145:5
    |
 LL |     5..=6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:159:5
+  --> tests/ui/no_effect.rs:147:5
    |
 LL |     [42, 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:161:5
+  --> tests/ui/no_effect.rs:149:5
    |
 LL |     [42, 55][1];
    |     ^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:163:5
+  --> tests/ui/no_effect.rs:151:5
    |
 LL |     (42, 55).1;
    |     ^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:165:5
+  --> tests/ui/no_effect.rs:153:5
    |
 LL |     [42; 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:167:5
+  --> tests/ui/no_effect.rs:155:5
    |
 LL |     [42; 55][13];
    |     ^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:170:5
+  --> tests/ui/no_effect.rs:158:5
    |
 LL |     || x += 5;
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:173:5
+  --> tests/ui/no_effect.rs:161:5
    |
 LL |     FooString { s: s };
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:175:9
+  --> tests/ui/no_effect.rs:163:9
    |
 LL |     let _unused = 1;
    |         ^^^^^^^
@@ -161,22 +149,22 @@ LL |     let _unused = 1;
    = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]`
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:178:9
+  --> tests/ui/no_effect.rs:166:9
    |
 LL |     let _penguin = || println!("Some helpful closure");
    |         ^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:180:9
+  --> tests/ui/no_effect.rs:168:9
    |
 LL |     let _duck = Struct { field: 0 };
    |         ^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:182:9
+  --> tests/ui/no_effect.rs:170:9
    |
 LL |     let _cat = [2, 4, 6, 8][2];
    |         ^^^^
 
-error: aborting due to 29 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index fcd716f4144..5d6e488972c 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -282,7 +282,7 @@ mod issue_9218 {
         todo!()
     }
 
-    // These two's return types don't use use 'a so it's not okay
+    // These two's return types don't use 'a so it's not okay
     fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str {
         //~^ ERROR: using a reference to `Cow` is not recommended
         todo!()
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 0305d895fc5..7fc89bb9538 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -675,4 +675,60 @@ fn should_not_trigger_on_significant_iterator_drop() {
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/9072
+fn should_not_trigger_lint_if_place_expr_has_significant_drop() {
+    let x = Mutex::new(vec![1, 2, 3]);
+    let x_guard = x.lock().unwrap();
+
+    match x_guard[0] {
+        1 => println!("1!"),
+        x => println!("{x}"),
+    }
+
+    match x_guard.len() {
+        1 => println!("1!"),
+        x => println!("{x}"),
+    }
+}
+
+struct Guard<'a, T>(MutexGuard<'a, T>);
+
+struct Ref<'a, T>(&'a T);
+
+impl<'a, T> Guard<'a, T> {
+    fn guard(&self) -> &MutexGuard<T> {
+        &self.0
+    }
+
+    fn guard_ref(&self) -> Ref<MutexGuard<T>> {
+        Ref(&self.0)
+    }
+
+    fn take(self) -> Box<MutexGuard<'a, T>> {
+        Box::new(self.0)
+    }
+}
+
+fn should_not_trigger_for_significant_drop_ref() {
+    let mutex = Mutex::new(vec![1, 2]);
+    let guard = Guard(mutex.lock().unwrap());
+
+    match guard.guard().len() {
+        0 => println!("empty"),
+        _ => println!("not empty"),
+    }
+
+    match guard.guard_ref().0.len() {
+        0 => println!("empty"),
+        _ => println!("not empty"),
+    }
+
+    match guard.take().len() {
+        //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the
+        //~| NOTE: this might lead to deadlocks or other unexpected behavior
+        0 => println!("empty"),
+        _ => println!("not empty"),
+    };
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index 7d5b1acc7f0..811bb065527 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -28,6 +28,9 @@ LL |     match s.lock_m().get_the_value() {
 LL |             println!("{}", s.lock_m().get_the_value());
    |                            ---------- another value with significant `Drop` created here
 ...
+LL |             println!("{}", s.lock_m().get_the_value());
+   |                            ---------- another value with significant `Drop` created here
+...
 LL |     }
    |      - temporary lives until here
    |
@@ -47,6 +50,9 @@ LL |     match s.lock_m_m().get_the_value() {
 LL |             println!("{}", s.lock_m().get_the_value());
    |                            ---------- another value with significant `Drop` created here
 ...
+LL |             println!("{}", s.lock_m().get_the_value());
+   |                            ---------- another value with significant `Drop` created here
+...
 LL |     }
    |      - temporary lives until here
    |
@@ -360,7 +366,7 @@ LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL |         _ => println!("Value is {}", s.lock().deref()),
-   |                                      ---------------- another value with significant `Drop` created here
+   |                                      -------- another value with significant `Drop` created here
 LL |     };
    |      - temporary lives until here
    |
@@ -378,7 +384,7 @@ LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL |         matcher => println!("Value is {}", s.lock().deref()),
-   |                                            ---------------- another value with significant `Drop` created here
+   |                                            -------- another value with significant `Drop` created here
 LL |         _ => println!("Value was not a match"),
 LL |     };
    |      - temporary lives until here
@@ -499,5 +505,21 @@ LL ~     let value = mutex.lock().unwrap().foo();
 LL ~     match value {
    |
 
-error: aborting due to 26 previous errors
+error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
+  --> tests/ui/significant_drop_in_scrutinee.rs:726:11
+   |
+LL |     match guard.take().len() {
+   |           ^^^^^^^^^^^^^^^^^^
+...
+LL |     };
+   |      - temporary lives until here
+   |
+   = note: this might lead to deadlocks or other unexpected behavior
+help: try moving the temporary above the match
+   |
+LL ~     let value = guard.take().len();
+LL ~     match value {
+   |
+
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
index ad0e5fab029..2c582c90ba8 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
@@ -21,6 +21,8 @@ fn main() {
     let _ = check_files_ref_mut(&[(FileType::Account, path)]);
     let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
     let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
+
+    check_mut_iteratee_and_modify_inner_variable();
 }
 
 // `check_files` and its variants are based on:
@@ -138,3 +140,33 @@ fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool {
 fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
     Ok(std::path::PathBuf::new())
 }
+
+// Issue 12098
+// https://github.com/rust-lang/rust-clippy/issues/12098
+// no message emits
+fn check_mut_iteratee_and_modify_inner_variable() {
+    struct Test {
+        list: Vec<String>,
+        mut_this: bool,
+    }
+
+    impl Test {
+        fn list(&self) -> &[String] {
+            &self.list
+        }
+    }
+
+    let mut test = Test {
+        list: vec![String::from("foo"), String::from("bar")],
+        mut_this: false,
+    };
+
+    for _item in test.list().to_vec() {
+        println!("{}", _item);
+
+        test.mut_this = true;
+        {
+            test.mut_this = true;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
index d3d59c4c70f..a28ccd1efef 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
@@ -21,6 +21,8 @@ fn main() {
     let _ = check_files_ref_mut(&[(FileType::Account, path)]);
     let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
     let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
+
+    check_mut_iteratee_and_modify_inner_variable();
 }
 
 // `check_files` and its variants are based on:
@@ -138,3 +140,33 @@ fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool {
 fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
     Ok(std::path::PathBuf::new())
 }
+
+// Issue 12098
+// https://github.com/rust-lang/rust-clippy/issues/12098
+// no message emits
+fn check_mut_iteratee_and_modify_inner_variable() {
+    struct Test {
+        list: Vec<String>,
+        mut_this: bool,
+    }
+
+    impl Test {
+        fn list(&self) -> &[String] {
+            &self.list
+        }
+    }
+
+    let mut test = Test {
+        list: vec![String::from("foo"), String::from("bar")],
+        mut_this: false,
+    };
+
+    for _item in test.list().to_vec() {
+        println!("{}", _item);
+
+        test.mut_this = true;
+        {
+            test.mut_this = true;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
index 9d3591e0dbf..fb98cfddc26 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
@@ -1,5 +1,5 @@
 error: unnecessary use of `copied`
-  --> tests/ui/unnecessary_iter_cloned.rs:29:22
+  --> tests/ui/unnecessary_iter_cloned.rs:31:22
    |
 LL |     for (t, path) in files.iter().copied() {
    |                      ^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL +         let other = match get_file_path(t) {
    |
 
 error: unnecessary use of `copied`
-  --> tests/ui/unnecessary_iter_cloned.rs:44:22
+  --> tests/ui/unnecessary_iter_cloned.rs:46:22
    |
 LL |     for (t, path) in files.iter().copied() {
    |                      ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index 81759086f79..231fc0a892a 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -86,8 +86,51 @@ mod module {
 
 #[rustfmt::skip]
 #[allow(unused_import_braces)]
+#[allow(unused_braces)]
 use module::{Struct};
 
 fn main() {
     test_indented_attr();
 }
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/4467
+#[allow(dead_code)]
+use std::collections as puppy_doggy;
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/11595
+pub mod hidden_glob_reexports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyCoolTypeInternal;
+        pub use MyCoolTypeInternal as MyCoolType;
+    }
+
+    mod my_uncool_type {
+        pub(crate) struct MyUncoolType;
+    }
+
+    // This exports `MyCoolType`.
+    pub use my_prelude::*;
+
+    // This hides `my_prelude::MyCoolType`.
+    #[allow(hidden_glob_reexports)]
+    use my_uncool_type::MyUncoolType as MyCoolType;
+}
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/10878
+pub mod ambiguous_glob_exports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyType;
+    }
+
+    mod my_type {
+        pub struct MyType;
+    }
+
+    #[allow(ambiguous_glob_reexports)]
+    pub use my_prelude::*;
+    pub use my_type::*;
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 59a9dcf093b..8dfcd2110a4 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -86,8 +86,51 @@ mod module {
 
 #[rustfmt::skip]
 #[allow(unused_import_braces)]
+#[allow(unused_braces)]
 use module::{Struct};
 
 fn main() {
     test_indented_attr();
 }
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/4467
+#[allow(dead_code)]
+use std::collections as puppy_doggy;
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/11595
+pub mod hidden_glob_reexports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyCoolTypeInternal;
+        pub use MyCoolTypeInternal as MyCoolType;
+    }
+
+    mod my_uncool_type {
+        pub(crate) struct MyUncoolType;
+    }
+
+    // This exports `MyCoolType`.
+    pub use my_prelude::*;
+
+    // This hides `my_prelude::MyCoolType`.
+    #[allow(hidden_glob_reexports)]
+    use my_uncool_type::MyUncoolType as MyCoolType;
+}
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/10878
+pub mod ambiguous_glob_exports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyType;
+    }
+
+    mod my_type {
+        pub struct MyType;
+    }
+
+    #[allow(ambiguous_glob_reexports)]
+    pub use my_prelude::*;
+    pub use my_type::*;
+}
diff --git a/src/tools/clippy/tests/ui/while_float.rs b/src/tools/clippy/tests/ui/while_float.rs
new file mode 100644
index 00000000000..a3b0618948e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_float.rs
@@ -0,0 +1,14 @@
+#[deny(clippy::while_float)]
+fn main() {
+    let mut x = 0.0_f32;
+    while x < 42.0_f32 {
+        x += 0.5;
+    }
+    while x < 42.0 {
+        x += 1.0;
+    }
+    let mut x = 0;
+    while x < 42 {
+        x += 1;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/while_float.stderr b/src/tools/clippy/tests/ui/while_float.stderr
new file mode 100644
index 00000000000..b8e934b97c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_float.stderr
@@ -0,0 +1,20 @@
+error: while condition comparing floats
+  --> tests/ui/while_float.rs:4:11
+   |
+LL |     while x < 42.0_f32 {
+   |           ^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> tests/ui/while_float.rs:1:8
+   |
+LL | #[deny(clippy::while_float)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
+error: while condition comparing floats
+  --> tests/ui/while_float.rs:7:11
+   |
+LL |     while x < 42.0 {
+   |           ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index c63edd5bf70..7fd779fe9a4 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -406,7 +406,7 @@
                 }
 
                 // Search by id
-                if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) {
+                if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) {
                     return true;
                 }
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index afbcc3e92bc..7ff45edd4b2 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -250,7 +250,7 @@ pub struct Config {
     /// Only run tests that match these filters
     pub filters: Vec<String>,
 
-    /// Skip tests tests matching these substrings. Corresponds to
+    /// Skip tests matching these substrings. Corresponds to
     /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags.
     pub skip: Vec<String>,
 
@@ -381,7 +381,7 @@ pub struct Config {
     /// Whether to rerun tests even if the inputs are unchanged.
     pub force_rerun: bool,
 
-    /// Only rerun the tests that result has been modified accoring to Git status
+    /// Only rerun the tests that result has been modified according to Git status
     pub only_modified: bool,
 
     pub target_cfgs: OnceLock<TargetCfgs>,
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 2e45caec46c..99bde107f3a 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -950,7 +950,7 @@ fn is_android_gdb_target(target: &str) -> bool {
     )
 }
 
-/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing.
+/// Returns `true` if the given target is a MSVC target for the purposes of CDB testing.
 fn is_pc_windows_msvc_target(target: &str) -> bool {
     target.ends_with("-pc-windows-msvc")
 }
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 9e08f7e5f9b..904c2b614f3 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -21,7 +21,7 @@ const LOCAL_CRATE_ID: u32 = 0;
 ///              it is well formed. This involves calling `check_*` functions on
 ///              fields of that item, and `add_*` functions on [`Id`]s.
 /// - `add_*`: These add an [`Id`] to the worklist, after validating it to check if
-///            the `Id` is a kind expected in this suituation.
+///            the `Id` is a kind expected in this situation.
 #[derive(Debug)]
 pub struct Validator<'a> {
     pub(crate) errs: Vec<Error>,
diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs
index da94e686f38..79e279a8614 100644
--- a/src/tools/lld-wrapper/src/main.rs
+++ b/src/tools/lld-wrapper/src/main.rs
@@ -1,6 +1,6 @@
 //! Script to invoke the bundled rust-lld with the correct flavor.
 //!
-//! lld supports multiple command line interfaces. If `-flavor <flavor>` are passed as the first
+//! `lld` supports multiple command line interfaces. If `-flavor <flavor>` are passed as the first
 //! two arguments the `<flavor>` command line interface is used to process the remaining arguments.
 //! If no `-flavor` argument is present the flavor is determined by the executable name.
 //!
diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs
index d99957d9c22..28a824e54f6 100644
--- a/src/tools/miri/cargo-miri/src/util.rs
+++ b/src/tools/miri/cargo-miri/src/util.rs
@@ -269,7 +269,7 @@ pub fn get_target_dir(meta: &Metadata) -> PathBuf {
     output
 }
 
-/// Determines where the sysroot of this exeuction is
+/// Determines where the sysroot of this execution is
 ///
 /// Either in a user-specified spot by an envar, or in a default cache location.
 pub fn get_sysroot_dir() -> PathBuf {
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 8061f99b5d6..be0fdbc177a 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -253,7 +253,7 @@ impl Command {
         cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
             .run()
             .map_err(|e| {
-                // Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
+                // Try to un-do the previous `git commit`, to leave the repo in the state we found it.
                 cmd!(sh, "git reset --hard HEAD^")
                     .run()
                     .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
index 55ff09c53fe..3b6c29b5eb1 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
@@ -9,7 +9,7 @@ use crate::borrow_tracker::{
 };
 use crate::ProvenanceExtra;
 
-/// Exactly what cache size we should use is a difficult tradeoff. There will always be some
+/// Exactly what cache size we should use is a difficult trade-off. There will always be some
 /// workload which has a `BorTag` working set which exceeds the size of the cache, and ends up
 /// falling back to linear searches of the borrow stack very often.
 /// The cost of making this value too large is that the loop in `Stack::insert` which ensures the
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index b9f0b5bc17a..8abc8530f7c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -390,7 +390,7 @@ struct DisplayFmtWrapper {
     warning_text: S,
 }
 
-/// Formating of the permissions on each range.
+/// Formatting of the permissions on each range.
 ///
 /// Example:
 /// ```rust,ignore (private type)
@@ -422,7 +422,7 @@ struct DisplayFmtPermission {
     range_sep: S,
 }
 
-/// Formating of the tree structure.
+/// Formatting of the tree structure.
 ///
 /// Example:
 /// ```rust,ignore (private type)
@@ -487,7 +487,7 @@ struct DisplayFmtAccess {
     meh: S,
 }
 
-/// All parameters to determine how the tree is formated.
+/// All parameters to determine how the tree is formatted.
 struct DisplayFmt {
     wrapper: DisplayFmtWrapper,
     perm: DisplayFmtPermission,
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index bec51c7cdf2..28848e244ee 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -202,7 +202,7 @@ impl Permission {
         Self { inner: Frozen }
     }
 
-    /// Default initial permission of  the root of a new tre at out-of-bounds positions.
+    /// Default initial permission of  the root of a new tree at out-of-bounds positions.
     /// Must *only* be used for the root, this is not in general an "initial" permission!
     pub fn new_disabled() -> Self {
         Self { inner: Disabled }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index 6777f41ac2d..19acbdb697b 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -483,7 +483,7 @@ mod spurious_read {
         /// that causes UB in the target but not in the source.
         /// This implementation simply explores the reachable space
         /// by all sequences of `TestEvent`.
-        /// This function can be instanciated with `RetX` and `RetY`
+        /// This function can be instantiated with `RetX` and `RetY`
         /// among `NoRet` or `AllowRet` to resp. forbid/allow `x`/`y` to lose their
         /// protector.
         fn distinguishable<RetX, RetY>(&self, other: &Self) -> bool
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 6953ce81c5e..24e2c253852 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -111,7 +111,7 @@ pub enum BlockReason {
     Condvar(CondvarId),
     /// Blocked on a reader-writer lock.
     RwLock(RwLockId),
-    /// Blocled on a Futex variable.
+    /// Blocked on a Futex variable.
     Futex { addr: u64 },
     /// Blocked on an InitOnce.
     InitOnce(InitOnceId),
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index 574962c48d4..8c71eeb27aa 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -48,7 +48,7 @@
 //! One consequence of this difference is that safe/sound Rust allows for more operations on atomic locations
 //! than the C++20 atomic API was intended to allow, such as non-atomically accessing
 //! a previously atomically accessed location, or accessing previously atomically accessed locations with a differently sized operation
-//! (such as accessing the top 16 bits of an AtomicU32). These scenarios are generally undiscussed in formalisations of C++ memory model.
+//! (such as accessing the top 16 bits of an AtomicU32). These scenarios are generally undiscussed in formalizations of C++ memory model.
 //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations
 //! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations.
 //! A mixed atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown.
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 4cde364fbc4..e178187ffa6 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -42,6 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "flog2"
             | "flog10"
             | "ctlz"
+            | "ctpop"
             | "cttz"
             | "bswap"
             | "bitreverse"
@@ -68,6 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
                     "trunc" => Op::Round(rustc_apfloat::Round::TowardZero),
                     "ctlz" => Op::Numeric(sym::ctlz),
+                    "ctpop" => Op::Numeric(sym::ctpop),
                     "cttz" => Op::Numeric(sym::cttz),
                     "bswap" => Op::Numeric(sym::bswap),
                     "bitreverse" => Op::Numeric(sym::bitreverse),
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 54770873b84..cbf02d701bc 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -205,11 +205,11 @@ pub enum Provenance {
     /// whether *some* exposed pointer could have done what we want to do, and if the answer is yes
     /// then we allow the access. This allows too much code in two ways:
     /// - The same wildcard pointer can "take the role" of multiple different exposed pointers on
-    ///   subsequenct memory accesses.
+    ///   subsequent memory accesses.
     /// - In the aliasing model, we don't just have to know the borrow tag of the pointer used for
     ///   the access, we also have to update the aliasing state -- and that update can be very
     ///   different depending on which borrow tag we pick! Stacked Borrows has support for this by
-    ///   switching to a stack that is only approximately known, i.e. we overapproximate the effect
+    ///   switching to a stack that is only approximately known, i.e. we over-approximate the effect
     ///   of using *any* exposed pointer for this access, and only keep information about the borrow
     ///   stack that would be true with all possible choices.
     Wildcard,
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 38e689a3c34..89d04bb737e 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -11,7 +11,7 @@
 //! calls to munmap, but for a very different reason. In principle, according to the man pages, it
 //! is possible to unmap arbitrary regions of address space. But in a high-level language like Rust
 //! this amounts to partial deallocation, which LLVM does not support. So any attempt to call our
-//! munmap shim which would partily unmap a region of address space previously mapped by mmap will
+//! munmap shim which would partially unmap a region of address space previously mapped by mmap will
 //! report UB.
 
 use crate::*;
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index f24f279ab0f..0ba03d4ab78 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -390,7 +390,7 @@ fn reacquire_cond_mutex<'mir, 'tcx: 'mir>(
     Ok(())
 }
 
-/// After a thread waiting on a condvar was signalled:
+/// After a thread waiting on a condvar was signaled:
 /// Reacquire the conditional variable and remove the timeout callback if any
 /// was registered.
 fn post_cond_signal<'mir, 'tcx: 'mir>(
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 1f7138ca338..48b7222917b 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -757,7 +757,7 @@ fn int_abs<'tcx>(
     Ok(())
 }
 
-/// Splits `op` (which must be a SIMD vector) into 128-bit chuncks.
+/// Splits `op` (which must be a SIMD vector) into 128-bit chunks.
 ///
 /// Returns a tuple where:
 /// * The first element is the number of 128-bit chunks (let's call it `N`).
@@ -788,7 +788,7 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>(
     Ok((num_chunks, items_per_chunk, chunked_op))
 }
 
-/// Horizontaly performs `which` operation on adjacent values of
+/// Horizontally performs `which` operation on adjacent values of
 /// `left` and `right` SIMD vectors and stores the result in `dest`.
 /// "Horizontal" means that the i-th output element is calculated
 /// from the elements 2*i and 2*i+1 of the concatenation of `left` and
@@ -1256,7 +1256,7 @@ fn packusdw<'tcx>(
 
 /// Negates elements from `left` when the corresponding element in
 /// `right` is negative. If an element from `right` is zero, zero
-/// is writen to the corresponding output element.
+/// is written to the corresponding output element.
 /// In other words, multiplies `left` with `right.signum()`.
 fn psign<'tcx>(
     this: &mut crate::MiriInterpCx<'_, 'tcx>,
diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
index 97a70103e64..a20539ee7c7 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
@@ -5,7 +5,7 @@ extern "Rust" {
 
 fn main() {
     let frames = unsafe { miri_get_backtrace(0) };
-    for frame in frames.into_iter() {
+    for frame in frames.iter() {
         unsafe {
             miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields
         }
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
index 8d3173da400..3fff7921aff 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
@@ -27,7 +27,7 @@ fn func_d() -> Box<[*mut ()]> {
 fn main() {
     let mut seen_main = false;
     let frames = func_a();
-    for frame in frames.into_iter() {
+    for frame in frames.iter() {
         let miri_frame = unsafe { miri_resolve_frame(*frame, 0) };
         let name = String::from_utf8(miri_frame.name.into()).unwrap();
         let filename = String::from_utf8(miri_frame.filename.into()).unwrap();
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs
index ad05271ca51..a3060abc394 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs
@@ -32,7 +32,7 @@ fn func_d() -> Box<[*mut ()]> {
 fn main() {
     let mut seen_main = false;
     let frames = func_a();
-    for frame in frames.into_iter() {
+    for frame in frames.iter() {
         let miri_frame = unsafe { miri_resolve_frame(*frame, 1) };
 
         let mut name = vec![0; miri_frame.name_len];
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index 1fc713d48dc..248a57d6850 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -506,6 +506,21 @@ fn simd_intrinsics() {
         assert!(!simd_reduce_all(i32x2::from_array([0, -1])));
 
         assert_eq!(
+            simd_ctlz(i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32])),
+            i32x4::from_array([32, 1, 0, 0])
+        );
+
+        assert_eq!(
+            simd_ctpop(i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32])),
+            i32x4::from_array([0, 31, 1, 32])
+        );
+
+        assert_eq!(
+            simd_cttz(i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32])),
+            i32x4::from_array([32, 0, 31, 0])
+        );
+
+        assert_eq!(
             simd_select(i8x4::from_array([0, -1, -1, 0]), a, b),
             i32x4::from_array([1, 10, 10, 4])
         );
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 1ff410e723a..88e8640d56a 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -13,8 +13,6 @@ humansize = "2"
 sysinfo = { version = "0.30", default-features = false }
 fs_extra = "1"
 camino = "1"
-reqwest = { version = "0.11", features = ["blocking"] }
-zip = { version = "0.6", default-features = false, features = ["deflate"] }
 tar = "0.4"
 xz = { version = "0.1", package = "xz2" }
 serde = { version = "1", features = ["derive"] }
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index bd0a3815855..a709076f245 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -3,10 +3,7 @@ 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::{Environment, EnvironmentBuilder};
 use crate::exec::{cmd, Bootstrap};
@@ -17,9 +14,9 @@ use crate::training::{
     rustc_benchmarks,
 };
 use crate::utils::artifact_size::print_binary_sizes;
-use crate::utils::io::{copy_directory, move_directory, reset_directory};
+use crate::utils::io::{copy_directory, reset_directory};
 use crate::utils::{
-    clear_llvm_files, format_env_variables, print_free_disk_space, retry_action, with_log_group,
+    clear_llvm_files, format_env_variables, print_free_disk_space, with_log_group,
     write_timer_to_summary,
 };
 
@@ -69,7 +66,12 @@ enum EnvironmentCmd {
         #[arg(long, default_value = "opt-artifacts")]
         artifact_dir: Utf8PathBuf,
 
-        /// Checkout directory of `rustc-perf`, it will be fetched automatically if unspecified.
+        /// Checkout directory of `rustc-perf`.
+        ///
+        /// If unspecified, defaults to the rustc-perf submodule in the rustc checkout dir
+        /// (`src/tools/rustc-perf`), which should have been initialized when building this tool.
+        // FIXME: Move update_submodule into build_helper, that way we can also ensure the submodule
+        // is updated when _running_ opt-dist, rather than building.
         #[arg(long)]
         rustc_perf_checkout_dir: Option<Utf8PathBuf>,
 
@@ -146,8 +148,6 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .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![
@@ -191,9 +191,12 @@ fn execute_pipeline(
 ) -> anyhow::Result<()> {
     reset_directory(&env.artifact_dir())?;
 
-    with_log_group("Building rustc-perf", || match env.prebuilt_rustc_perf() {
-        Some(dir) => copy_rustc_perf(env, &dir),
-        None => download_rustc_perf(env),
+    with_log_group("Building rustc-perf", || {
+        let rustc_perf_checkout_dir = match env.prebuilt_rustc_perf() {
+            Some(dir) => dir,
+            None => env.checkout_path().join("src").join("tools").join("rustc-perf"),
+        };
+        copy_rustc_perf(env, &rustc_perf_checkout_dir)
     })?;
 
     // Stage 1: Build PGO instrumented rustc
@@ -409,36 +412,6 @@ fn copy_rustc_perf(env: &Environment, dir: &Utf8Path) -> anyhow::Result<()> {
     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-10-22
-    const PERF_COMMIT: &str = "4f313add609f43e928e98132358e8426ed3969ae";
-
-    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())
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index f9421117eaa..860d21876de 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -3,8 +3,7 @@
 
 # This script computes the new "current" toolstate for the toolstate repo (not to be
 # confused with publishing the test results, which happens in `src/bootstrap/toolstate.rs`).
-# It gets called from `src/ci/publish_toolstate.sh` when a new commit lands on `master`
-# (i.e., after it passed all checks on `auto`).
+# It gets called from `src/ci/publish_toolstate.sh` at the end of an `auto` build.
 
 from __future__ import print_function
 
diff --git a/src/tools/rust-analyzer/.git-blame-ignore-revs b/src/tools/rust-analyzer/.git-blame-ignore-revs
index a302e23781a..d5951a94209 100644
--- a/src/tools/rust-analyzer/.git-blame-ignore-revs
+++ b/src/tools/rust-analyzer/.git-blame-ignore-revs
@@ -6,3 +6,10 @@
 
 # prettier format
 f247090558c9ba3c551566eae5882b7ca865225f
+
+# subtree syncs
+932d85b52946d917deab2c23ead552f7f713b828
+3e358a6827d83e8d6473913a5e304734aadfed04
+9d2cb42a413e51deb50b36794a2e1605381878fc
+f532576ac53ddcc666bc8d59e0b6437065e2f599
+c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index a10345a7060..87a1729d2b4 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -63,15 +63,15 @@ jobs:
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update ${{ env.RUST_CHANNEL }}
-          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
           rustup default ${{ env.RUST_CHANNEL }}
+          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
         if: matrix.os == 'ubuntu-latest'
         run: echo "::add-matcher::.github/rust.json"
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
         with:
           key: ${{ env.RUST_CHANNEL }}
 
@@ -140,7 +140,7 @@ jobs:
           rustup target add ${{ env.targets }} ${{ env.targets_ide }}
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
 
       - name: Check
         run: |
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index b6cd4a795a8..a4146d60218 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -11,34 +11,21 @@ env:
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
-  setup_cargo:
+  build_metrics:
     if: github.repository == 'rust-lang/rust-analyzer'
     runs-on: ubuntu-latest
+
     steps:
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update stable
-          rustup component add rustfmt rust-src
           rustup default stable
-      - name: Cache cargo
-        uses: actions/cache@v4
-        with:
-          path: |
-            ~/.cargo/bin/
-            ~/.cargo/registry/index/
-            ~/.cargo/registry/cache/
-            ~/.cargo/git/db/
-          key: ${{ runner.os }}-cargo-${{ github.sha }}
+          rustup component add --toolchain stable rust-src
 
-  build_metrics:
-    runs-on: ubuntu-latest
-    needs: setup_cargo
-
-    steps:
       - name: Checkout repository
         uses: actions/checkout@v4
 
-      - name: Restore cargo cache
+      - name: Cache cargo
         uses: actions/cache@v4
         with:
           path: |
@@ -69,22 +56,18 @@ jobs:
       matrix:
         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]
+    needs: build_metrics
 
     steps:
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup default stable
+          rustup component add --toolchain stable rust-src
+
       - name: Checkout repository
         uses: actions/checkout@v4
 
-      - name: Restore cargo cache
-        uses: actions/cache@v4
-        with:
-          path: |
-            ~/.cargo/bin/
-            ~/.cargo/registry/index/
-            ~/.cargo/registry/cache/
-            ~/.cargo/git/db/
-          key: ${{ runner.os }}-cargo-${{ github.sha }}
-
       - name: Restore target cache
         uses: actions/cache@v4
         with:
diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
index 12a1a791fda..f975bbaa510 100644
--- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
@@ -26,7 +26,7 @@ jobs:
       run: cargo doc --all --no-deps
 
     - name: Deploy Docs
-      uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0
+      uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
       with:
         github_token: ${{ secrets.GITHUB_TOKEN }}
         publish_branch: gh-pages
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index a6e460134f2..8eb872514a5 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -28,9 +28,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.80"
+version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
+checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
 
 [[package]]
 name = "arbitrary"
@@ -46,15 +46,15 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "backtrace"
-version = "0.3.69"
+version = "0.3.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
 dependencies = [
  "addr2line",
  "cc",
@@ -91,9 +91,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.2"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
 
 [[package]]
 name = "byteorder"
@@ -112,9 +112,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
+checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
 dependencies = [
  "serde",
 ]
@@ -135,9 +135,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.90"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
 
 [[package]]
 name = "cfg"
@@ -160,6 +160,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
 name = "chalk-derive"
 version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -177,7 +183,7 @@ version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "chalk-derive",
 ]
 
@@ -282,11 +288,11 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
 
 [[package]]
 name = "ctrlc"
-version = "3.4.2"
+version = "3.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
+checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345"
 dependencies = [
- "nix 0.27.1",
+ "nix 0.28.0",
  "windows-sys 0.52.0",
 ]
 
@@ -324,10 +330,31 @@ dependencies = [
 ]
 
 [[package]]
+name = "directories"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "dissimilar"
-version = "1.0.7"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
+checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
 
 [[package]]
 name = "dot"
@@ -343,15 +370,15 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
 
 [[package]]
 name = "either"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
 
 [[package]]
 name = "ena"
-version = "0.14.2"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
+checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
 dependencies = [
  "log",
 ]
@@ -364,9 +391,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "expect-test"
-version = "1.4.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3"
+checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
 dependencies = [
  "dissimilar",
  "once_cell",
@@ -380,7 +407,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.4.1",
  "windows-sys 0.52.0",
 ]
 
@@ -392,9 +419,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
 
 [[package]]
 name = "flate2"
-version = "1.0.28"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
+checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -442,9 +469,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 
 [[package]]
 name = "getrandom"
-version = "0.2.12"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -459,9 +486,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 
 [[package]]
 name = "heck"
@@ -504,7 +531,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cfg",
  "cov-mark",
  "dashmap",
@@ -568,7 +595,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "chalk-derive",
  "chalk-ir",
  "chalk-recursive",
@@ -589,7 +616,7 @@ dependencies = [
  "oorandom",
  "project-model",
  "ra-ap-rustc_abi",
- "ra-ap-rustc_index",
+ "ra-ap-rustc_index 0.53.0",
  "ra-ap-rustc_pattern_analysis",
  "rustc-hash",
  "scoped-tls",
@@ -695,7 +722,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cov-mark",
  "crossbeam-channel",
  "either",
@@ -776,9 +803,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.2.5"
+version = "2.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -826,9 +853,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "jod-thread"
@@ -874,9 +901,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.153"
+version = "0.2.154"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
 
 [[package]]
 name = "libloading"
@@ -885,20 +912,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
 name = "libmimalloc-sys"
-version = "0.1.35"
+version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664"
+checksum = "81eb4061c0582dedea1cbc7aff2240300dd6982e0239d1c99e65c1dbf4a30ba7"
 dependencies = [
  "cc",
  "libc",
 ]
 
 [[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.5.0",
+ "libc",
+]
+
+[[package]]
 name = "limit"
 version = "0.0.0"
 
@@ -948,9 +985,9 @@ dependencies = [
 
 [[package]]
 name = "lock_api"
-version = "0.4.11"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -1001,9 +1038,9 @@ dependencies = [
 
 [[package]]
 name = "lz4_flex"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
+checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
 
 [[package]]
 name = "mbe"
@@ -1023,9 +1060,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.1"
+version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
 [[package]]
 name = "memmap2"
@@ -1038,18 +1075,18 @@ dependencies = [
 
 [[package]]
 name = "memoffset"
-version = "0.9.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "mimalloc"
-version = "0.1.39"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c"
+checksum = "9f41a2280ded0da56c8cf898babb86e8f10651a34adcfff190ae9a1159c6908d"
 dependencies = [
  "libmimalloc-sys",
 ]
@@ -1097,12 +1134,13 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.27.1"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cfg-if",
+ "cfg_aliases",
  "libc",
 ]
 
@@ -1118,7 +1156,7 @@ version = "6.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "crossbeam-channel",
  "filetime",
  "fsevent-sys",
@@ -1187,10 +1225,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
 name = "parking_lot"
-version = "0.12.1"
+version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -1198,15 +1242,15 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.9"
+version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.5.1",
  "smallvec",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -1224,9 +1268,9 @@ dependencies = [
 
 [[package]]
 name = "paste"
-version = "1.0.14"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
 [[package]]
 name = "paths"
@@ -1262,9 +1306,9 @@ dependencies = [
 
 [[package]]
 name = "petgraph"
-version = "0.6.4"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
+checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
 dependencies = [
  "fixedbitset",
  "indexmap",
@@ -1272,9 +1316,9 @@ dependencies = [
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "powerfmt"
@@ -1346,9 +1390,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
 dependencies = [
  "unicode-ident",
 ]
@@ -1365,7 +1409,7 @@ dependencies = [
  "perf-event",
  "tikv-jemalloc-ctl",
  "tracing",
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -1417,7 +1461,7 @@ version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "memchr",
  "unicase",
 ]
@@ -1433,21 +1477,21 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.44.0"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8709df2a746f055316bc0c62bd30948695a25e734863bf6e1f9755403e010ab"
+checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46"
 dependencies = [
- "bitflags 2.4.2",
- "ra-ap-rustc_index",
+ "bitflags 2.5.0",
+ "ra-ap-rustc_index 0.53.0",
  "tracing",
 ]
 
@@ -1458,7 +1502,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20"
 dependencies = [
  "arrayvec",
- "ra-ap-rustc_index_macros",
+ "ra-ap-rustc_index_macros 0.44.0",
+ "smallvec",
+]
+
+[[package]]
+name = "ra-ap-rustc_index"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9"
+dependencies = [
+ "arrayvec",
+ "ra-ap-rustc_index_macros 0.53.0",
  "smallvec",
 ]
 
@@ -1475,10 +1530,22 @@ dependencies = [
 ]
 
 [[package]]
+name = "ra-ap-rustc_index_macros"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82f3d6dcb30a66905388e14756b8f2216131d9f8004922c07f13335840e058d1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.44.0"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aab683fc8579d09eb72033bd5dc9ba6d701aa9645b5fed087ef19af71184dff3"
+checksum = "dbd8a2b0bdcba9892cbce0b25f6c953d31b0febc1f3420fc692884fce5a23ad8"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1486,11 +1553,11 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.44.0"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bcf9ff5edbf784b67b8ad5e03a068f1300fcc24062c0d476b3018965135d933"
+checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135"
 dependencies = [
- "ra-ap-rustc_index",
+ "ra-ap-rustc_index 0.53.0",
  "ra-ap-rustc_lexer",
 ]
 
@@ -1500,7 +1567,7 @@ version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334"
 dependencies = [
- "ra-ap-rustc_index",
+ "ra-ap-rustc_index 0.44.0",
  "rustc-hash",
  "rustc_apfloat",
  "smallvec",
@@ -1539,9 +1606,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
 dependencies = [
  "either",
  "rayon-core",
@@ -1567,6 +1634,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "redox_syscall"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+dependencies = [
+ "bitflags 2.5.0",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
 name = "rowan"
 version = "0.15.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1634,16 +1721,16 @@ dependencies = [
  "vfs",
  "vfs-notify",
  "walkdir",
- "winapi",
+ "windows-sys 0.52.0",
  "xflags",
  "xshell",
 ]
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustc-hash"
@@ -1663,9 +1750,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "salsa"
@@ -1729,27 +1816,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.197"
+version = "1.0.201"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.197"
+version = "1.0.201"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1758,9 +1845,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.114"
+version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
 dependencies = [
  "indexmap",
  "itoa",
@@ -1770,9 +1857,9 @@ dependencies = [
 
 [[package]]
 name = "serde_repr"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
+checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1799,9 +1886,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.13.1"
+version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "smol_str"
@@ -1856,14 +1943,14 @@ dependencies = [
  "jod-thread",
  "libc",
  "miow",
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.52"
+version = "2.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
+checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1946,18 +2033,18 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
 
 [[package]]
 name = "thiserror"
-version = "1.0.57"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.57"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2007,9 +2094,9 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.34"
+version = "0.3.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
 dependencies = [
  "deranged",
  "num-conv",
@@ -2041,9 +2128,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "toml"
-version = "0.8.8"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
+checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2062,9 +2149,9 @@ dependencies = [
 
 [[package]]
 name = "toml_edit"
-version = "0.21.0"
+version = "0.22.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
+checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
 dependencies = [
  "indexmap",
  "serde",
@@ -2255,6 +2342,7 @@ dependencies = [
  "paths",
  "rustc-hash",
  "stdx",
+ "tracing",
 ]
 
 [[package]]
@@ -2304,11 +2392,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-util"
-version = "0.1.6"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
 dependencies = [
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2332,7 +2420,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -2352,17 +2440,18 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.4",
- "windows_aarch64_msvc 0.52.4",
- "windows_i686_gnu 0.52.4",
- "windows_i686_msvc 0.52.4",
- "windows_x86_64_gnu 0.52.4",
- "windows_x86_64_gnullvm 0.52.4",
- "windows_x86_64_msvc 0.52.4",
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
 ]
 
 [[package]]
@@ -2373,9 +2462,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -2385,9 +2474,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -2397,9 +2486,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.4"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -2409,9 +2504,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -2421,9 +2516,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -2433,9 +2528,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -2445,15 +2540,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
 [[package]]
 name = "winnow"
-version = "0.5.32"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6"
+checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
 dependencies = [
  "memchr",
 ]
@@ -2481,24 +2576,25 @@ checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155"
 
 [[package]]
 name = "xshell"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad"
+checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e"
+checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
 
 [[package]]
 name = "xtask"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "directories",
  "flate2",
  "itertools",
  "proc-macro2",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index f7e3ae51dfd..3108c1b3dfe 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.76"
+rust-version = "1.78"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
@@ -85,10 +85,10 @@ tt = { path = "./crates/tt", version = "0.0.0" }
 vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.44.0", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.44.0", default-features = false }
-ra-ap-rustc_index = { version = "0.44.0", default-features = false }
-ra-ap-rustc_abi = { version = "0.44.0", default-features = false }
+ra-ap-rustc_lexer = { version = "0.53.0", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false }
+ra-ap-rustc_index = { version = "0.53.0", default-features = false }
+ra-ap-rustc_abi = { version = "0.53.0", default-features = false }
 ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs
index f202a885e27..927b2108a6c 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/change.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs
@@ -51,7 +51,7 @@ impl FileChange {
     }
 
     pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
-        let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered();
         if let Some(roots) = self.roots {
             for (idx, root) in roots.into_iter().enumerate() {
                 let root_id = SourceRootId(idx as u32);
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 240af7925cc..b2c3f38ab4f 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -324,21 +324,27 @@ pub struct Dependency {
     pub crate_id: CrateId,
     pub name: CrateName,
     prelude: bool,
+    sysroot: bool,
 }
 
 impl Dependency {
     pub fn new(name: CrateName, crate_id: CrateId) -> Self {
-        Self { name, crate_id, prelude: true }
+        Self { name, crate_id, prelude: true, sysroot: false }
     }
 
-    pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self {
-        Self { name, crate_id, prelude }
+    pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool, sysroot: bool) -> Self {
+        Self { name, crate_id, prelude, sysroot }
     }
 
     /// Whether this dependency is to be added to the depending crate's extern prelude.
     pub fn is_prelude(&self) -> bool {
         self.prelude
     }
+
+    /// Whether this dependency is a sysroot injected one.
+    pub fn is_sysroot(&self) -> bool {
+        self.sysroot
+    }
 }
 
 impl CrateGraph {
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 2b64a07a5a9..2c13eed56c3 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -8,7 +8,7 @@ mod input;
 use std::panic;
 
 use salsa::Durability;
-use syntax::{ast, Parse, SourceFile};
+use syntax::{ast, Parse, SourceFile, SyntaxError};
 use triomphe::Arc;
 
 pub use crate::{
@@ -51,6 +51,7 @@ pub trait FileLoader {
     /// Text of the file.
     fn file_text(&self, file_id: FileId) -> Arc<str>;
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
+    /// Crates whose root's source root is the same as the source root of `file_id`
     fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>;
 }
 
@@ -61,6 +62,9 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
     /// Parses the file into the syntax tree.
     fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
 
+    /// Returns the set of errors obtained from parsing the file including validation errors.
+    fn parse_errors(&self, file_id: FileId) -> Option<Arc<[SyntaxError]>>;
+
     /// The crate graph.
     #[salsa::input]
     fn crate_graph(&self) -> Arc<CrateGraph>;
@@ -81,12 +85,20 @@ fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option<ReleaseC
 }
 
 fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
-    let _p = tracing::span!(tracing::Level::INFO, "parse_query", ?file_id).entered();
+    let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered();
     let text = db.file_text(file_id);
     // FIXME: Edition based parsing
     SourceFile::parse(&text, span::Edition::CURRENT)
 }
 
+fn parse_errors(db: &dyn SourceDatabase, file_id: FileId) -> Option<Arc<[SyntaxError]>> {
+    let errors = db.parse(file_id).errors();
+    match &*errors {
+        [] => None,
+        [..] => Some(errors.into()),
+    }
+}
+
 /// We don't want to give HIR knowledge of source roots, hence we extract these
 /// methods into a separate DB.
 #[salsa::query_group(SourceDatabaseExtStorage)]
@@ -104,6 +116,7 @@ pub trait SourceDatabaseExt: SourceDatabase {
     #[salsa::input]
     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
 
+    /// Crates whose root fool is in `id`.
     fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
 }
 
diff --git a/src/tools/rust-analyzer/crates/cfg/src/tests.rs b/src/tools/rust-analyzer/crates/cfg/src/tests.rs
index a1ae15fcdda..dddaf2cce18 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/tests.rs
@@ -1,6 +1,6 @@
 use arbitrary::{Arbitrary, Unstructured};
 use expect_test::{expect, Expect};
-use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
 use syntax::{ast, AstNode, Edition};
 
 use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr};
@@ -8,7 +8,12 @@ use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr};
 fn assert_parse_result(input: &str, expected: CfgExpr) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     assert_eq!(cfg, expected);
 }
@@ -16,7 +21,12 @@ fn assert_parse_result(input: &str, expected: CfgExpr) {
 fn check_dnf(input: &str, expect: Expect) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     let actual = format!("#![cfg({})]", DnfExpr::new(cfg));
     expect.assert_eq(&actual);
@@ -25,7 +35,12 @@ fn check_dnf(input: &str, expect: Expect) {
 fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     let dnf = DnfExpr::new(cfg);
     let why_inactive = dnf.why_inactive(opts).unwrap().to_string();
@@ -36,7 +51,12 @@ fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) {
 fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     let dnf = DnfExpr::new(cfg);
     let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::<Vec<_>>();
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index 5dfaaf77420..6d5ca8321e5 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -125,8 +125,10 @@ impl FlycheckHandle {
         config: FlycheckConfig,
         sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
+        manifest_path: Option<AbsPathBuf>,
     ) -> FlycheckHandle {
-        let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root);
+        let actor =
+            FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path);
         let (sender, receiver) = unbounded::<StateChange>();
         let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
             .name("Flycheck".to_owned())
@@ -205,6 +207,7 @@ struct FlycheckActor {
     id: usize,
     sender: Box<dyn Fn(Message) + Send>,
     config: FlycheckConfig,
+    manifest_path: Option<AbsPathBuf>,
     /// Either the workspace root of the workspace we are flychecking,
     /// or the project root of the project.
     root: AbsPathBuf,
@@ -233,6 +236,7 @@ impl FlycheckActor {
         config: FlycheckConfig,
         sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
+        manifest_path: Option<AbsPathBuf>,
     ) -> FlycheckActor {
         tracing::info!(%id, ?workspace_root, "Spawning flycheck");
         FlycheckActor {
@@ -241,6 +245,7 @@ impl FlycheckActor {
             config,
             sysroot_root,
             root: workspace_root,
+            manifest_path,
             command_handle: None,
             command_receiver: None,
         }
@@ -388,8 +393,13 @@ impl FlycheckActor {
                     "--message-format=json"
                 });
 
-                cmd.arg("--manifest-path");
-                cmd.arg(self.root.join("Cargo.toml"));
+                if let Some(manifest_path) = &self.manifest_path {
+                    cmd.arg("--manifest-path");
+                    cmd.arg(manifest_path);
+                    if manifest_path.extension().map_or(false, |ext| ext == "rs") {
+                        cmd.arg("-Zscript");
+                    }
+                }
 
                 options.apply_on_command(&mut cmd);
                 (cmd, options.extra_args.clone())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
index 9b68797fbf7..727f4429802 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
@@ -5,7 +5,7 @@ use triomphe::Arc;
 
 use base_db::FileId;
 use hir_expand::span_map::{RealSpanMap, SpanMap};
-use mbe::syntax_node_to_token_tree;
+use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode};
 use syntax::{ast, AstNode, TextRange};
 
 use crate::attr::{DocAtom, DocExpr};
@@ -18,6 +18,7 @@ fn assert_parse_result(input: &str, expected: DocExpr) {
         tt.syntax(),
         map.as_ref(),
         map.span_for_range(TextRange::empty(0.into())),
+        DocCommentDesugarMode::ProcMacro,
     );
     let cfg = DocExpr::parse(&tt);
     assert_eq!(cfg, expected);
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 c9f1add2751..d2f4d7b7e56 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -10,9 +10,10 @@ use std::ops::Index;
 
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
-use hir_expand::{name::Name, HirFileId, InFile};
+use hir_expand::{name::Name, InFile};
 use la_arena::{Arena, ArenaMap};
 use rustc_hash::FxHashMap;
+use span::MacroFileId;
 use syntax::{ast, AstPtr, SyntaxNodePtr};
 use triomphe::Arc;
 
@@ -98,7 +99,7 @@ pub struct BodySourceMap {
 
     format_args_template_map: FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
 
-    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
+    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,
 
     /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
     /// the source map (since they're just as volatile).
@@ -349,11 +350,17 @@ impl BodySourceMap {
         self.expr_map.get(&src).cloned()
     }
 
-    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
+    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroFileId> {
         let src = node.map(AstPtr::new);
         self.expansions.get(&src).cloned()
     }
 
+    pub fn macro_calls(
+        &self,
+    ) -> impl Iterator<Item = (InFile<AstPtr<ast::MacroCall>>, MacroFileId)> + '_ {
+        self.expansions.iter().map(|(&a, &b)| (a, b))
+    }
+
     pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
         self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
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 340e95dbc2f..82f89393add 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
@@ -1006,7 +1006,9 @@ impl ExprCollector<'_> {
             Some((mark, expansion)) => {
                 // Keep collecting even with expansion errors so we can provide completions and
                 // other services in incomplete macro expressions.
-                self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id());
+                self.source_map
+                    .expansions
+                    .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap());
                 let prev_ast_id_map = mem::replace(
                     &mut self.ast_id_map,
                     self.db.ast_id_map(self.expander.current_file_id()),
@@ -1869,42 +1871,45 @@ impl ExprCollector<'_> {
     ) -> 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(),
-                }
+                let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                    *n as u128,
+                    Some(BuiltinUint::Usize),
+                )));
+                let count_is =
+                    match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
+                        Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
+                        None => self.missing_expr(),
+                    };
+                self.alloc_expr_desugared(Expr::Call {
+                    callee: count_is,
+                    args: Box::new([args]),
+                    is_assignee_expr: false,
+                })
             }
             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,
-                            })
-                        }
+                    let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                        i as u128,
+                        Some(BuiltinUint::Usize),
+                    )));
+                    let count_param = match LangItem::FormatCount.ty_rel_path(
+                        self.db,
+                        self.krate,
+                        name![Param],
+                    ) {
+                        Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
                         None => self.missing_expr(),
-                    }
+                    };
+                    self.alloc_expr_desugared(Expr::Call {
+                        callee: count_param,
+                        args: Box::new([args]),
+                        is_assignee_expr: false,
+                    })
                 } else {
+                    // FIXME: This drops arg causing it to potentially not be resolved/type checked
+                    // when typing?
                     self.missing_expr()
                 }
             }
@@ -1925,7 +1930,8 @@ impl ExprCollector<'_> {
     fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
         use ArgumentType::*;
         use FormatTrait::*;
-        match LangItem::FormatArgument.ty_rel_path(
+
+        let new_fn = match LangItem::FormatArgument.ty_rel_path(
             self.db,
             self.krate,
             match ty {
@@ -1941,16 +1947,14 @@ impl ExprCollector<'_> {
                 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,
-                })
-            }
+            Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
             None => self.missing_expr(),
-        }
+        };
+        self.alloc_expr_desugared(Expr::Call {
+            callee: new_fn,
+            args: Box::new([arg]),
+            is_assignee_expr: false,
+        })
     }
     // endregion: format
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index 0020e4eac30..fd685235e17 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -7,7 +7,7 @@ use crate::{
     body::Body,
     db::DefDatabase,
     hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
-    BlockId, DefWithBodyId,
+    BlockId, ConstBlockId, DefWithBodyId,
 };
 
 pub type ScopeId = Idx<ScopeData>;
@@ -46,7 +46,9 @@ pub struct ScopeData {
 impl ExprScopes {
     pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
         let body = db.body(def);
-        let mut scopes = ExprScopes::new(&body);
+        let mut scopes = ExprScopes::new(&body, |const_block| {
+            db.lookup_intern_anonymous_const(const_block).root
+        });
         scopes.shrink_to_fit();
         Arc::new(scopes)
     }
@@ -89,7 +91,10 @@ fn empty_entries(idx: usize) -> IdxRange<ScopeEntry> {
 }
 
 impl ExprScopes {
-    fn new(body: &Body) -> ExprScopes {
+    fn new(
+        body: &Body,
+        resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
+    ) -> ExprScopes {
         let mut scopes = ExprScopes {
             scopes: Arena::default(),
             scope_entries: Arena::default(),
@@ -100,7 +105,7 @@ impl ExprScopes {
             scopes.add_bindings(body, root, self_param);
         }
         scopes.add_params_bindings(body, root, &body.params);
-        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
+        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
         scopes
     }
 
@@ -183,35 +188,46 @@ fn compute_block_scopes(
     body: &Body,
     scopes: &mut ExprScopes,
     scope: &mut ScopeId,
+    resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
 ) {
     for stmt in statements {
         match stmt {
             Statement::Let { pat, initializer, else_branch, .. } => {
                 if let Some(expr) = initializer {
-                    compute_expr_scopes(*expr, body, scopes, scope);
+                    compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
                 }
                 if let Some(expr) = else_branch {
-                    compute_expr_scopes(*expr, body, scopes, scope);
+                    compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
                 }
 
                 *scope = scopes.new_scope(*scope);
                 scopes.add_pat_bindings(body, *scope, *pat);
             }
             Statement::Expr { expr, .. } => {
-                compute_expr_scopes(*expr, body, scopes, scope);
+                compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
             }
             Statement::Item => (),
         }
     }
     if let Some(expr) = tail {
-        compute_expr_scopes(expr, body, scopes, scope);
+        compute_expr_scopes(expr, body, scopes, scope, resolve_const_block);
     }
 }
 
-fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) {
+fn compute_expr_scopes(
+    expr: ExprId,
+    body: &Body,
+    scopes: &mut ExprScopes,
+    scope: &mut ScopeId,
+    resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
+) {
     let make_label =
         |label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
 
+    let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
+        compute_expr_scopes(expr, body, scopes, scope, resolve_const_block)
+    };
+
     scopes.set_scope(expr, *scope);
     match &body[expr] {
         Expr::Block { statements, tail, id, label } => {
@@ -219,53 +235,54 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
             // Overwrite the old scope for the block expr, so that every block scope can be found
             // via the block itself (important for blocks that only contain items, no expressions).
             scopes.set_scope(expr, scope);
-            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
+            compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
         }
-        Expr::Const(_) => {
-            // FIXME: This is broken.
+        Expr::Const(id) => {
+            let mut scope = scopes.root_scope();
+            compute_expr_scopes(scopes, resolve_const_block(*id), &mut scope);
         }
         Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => {
             let mut scope = scopes.new_block_scope(*scope, *id, None);
             // Overwrite the old scope for the block expr, so that every block scope can be found
             // via the block itself (important for blocks that only contain items, no expressions).
             scopes.set_scope(expr, scope);
-            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
+            compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
         }
         Expr::Loop { body: body_expr, label } => {
             let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
-            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
+            compute_expr_scopes(scopes, *body_expr, &mut scope);
         }
         Expr::Closure { args, body: body_expr, .. } => {
             let mut scope = scopes.new_scope(*scope);
             scopes.add_params_bindings(body, scope, args);
-            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
+            compute_expr_scopes(scopes, *body_expr, &mut scope);
         }
         Expr::Match { expr, arms } => {
-            compute_expr_scopes(*expr, body, scopes, scope);
+            compute_expr_scopes(scopes, *expr, scope);
             for arm in arms.iter() {
                 let mut scope = scopes.new_scope(*scope);
                 scopes.add_pat_bindings(body, scope, arm.pat);
                 if let Some(guard) = arm.guard {
                     scope = scopes.new_scope(scope);
-                    compute_expr_scopes(guard, body, scopes, &mut scope);
+                    compute_expr_scopes(scopes, guard, &mut scope);
                 }
-                compute_expr_scopes(arm.expr, body, scopes, &mut scope);
+                compute_expr_scopes(scopes, arm.expr, &mut scope);
             }
         }
         &Expr::If { condition, then_branch, else_branch } => {
             let mut then_branch_scope = scopes.new_scope(*scope);
-            compute_expr_scopes(condition, body, scopes, &mut then_branch_scope);
-            compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope);
+            compute_expr_scopes(scopes, condition, &mut then_branch_scope);
+            compute_expr_scopes(scopes, then_branch, &mut then_branch_scope);
             if let Some(else_branch) = else_branch {
-                compute_expr_scopes(else_branch, body, scopes, scope);
+                compute_expr_scopes(scopes, else_branch, scope);
             }
         }
         &Expr::Let { pat, expr } => {
-            compute_expr_scopes(expr, body, scopes, scope);
+            compute_expr_scopes(scopes, expr, scope);
             *scope = scopes.new_scope(*scope);
             scopes.add_pat_bindings(body, *scope, pat);
         }
-        e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
+        e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
     };
 }
 
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 a27ffe21675..4c8a54f7c8c 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
@@ -318,18 +318,20 @@ fn f() {
 
     expect![[r#"
         fn f() {
-            $crate::panicking::panic_fmt(
-                builtin#lang(Arguments::new_v1_formatted)(
-                    &[
-                        "cc",
-                    ],
-                    &[],
-                    &[],
-                    unsafe {
-                        builtin#lang(UnsafeArg::new)()
-                    },
-                ),
-            );
+            {
+                $crate::panicking::panic_fmt(
+                    builtin#lang(Arguments::new_v1_formatted)(
+                        &[
+                            "cc",
+                        ],
+                        &[],
+                        &[],
+                        unsafe {
+                            builtin#lang(UnsafeArg::new)()
+                        },
+                    ),
+                );
+            };
         }"#]]
     .assert_eq(&body.pretty_print(&db, def))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index e3d750d33ca..51a4dd6f42a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -229,7 +229,7 @@ pub struct TraitData {
     /// method calls to this trait's methods when the receiver is an array and the crate edition is
     /// 2015 or 2018.
     // box it as the vec is usually empty anyways
-    pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 }
 
 impl TraitData {
@@ -258,12 +258,12 @@ impl TraitData {
         let mut collector =
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
         collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
-        let (items, attribute_calls, diagnostics) = collector.finish();
+        let (items, macro_calls, diagnostics) = collector.finish();
 
         (
             Arc::new(TraitData {
                 name,
-                attribute_calls,
+                macro_calls,
                 items,
                 is_auto,
                 is_unsafe,
@@ -298,7 +298,7 @@ impl TraitData {
     }
 
     pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
-        self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
+        self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
 }
 
@@ -319,7 +319,7 @@ impl TraitAliasData {
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 pub struct ImplData {
     pub target_trait: Option<Interned<TraitRef>>,
     pub self_ty: Interned<TypeRef>,
@@ -327,7 +327,7 @@ pub struct ImplData {
     pub is_negative: bool,
     pub is_unsafe: bool,
     // box it as the vec is usually empty anyways
-    pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 }
 
 impl ImplData {
@@ -354,7 +354,7 @@ impl ImplData {
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id));
         collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
 
-        let (items, attribute_calls, diagnostics) = collector.finish();
+        let (items, macro_calls, diagnostics) = collector.finish();
         let items = items.into_iter().map(|(_, item)| item).collect();
 
         (
@@ -364,14 +364,14 @@ impl ImplData {
                 items,
                 is_negative,
                 is_unsafe,
-                attribute_calls,
+                macro_calls,
             }),
             DefDiagnostics::new(diagnostics),
         )
     }
 
     pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
-        self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
+        self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
 }
 
@@ -573,7 +573,7 @@ struct AssocItemCollector<'a> {
     expander: Expander,
 
     items: Vec<(Name, AssocItemId)>,
-    attr_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
+    macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
 }
 
 impl<'a> AssocItemCollector<'a> {
@@ -590,7 +590,7 @@ impl<'a> AssocItemCollector<'a> {
             container,
             expander: Expander::new(db, file_id, module_id),
             items: Vec::new(),
-            attr_calls: Vec::new(),
+            macro_calls: Vec::new(),
             diagnostics: Vec::new(),
         }
     }
@@ -604,7 +604,7 @@ impl<'a> AssocItemCollector<'a> {
     ) {
         (
             self.items,
-            if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) },
+            if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
             self.diagnostics,
         )
     }
@@ -662,11 +662,11 @@ impl<'a> AssocItemCollector<'a> {
                             }
                         }
 
-                        self.attr_calls.push((ast_id, call_id));
+                        self.macro_calls.push((ast_id, call_id));
 
                         let res =
                             self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
-                        self.collect_macro_items(res, &|| loc.kind.clone());
+                        self.collect_macro_items(res);
                         continue 'items;
                     }
                     Ok(_) => (),
@@ -698,24 +698,22 @@ impl<'a> AssocItemCollector<'a> {
         match item {
             AssocItem::Function(id) => {
                 let item = &item_tree[id];
-
                 let def =
                     FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
                 self.items.push((item.name.clone(), def.into()));
             }
-            AssocItem::Const(id) => {
-                let item = &item_tree[id];
-                let Some(name) = item.name.clone() else { return };
-                let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
-                self.items.push((name, def.into()));
-            }
             AssocItem::TypeAlias(id) => {
                 let item = &item_tree[id];
-
                 let def =
                     TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
                 self.items.push((item.name.clone(), def.into()));
             }
+            AssocItem::Const(id) => {
+                let item = &item_tree[id];
+                let Some(name) = item.name.clone() else { return };
+                let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
+                self.items.push((name, def.into()));
+            }
             AssocItem::MacroCall(call) => {
                 let file_id = self.expander.current_file_id();
                 let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
@@ -745,11 +743,8 @@ impl<'a> AssocItemCollector<'a> {
                     Ok(Some(call_id)) => {
                         let res =
                             self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
-                        self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
-                            ast_id: InFile::new(file_id, ast_id),
-                            expand_to: hir_expand::ExpandTo::Items,
-                            eager: None,
-                        });
+                        self.macro_calls.push((InFile::new(file_id, ast_id.upcast()), call_id));
+                        self.collect_macro_items(res);
                     }
                     Ok(None) => (),
                     Err(_) => {
@@ -768,39 +763,8 @@ impl<'a> AssocItemCollector<'a> {
         }
     }
 
-    fn collect_macro_items(
-        &mut self,
-        ExpandResult { value, err }: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>,
-        error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind,
-    ) {
-        let Some((mark, parse)) = value else { return };
-
-        if let Some(err) = err {
-            let diag = match err {
-                // why is this reported here?
-                hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
-                    DefDiagnostic::unresolved_proc_macro(
-                        self.module_id.local_id,
-                        error_call_kind(),
-                        krate,
-                    )
-                }
-                _ => DefDiagnostic::macro_error(
-                    self.module_id.local_id,
-                    error_call_kind(),
-                    err.to_string(),
-                ),
-            };
-            self.diagnostics.push(diag);
-        }
-        let errors = parse.errors();
-        if !errors.is_empty() {
-            self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
-                self.module_id.local_id,
-                error_call_kind(),
-                errors.into_boxed_slice(),
-            ));
-        }
+    fn collect_macro_items(&mut self, res: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>) {
+        let Some((mark, _parse)) = res.value else { return };
 
         let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
         let item_tree = tree_id.item_tree(self.db);
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 bf728a71079..4e57845a694 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
@@ -1177,6 +1177,8 @@ pub mod fmt {
 //- /main.rs crate:main deps:alloc,std
 #![no_std]
 
+extern crate alloc;
+
 $0
 
 //- /std.rs crate:std deps:alloc
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index acc60e1d9e4..10a1d65bb93 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -20,7 +20,7 @@ use triomphe::Arc;
 use crate::{
     db::DefDatabase,
     expander::Expander,
-    item_tree::{GenericsItemTreeNode, ItemTree},
+    item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
     type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
@@ -339,6 +339,7 @@ impl GenericParamsCollector {
         target: Either<TypeRef, LifetimeRef>,
     ) {
         let bound = TypeBound::from_ast(lower_ctx, bound);
+        self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
         let predicate = match (target, bound) {
             (Either::Left(type_ref), bound) => match hrtb_lifetimes {
                 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
@@ -359,7 +360,24 @@ impl GenericParamsCollector {
         self.where_predicates.push(predicate);
     }
 
-    pub(crate) fn fill_implicit_impl_trait_args(
+    fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
+        for bounds in impl_bounds {
+            let param = TypeParamData {
+                name: None,
+                default: None,
+                provenance: TypeParamProvenance::ArgumentImplTrait,
+            };
+            let param_id = self.type_or_consts.alloc(param.into());
+            for bound in bounds {
+                self.where_predicates.push(WherePredicate::TypeBound {
+                    target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
+                    bound,
+                });
+            }
+        }
+    }
+
+    fn fill_implicit_impl_trait_args(
         &mut self,
         db: &dyn DefDatabase,
         exp: &mut Lazy<(Arc<DefMap>, Expander), impl FnOnce() -> (Arc<DefMap>, Expander)>,
@@ -456,56 +474,67 @@ impl GenericParams {
         let cfg_options = &cfg_options[krate].cfg_options;
 
         // Returns the generic parameters that are enabled under the current `#[cfg]` options
-        let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
-            let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
-
-            // In the common case, no parameters will by disabled by `#[cfg]` attributes.
-            // Therefore, make a first pass to check if all parameters are enabled and, if so,
-            // clone the `Interned<GenericParams>` instead of recreating an identical copy.
-            let all_type_or_consts_enabled =
-                params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
-            let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
-
-            if all_type_or_consts_enabled && all_lifetimes_enabled {
-                params.clone()
-            } else {
-                Interned::new(GenericParams {
-                    type_or_consts: all_type_or_consts_enabled
-                        .then(|| params.type_or_consts.clone())
-                        .unwrap_or_else(|| {
-                            params
-                                .type_or_consts
-                                .iter()
-                                .filter(|(idx, _)| enabled((*idx).into()))
-                                .map(|(_, param)| param.clone())
-                                .collect()
-                        }),
-                    lifetimes: all_lifetimes_enabled
-                        .then(|| params.lifetimes.clone())
-                        .unwrap_or_else(|| {
-                            params
-                                .lifetimes
-                                .iter()
-                                .filter(|(idx, _)| enabled((*idx).into()))
-                                .map(|(_, param)| param.clone())
-                                .collect()
-                        }),
-                    where_predicates: params.where_predicates.clone(),
-                })
-            }
-        };
+        let enabled_params =
+            |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+                let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
+                let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
+                let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
+
+                // In the common case, no parameters will by disabled by `#[cfg]` attributes.
+                // Therefore, make a first pass to check if all parameters are enabled and, if so,
+                // clone the `Interned<GenericParams>` instead of recreating an identical copy.
+                let all_type_or_consts_enabled =
+                    params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
+                let all_lifetimes_enabled =
+                    params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
+
+                if all_type_or_consts_enabled && all_lifetimes_enabled {
+                    params.clone()
+                } else {
+                    Interned::new(GenericParams {
+                        type_or_consts: all_type_or_consts_enabled
+                            .then(|| params.type_or_consts.clone())
+                            .unwrap_or_else(|| {
+                                params
+                                    .type_or_consts
+                                    .iter()
+                                    .filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
+                                    .map(|(_, param)| param.clone())
+                                    .collect()
+                            }),
+                        lifetimes: all_lifetimes_enabled
+                            .then(|| params.lifetimes.clone())
+                            .unwrap_or_else(|| {
+                                params
+                                    .lifetimes
+                                    .iter()
+                                    .filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
+                                    .map(|(_, param)| param.clone())
+                                    .collect()
+                            }),
+                        where_predicates: params.where_predicates.clone(),
+                    })
+                }
+            };
         fn id_to_generics<Id: GenericsItemTreeNode>(
             db: &dyn DefDatabase,
             id: impl for<'db> Lookup<
                 Database<'db> = dyn DefDatabase + 'db,
                 Data = impl ItemTreeLoc<Id = Id>,
             >,
-            enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>,
-        ) -> Interned<GenericParams> {
+            enabled_params: impl Fn(
+                &Interned<GenericParams>,
+                &ItemTree,
+                GenericModItem,
+            ) -> Interned<GenericParams>,
+        ) -> Interned<GenericParams>
+        where
+            FileItemTreeId<Id>: Into<GenericModItem>,
+        {
             let id = id.lookup(db).item_tree_id();
             let tree = id.item_tree(db);
             let item = &tree[id.value];
-            enabled_params(item.generic_params(), &tree)
+            enabled_params(item.generic_params(), &tree, id.value.into())
         }
 
         match def {
@@ -514,7 +543,8 @@ impl GenericParams {
                 let tree = loc.id.item_tree(db);
                 let item = &tree[loc.id.value];
 
-                let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
+                let enabled_params =
+                    enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
 
                 let module = loc.container.module(db);
                 let func_data = db.function_data(id);
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 ac0caaf0dc8..2f7ebbfec13 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -136,15 +136,15 @@ impl From<ast::LiteralKind> for Literal {
                 Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
             }
             LiteralKind::ByteString(bs) => {
-                let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
+                let text = bs.value().map_or_else(|_| Default::default(), Box::from);
                 Literal::ByteString(text)
             }
             LiteralKind::String(s) => {
-                let text = s.value().map(Box::from).unwrap_or_else(Default::default);
+                let text = s.value().map_or_else(|_| Default::default(), Box::from);
                 Literal::String(text)
             }
             LiteralKind::CString(s) => {
-                let text = s.value().map(Box::from).unwrap_or_else(Default::default);
+                let text = s.value().map_or_else(|_| Default::default(), Box::from);
                 Literal::CString(text)
             }
             LiteralKind::Byte(b) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index a60b9f9f3ab..54cd57110ea 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -234,6 +234,14 @@ impl ItemScope {
         self.impls.iter().copied()
     }
 
+    pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
+        self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
+            self.derive_macros.values().flat_map(|it| {
+                it.iter().flat_map(|it| it.derive_call_ids.iter().copied().flatten())
+            }),
+        )
+    }
+
     pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
         self.types.values().copied().filter_map(|(def, vis, _)| match def {
             ModuleDefId::ModuleId(module) => Some((module, vis)),
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 610480736cc..acda64c41fb 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
@@ -29,6 +29,7 @@
 //!
 //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
 //! surface syntax.
+#![allow(unexpected_cfgs)]
 
 mod lower;
 mod pretty;
@@ -57,21 +58,21 @@ use triomphe::Arc;
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
+    generics::GenericParams,
     path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
     type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
     visibility::{RawVisibility, VisibilityExplicitness},
-    BlockId, Lookup,
+    BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
 };
 
 #[derive(Copy, Clone, Eq, PartialEq)]
 pub struct RawVisibilityId(u32);
 
 impl RawVisibilityId {
-    pub const PUB: Self = RawVisibilityId(u32::max_value());
-    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
-    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2);
-    pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3);
+    pub const PUB: Self = RawVisibilityId(u32::MAX);
+    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
+    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
+    pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
 }
 
 impl fmt::Debug for RawVisibilityId {
@@ -293,8 +294,8 @@ pub enum AttrOwner {
     Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
-    TypeOrConstParamData(Idx<TypeOrConstParamData>),
-    LifetimeParamData(Idx<LifetimeParamData>),
+    TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId),
+    LifetimeParamData(GenericModItem, LocalLifetimeParamId),
 }
 
 macro_rules! from_attrs {
@@ -314,8 +315,6 @@ from_attrs!(
     Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
-    TypeOrConstParamData(Idx<TypeOrConstParamData>),
-    LifetimeParamData(Idx<LifetimeParamData>),
 );
 
 /// Trait implemented by all nodes in the item tree.
@@ -465,12 +464,49 @@ macro_rules! mod_items {
             )+
         }
 
+        #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+        pub enum GenericModItem {
+            $(
+                $(
+                    #[cfg_attr(ignore_fragment, $generic_params)]
+                    $typ(FileItemTreeId<$typ>),
+                )?
+            )+
+        }
+
+        impl From<GenericModItem> for ModItem {
+            fn from(id: GenericModItem) -> ModItem {
+                match id {
+                    $(
+                        $(
+                            #[cfg_attr(ignore_fragment, $generic_params)]
+                            GenericModItem::$typ(id) => ModItem::$typ(id),
+                        )?
+                    )+
+                }
+            }
+        }
+
+        impl From<GenericModItem> for AttrOwner {
+            fn from(t: GenericModItem) -> AttrOwner {
+                AttrOwner::ModItem(t.into())
+            }
+        }
+
         $(
             impl From<FileItemTreeId<$typ>> for ModItem {
                 fn from(id: FileItemTreeId<$typ>) -> ModItem {
                     ModItem::$typ(id)
                 }
             }
+            $(
+                #[cfg_attr(ignore_fragment, $generic_params)]
+                impl From<FileItemTreeId<$typ>> for GenericModItem {
+                    fn from(id: FileItemTreeId<$typ>) -> GenericModItem {
+                        GenericModItem::$typ(id)
+                    }
+                }
+            )?
         )+
 
         $(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 4b5ef56d782..199b8daa37e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -4,6 +4,7 @@ use std::collections::hash_map::Entry;
 
 use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId};
 use la_arena::Arena;
+use rustc_hash::FxHashMap;
 use span::{AstIdMap, SyntaxContextId};
 use syntax::{
     ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
@@ -16,11 +17,11 @@ use crate::{
     generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
     item_tree::{
         AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId,
-        Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias,
-        Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod,
-        ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs,
-        RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union,
-        Use, UseTree, UseTreeKind, Variant,
+        Fields, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, IdxRange,
+        Impl, ImportAlias, Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall,
+        MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path,
+        Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias,
+        TypeAlias, Union, Use, UseTree, UseTreeKind, Variant,
     },
     path::AssociatedTypeBinding,
     type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
@@ -36,6 +37,8 @@ pub(super) struct Ctx<'a> {
     db: &'a dyn DefDatabase,
     tree: ItemTree,
     source_ast_id_map: Arc<AstIdMap>,
+    generic_param_attr_buffer:
+        FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
     body_ctx: crate::lower::LowerCtx<'a>,
 }
 
@@ -44,6 +47,7 @@ impl<'a> Ctx<'a> {
         Self {
             db,
             tree: ItemTree::default(),
+            generic_param_attr_buffer: FxHashMap::default(),
             source_ast_id_map: db.ast_id_map(file),
             body_ctx: crate::lower::LowerCtx::new(db, file),
         }
@@ -56,6 +60,7 @@ impl<'a> Ctx<'a> {
     pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
         self.tree.top_level =
             item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -89,6 +94,7 @@ impl<'a> Ctx<'a> {
             }
         }
 
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -117,6 +123,7 @@ impl<'a> Ctx<'a> {
             }
         }
 
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -185,10 +192,12 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
         let fields = self.lower_fields(&strukt.kind());
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
         let res = Struct { name, visibility, generic_params, fields, ast_id };
-        Some(id(self.data().structs.alloc(res)))
+        let id = id(self.data().structs.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
@@ -252,28 +261,32 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
         let fields = match union.record_field_list() {
             Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
             None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())),
         };
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
         let res = Union { name, visibility, generic_params, fields, ast_id };
-        Some(id(self.data().unions.alloc(res)))
+        let id = id(self.data().unions.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
         let visibility = self.lower_visibility(enum_);
         let name = enum_.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(enum_);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let variants = match &enum_.variant_list() {
             Some(variant_list) => self.lower_variants(variant_list),
             None => {
                 FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
             }
         };
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
-        Some(id(self.data().enums.alloc(res)))
+        let id = id(self.data().enums.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
@@ -414,7 +427,9 @@ impl<'a> Ctx<'a> {
             flags,
         };
 
-        Some(id(self.data().functions.alloc(res)))
+        let id = id(self.data().functions.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_type_alias(
@@ -428,7 +443,9 @@ impl<'a> Ctx<'a> {
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
         let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
         let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
-        Some(id(self.data().type_aliases.alloc(res)))
+        let id = id(self.data().type_aliases.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
@@ -475,8 +492,6 @@ impl<'a> Ctx<'a> {
         let name = trait_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_def);
-        let generic_params =
-            self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let is_auto = trait_def.auto_token().is_some();
         let is_unsafe = trait_def.unsafe_token().is_some();
 
@@ -487,8 +502,12 @@ impl<'a> Ctx<'a> {
             .filter_map(|item_node| self.lower_assoc_item(&item_node))
             .collect();
 
+        let generic_params =
+            self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
-        Some(id(self.data().traits.alloc(def)))
+        let id = id(self.data().traits.alloc(def));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_trait_alias(
@@ -504,19 +523,18 @@ impl<'a> Ctx<'a> {
         );
 
         let alias = TraitAlias { name, visibility, generic_params, ast_id };
-        Some(id(self.data().trait_aliases.alloc(alias)))
+        let id = id(self.data().trait_aliases.alloc(alias));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
-        // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
-        // type alias rather than a type parameter, so this is handled by the resolver.
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
         // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
         // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
         // equals itself.
-        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
         let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
+        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -527,9 +545,14 @@ impl<'a> Ctx<'a> {
             .flat_map(|it| it.assoc_items())
             .filter_map(|item| self.lower_assoc_item(&item))
             .collect();
+        // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
+        // type alias rather than a type parameter, so this is handled by the resolver.
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
         let res =
             Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
-        Some(id(self.data().impls.alloc(res)))
+        let id = id(self.data().impls.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@@ -616,11 +639,30 @@ impl<'a> Ctx<'a> {
         id(self.data().extern_blocks.alloc(res))
     }
 
+    fn write_generic_params_attributes(&mut self, parent: GenericModItem) {
+        self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| {
+            self.tree.attrs.insert(
+                match idx {
+                    Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id),
+                    Either::Right(id) => AttrOwner::LifetimeParamData(parent, id),
+                },
+                attrs,
+            );
+        })
+    }
+
     fn lower_generic_params(
         &mut self,
         has_implicit_self: HasImplicitSelf,
         node: &dyn ast::HasGenericParams,
     ) -> Interned<GenericParams> {
+        debug_assert!(self.generic_param_attr_buffer.is_empty(),);
+        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
+                               param| {
+            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
+            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
+        };
+        self.body_ctx.take_impl_traits_bounds();
         let mut generics = GenericParamsCollector::default();
 
         if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@@ -635,28 +677,13 @@ impl<'a> Ctx<'a> {
             );
             // add super traits as bounds on Self
             // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
-            let self_param = TypeRef::Path(name![Self].into());
-            generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
+            generics.fill_bounds(
+                &self.body_ctx,
+                bounds,
+                Either::Left(TypeRef::Path(name![Self].into())),
+            );
         }
 
-        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
-                               param| {
-            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
-            // This is identical to the body of `Ctx::add_attrs()` but we can't call that here
-            // because it requires `&mut self` and the call to `generics.fill()` below also
-            // references `self`.
-            match self.tree.attrs.entry(match item {
-                Either::Right(id) => id.into(),
-                Either::Left(id) => id.into(),
-            }) {
-                Entry::Occupied(mut entry) => {
-                    *entry.get_mut() = entry.get().merge(attrs);
-                }
-                Entry::Vacant(entry) => {
-                    entry.insert(attrs);
-                }
-            }
-        };
         generics.fill(&self.body_ctx, node, add_param_attrs);
 
         Interned::new(generics.finish())
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 cef2a3fb866..2803678a330 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
@@ -8,8 +8,8 @@ use crate::{
     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
     item_tree::{
         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields,
-        FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2,
-        MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
+        FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, Interned, ItemTree,
+        Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
         RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union,
         Use, UseTree, UseTreeKind, Variant,
     },
@@ -276,7 +276,7 @@ impl Printer<'_> {
                     w!(self, "extern \"{}\" ", abi);
                 }
                 w!(self, "fn {}", name.display(self.db.upcast()));
-                self.print_generic_params(explicit_generic_params);
+                self.print_generic_params(explicit_generic_params, it.into());
                 w!(self, "(");
                 if !params.is_empty() {
                     self.indented(|this| {
@@ -316,7 +316,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
@@ -329,7 +329,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
@@ -342,7 +342,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "enum {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for variant in FileItemTreeId::range_iter(variants.clone()) {
@@ -394,7 +394,7 @@ impl Printer<'_> {
                     w!(self, "auto ");
                 }
                 w!(self, "trait {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for item in &**items {
@@ -408,7 +408,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "trait {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 w!(self, " = ");
                 self.print_where_clause(generic_params);
                 w!(self, ";");
@@ -429,7 +429,7 @@ impl Printer<'_> {
                     w!(self, "unsafe");
                 }
                 w!(self, "impl");
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 w!(self, " ");
                 if *is_negative {
                     w!(self, "!");
@@ -453,7 +453,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 if !bounds.is_empty() {
                     w!(self, ": ");
                     self.print_type_bounds(bounds);
@@ -525,7 +525,7 @@ impl Printer<'_> {
         print_path(self.db, path, self).unwrap();
     }
 
-    fn print_generic_params(&mut self, params: &GenericParams) {
+    fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
         if params.is_empty() {
             return;
         }
@@ -537,7 +537,7 @@ impl Printer<'_> {
                 w!(self, ", ");
             }
             first = false;
-            self.print_attrs_of(idx, " ");
+            self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
             w!(self, "{}", lt.name.display(self.db.upcast()));
         }
         for (idx, x) in params.type_or_consts.iter() {
@@ -545,7 +545,7 @@ impl Printer<'_> {
                 w!(self, ", ");
             }
             first = false;
-            self.print_attrs_of(idx, " ");
+            self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
             match x {
                 TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
                     Some(name) => w!(self, "{}", name.display(self.db.upcast())),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 48da876ac15..79bab11998b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -427,10 +427,18 @@ fn generics_with_attributes() {
     check(
         r#"
 struct S<#[cfg(never)] T>;
+struct S<A, B, #[cfg(never)] C>;
+struct S<A, #[cfg(never)] B, C>;
         "#,
         expect![[r#"
             // AstId: 1
             pub(self) struct S<#[cfg(never)] T>;
+
+            // AstId: 2
+            pub(self) struct S<A, B, #[cfg(never)] C>;
+
+            // AstId: 3
+            pub(self) struct S<A, #[cfg(never)] B, C>;
         "#]],
     )
 }
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 d574d80a8e0..ecd8d79f20b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,26 +1,34 @@
 //! Context for lowering paths.
-use std::cell::OnceCell;
+use std::cell::{OnceCell, RefCell};
 
 use hir_expand::{
     span_map::{SpanMap, SpanMapRef},
     AstId, HirFileId, InFile,
 };
+use intern::Interned;
 use span::{AstIdMap, AstIdNode};
 use syntax::ast;
 use triomphe::Arc;
 
-use crate::{db::DefDatabase, path::Path};
+use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
 
 pub struct LowerCtx<'a> {
     pub db: &'a dyn DefDatabase,
     file_id: HirFileId,
     span_map: OnceCell<SpanMap>,
     ast_id_map: OnceCell<Arc<AstIdMap>>,
+    impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
 }
 
 impl<'a> LowerCtx<'a> {
     pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
-        LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() }
+        LowerCtx {
+            db,
+            file_id,
+            span_map: OnceCell::new(),
+            ast_id_map: OnceCell::new(),
+            impl_trait_bounds: RefCell::new(Vec::new()),
+        }
     }
 
     pub fn with_span_map_cell(
@@ -28,7 +36,13 @@ impl<'a> LowerCtx<'a> {
         file_id: HirFileId,
         span_map: OnceCell<SpanMap>,
     ) -> Self {
-        LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() }
+        LowerCtx {
+            db,
+            file_id,
+            span_map,
+            ast_id_map: OnceCell::new(),
+            impl_trait_bounds: RefCell::new(Vec::new()),
+        }
     }
 
     pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
@@ -45,4 +59,12 @@ impl<'a> LowerCtx<'a> {
             self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
         )
     }
+
+    pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
+        self.impl_trait_bounds.borrow_mut().push(bounds);
+    }
+
+    pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
+        self.impl_trait_bounds.take()
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index a4864c74d77..6f605c0cb33 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -186,3 +186,33 @@ fn#0:1@45..47#0# foo#0:1@48..51#0#(#0:1@51..52#0#&#0:1@52..53#0#self#0:1@53..57#
 }#0:1@76..77#0#"#]],
     );
 }
+
+#[test]
+fn attribute_macro_doc_desugaring() {
+    check(
+        r#"
+//- proc_macros: identity
+#[proc_macros::identity]
+/// doc string \n with newline
+/**
+     MultiLines Doc
+     MultiLines Doc
+*/
+#[doc = "doc attr"]
+struct S;
+"#,
+        expect![[r##"
+#[proc_macros::identity]
+/// doc string \n with newline
+/**
+     MultiLines Doc
+     MultiLines Doc
+*/
+#[doc = "doc attr"]
+struct S;
+
+#[doc = " doc string \\n with newline"]
+#[doc = "\n     MultiLines Doc\n     MultiLines Doc\n"]
+#[doc = "doc attr"] struct S;"##]],
+    );
+}
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 0a6cd0fe9ed..262bc538b94 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
@@ -5,7 +5,7 @@
 
 use std::{cmp::Ordering, iter, mem, ops::Not};
 
-use base_db::{CrateId, Dependency, FileId};
+use base_db::{CrateId, CrateOrigin, Dependency, FileId, LangCrateOrigin};
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
@@ -15,15 +15,13 @@ use hir_expand::{
     builtin_fn_macro::find_builtin_macro,
     name::{name, AsName, Name},
     proc_macro::CustomProcMacroExpander,
-    ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
-    MacroDefId, MacroDefKind,
+    ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
 use itertools::{izip, Itertools};
 use la_arena::Idx;
 use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
-use stdx::always;
 use syntax::ast;
 use triomphe::Arc;
 
@@ -279,7 +277,8 @@ impl DefCollector<'_> {
     fn seed_with_top_level(&mut self) {
         let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered();
 
-        let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
+        let crate_graph = self.db.crate_graph();
+        let file_id = crate_graph[self.def_map.krate].root_file_id;
         let item_tree = self.db.file_item_tree(file_id.into());
         let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
         let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
@@ -288,19 +287,14 @@ impl DefCollector<'_> {
             crate_data.proc_macro_loading_error = Some(e.clone());
         }
 
-        for (name, dep) in &self.deps {
-            if dep.is_prelude() {
-                crate_data
-                    .extern_prelude
-                    .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
-            }
-        }
+        let mut process = true;
 
         // Process other crate-level attributes.
         for attr in &*attrs {
             if let Some(cfg) = attr.cfg() {
                 if self.cfg_options.check(&cfg) == Some(false) {
-                    return;
+                    process = false;
+                    break;
                 }
             }
             let Some(attr_name) = attr.path.as_ident() else { continue };
@@ -350,9 +344,38 @@ impl DefCollector<'_> {
             }
         }
 
-        crate_data.shrink_to_fit();
+        for (name, dep) in &self.deps {
+            if dep.is_prelude() {
+                // This is a bit confusing but the gist is that `no_core` and `no_std` remove the
+                // sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly
+                // constructed with them in place no matter what though, since at that point we
+                // don't do pre-configured attribute resolution yet.
+                // So here check if we are no_core / no_std and we are trying to add the
+                // corresponding dep from the sysroot
+                let skip = match crate_graph[dep.crate_id].origin {
+                    CrateOrigin::Lang(LangCrateOrigin::Core) => {
+                        crate_data.no_core && dep.is_sysroot()
+                    }
+                    CrateOrigin::Lang(LangCrateOrigin::Std) => {
+                        crate_data.no_std && dep.is_sysroot()
+                    }
+                    _ => false,
+                };
+                if skip {
+                    continue;
+                }
+                crate_data
+                    .extern_prelude
+                    .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
+            }
+        }
+
         self.inject_prelude();
 
+        if !process {
+            return;
+        }
+
         ModCollector {
             def_collector: self,
             macro_depth: 0,
@@ -362,6 +385,7 @@ impl DefCollector<'_> {
             mod_dir: ModDir::root(),
         }
         .collect_in_top_module(item_tree.top_level_items());
+        Arc::get_mut(&mut self.def_map.data).unwrap().shrink_to_fit();
     }
 
     fn seed_with_inner(&mut self, tree_id: TreeId) {
@@ -519,15 +543,12 @@ impl DefCollector<'_> {
 
         let krate = if self.def_map.data.no_std {
             name![core]
+        } else if self.def_map.extern_prelude().any(|(name, _)| *name == name![std]) {
+            name![std]
         } else {
-            let std = name![std];
-            if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
-                std
-            } else {
-                // If `std` does not exist for some reason, fall back to core. This mostly helps
-                // keep r-a's own tests minimal.
-                name![core]
-            }
+            // If `std` does not exist for some reason, fall back to core. This mostly helps
+            // keep r-a's own tests minimal.
+            name![core]
         };
 
         let edition = match self.def_map.data.edition {
@@ -1389,31 +1410,6 @@ impl DefCollector<'_> {
         }
         let file_id = macro_call_id.as_file();
 
-        // First, fetch the raw expansion result for purposes of error reporting. This goes through
-        // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
-        // incrementality).
-        // FIXME: This kind of error fetching feels a bit odd?
-        let ExpandResult { value: errors, err } =
-            self.db.parse_macro_expansion_error(macro_call_id);
-        if let Some(err) = err {
-            let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
-            let diag = match err {
-                // why is this reported here?
-                hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
-                    always!(krate == loc.def.krate);
-                    DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
-                }
-                _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
-            };
-
-            self.def_map.diagnostics.push(diag);
-        }
-        if !errors.is_empty() {
-            let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
-            let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
-            self.def_map.diagnostics.push(diag);
-        }
-
         // Then, fetch and process the item tree. This will reuse the expansion result from above.
         let item_tree = self.db.file_item_tree(file_id);
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index 8c7fdaaf58b..523a4c107b3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -6,7 +6,7 @@ use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind};
 use la_arena::Idx;
-use syntax::{ast, SyntaxError};
+use syntax::ast;
 
 use crate::{
     item_tree::{self, ItemTreeId},
@@ -23,8 +23,6 @@ pub enum DefDiagnosticKind {
     UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
     UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
     UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
-    MacroError { ast: MacroCallKind, message: String },
-    MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> },
     UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
     InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
     MalformedDerive { ast: AstId<ast::Adt>, id: usize },
@@ -98,7 +96,7 @@ impl DefDiagnostic {
     // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
     // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
     // struct loses all that information!
-    pub(crate) fn unresolved_proc_macro(
+    pub fn unresolved_proc_macro(
         container: LocalModuleId,
         ast: MacroCallKind,
         krate: CrateId,
@@ -106,25 +104,6 @@ impl DefDiagnostic {
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
     }
 
-    pub(crate) fn macro_error(
-        container: LocalModuleId,
-        ast: MacroCallKind,
-        message: String,
-    ) -> Self {
-        Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } }
-    }
-
-    pub(crate) fn macro_expansion_parse_error(
-        container: LocalModuleId,
-        ast: MacroCallKind,
-        errors: Box<[SyntaxError]>,
-    ) -> Self {
-        Self {
-            in_module: container,
-            kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors },
-        }
-    }
-
     // FIXME: Whats the difference between this and unresolved_proc_macro
     pub(crate) fn unresolved_macro_call(
         container: LocalModuleId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index b3c41a073c6..6af52614111 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -208,6 +208,13 @@ pub(super) fn lower_generic_args(
                         .and_then(|args| lower_generic_args(lower_ctx, args))
                         .map(Interned::new);
                     let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
+                    let type_ref = type_ref.inspect(|tr| {
+                        tr.walk(&mut |tr| {
+                            if let TypeRef::ImplTrait(bounds) = tr {
+                                lower_ctx.update_impl_traits_bounds(bounds.clone());
+                            }
+                        });
+                    });
                     let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
                         l.bounds()
                             .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
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 fadab858aa1..1602b173858 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -1,5 +1,5 @@
 //! Name resolution façade.
-use std::{fmt, hash::BuildHasherDefault, mem};
+use std::{fmt, hash::BuildHasherDefault, iter, mem};
 
 use base_db::CrateId;
 use hir_expand::{
@@ -591,13 +591,13 @@ impl Resolver {
 
     pub fn where_predicates_in_scope(
         &self,
-    ) -> impl Iterator<Item = &crate::generics::WherePredicate> {
+    ) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
         self.scopes()
             .filter_map(|scope| match scope {
-                Scope::GenericParams { params, .. } => Some(params),
+                Scope::GenericParams { params, def } => Some((params, def)),
                 _ => None,
             })
-            .flat_map(|params| params.where_predicates.iter())
+            .flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def)))
     }
 
     pub fn generic_def(&self) -> Option<GenericDefId> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index f8bf88d83cd..85ec02ae073 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -5,7 +5,7 @@ use base_db::CrateId;
 use cfg::CfgExpr;
 use either::Either;
 use intern::Interned;
-use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
+use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct};
 use smallvec::{smallvec, SmallVec};
 use span::{Span, SyntaxContextId};
 use syntax::unescape;
@@ -239,7 +239,12 @@ impl Attr {
                 span,
             })))
         } else if let Some(tt) = ast.token_tree() {
-            let tree = syntax_node_to_token_tree(tt.syntax(), span_map, span);
+            let tree = syntax_node_to_token_tree(
+                tt.syntax(),
+                span_map,
+                span,
+                DocCommentDesugarMode::ProcMacro,
+            );
             Some(Interned::new(AttrInput::TokenTree(Box::new(tree))))
         } else {
             None
@@ -247,8 +252,18 @@ impl Attr {
         Some(Attr { id, path, input, ctxt: span.ctx })
     }
 
-    fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
-        let ctxt = tt.first()?.first_span().ctx;
+    fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
+        if matches!(tt,
+            [tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, .. })), ..]
+            if text == "unsafe"
+        ) {
+            match tt.get(1) {
+                Some(tt::TokenTree::Subtree(subtree)) => tt = &subtree.token_trees,
+                _ => return None,
+            }
+        }
+        let first = &tt.first()?;
+        let ctxt = first.first_span().ctx;
         let path_end = tt
             .iter()
             .position(|tt| {
@@ -430,7 +445,7 @@ fn inner_attributes(
 
 // Input subtree is: `(cfg, $(attr),+)`
 // Split it up into a `cfg` subtree and the `attr` subtrees.
-pub fn parse_cfg_attr_input(
+fn parse_cfg_attr_input(
     subtree: &Subtree,
 ) -> Option<(&[tt::TokenTree], impl Iterator<Item = &[tt::TokenTree]>)> {
     let mut parts = subtree
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
index 94681b42a9b..c7cdc5e9220 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
@@ -1,6 +1,7 @@
 //! Builtin derives.
 
 use itertools::izip;
+use mbe::DocCommentDesugarMode;
 use rustc_hash::FxHashSet;
 use span::{MacroCallId, Span};
 use stdx::never;
@@ -262,7 +263,12 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
                 match this {
                     Some(it) => {
                         param_type_set.insert(it.as_name());
-                        mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)
+                        mbe::syntax_node_to_token_tree(
+                            it.syntax(),
+                            tm,
+                            call_site,
+                            DocCommentDesugarMode::ProcMacro,
+                        )
                     }
                     None => {
                         tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
@@ -270,15 +276,27 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
                 }
             };
             let bounds = match &param {
-                ast::TypeOrConstParam::Type(it) => it
-                    .type_bound_list()
-                    .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)),
+                ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| {
+                    mbe::syntax_node_to_token_tree(
+                        it.syntax(),
+                        tm,
+                        call_site,
+                        DocCommentDesugarMode::ProcMacro,
+                    )
+                }),
                 ast::TypeOrConstParam::Const(_) => None,
             };
             let ty = if let ast::TypeOrConstParam::Const(param) = param {
                 let ty = param
                     .ty()
-                    .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax(), tm, call_site))
+                    .map(|ty| {
+                        mbe::syntax_node_to_token_tree(
+                            ty.syntax(),
+                            tm,
+                            call_site,
+                            DocCommentDesugarMode::ProcMacro,
+                        )
+                    })
                     .unwrap_or_else(|| {
                         tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
                     });
@@ -292,7 +310,14 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
 
     let where_clause = if let Some(w) = where_clause {
         w.predicates()
-            .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
+            .map(|it| {
+                mbe::syntax_node_to_token_tree(
+                    it.syntax(),
+                    tm,
+                    call_site,
+                    DocCommentDesugarMode::ProcMacro,
+                )
+            })
             .collect()
     } else {
         vec![]
@@ -322,7 +347,14 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
             let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name();
             param_type_set.contains(&name).then_some(p)
         })
-        .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
+        .map(|it| {
+            mbe::syntax_node_to_token_tree(
+                it.syntax(),
+                tm,
+                call_site,
+                DocCommentDesugarMode::ProcMacro,
+            )
+        })
         .collect();
     let name_token = name_to_token(tm, name)?;
     Ok(BasicAdtInfo { name: name_token, shape, param_types, where_clause, associated_types })
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 4d6fe6db396..ba96ab6cc2f 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
@@ -441,21 +441,21 @@ fn unquote_str(lit: &tt::Literal) -> Option<(String, Span)> {
     let span = lit.span;
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::String::cast(lit)?;
-    token.value().map(|it| (it.into_owned(), span))
+    token.value().ok().map(|it| (it.into_owned(), span))
 }
 
 fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> {
     let span = lit.span;
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::Char::cast(lit)?;
-    token.value().zip(Some(span))
+    token.value().ok().zip(Some(span))
 }
 
 fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec<u8>, Span)> {
     let span = lit.span;
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::ByteString::cast(lit)?;
-    token.value().map(|it| (it.into_owned(), span))
+    token.value().ok().map(|it| (it.into_owned(), span))
 }
 
 fn compile_error_expand(
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index d7233a8923f..2e5fa6131a7 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -3,7 +3,7 @@
 use base_db::{salsa, CrateId, FileId, SourceDatabase};
 use either::Either;
 use limit::Limit;
-use mbe::{syntax_node_to_token_tree, MatchedArmIndex};
+use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, MatchedArmIndex};
 use rustc_hash::FxHashSet;
 use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
 use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
@@ -132,7 +132,7 @@ pub trait ExpandDatabase: SourceDatabase {
     fn parse_macro_expansion_error(
         &self,
         macro_call: MacroCallId,
-    ) -> ExpandResult<Box<[SyntaxError]>>;
+    ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
 }
 
 /// This expands the given macro call, but with different arguments. This is
@@ -156,11 +156,25 @@ pub fn expand_speculative(
     // Build the subtree and token mapping for the speculative args
     let (mut tt, undo_info) = match loc.kind {
         MacroCallKind::FnLike { .. } => (
-            mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
+            mbe::syntax_node_to_token_tree(
+                speculative_args,
+                span_map,
+                span,
+                if loc.def.is_proc_macro() {
+                    DocCommentDesugarMode::ProcMacro
+                } else {
+                    DocCommentDesugarMode::Mbe
+                },
+            ),
             SyntaxFixupUndoInfo::NONE,
         ),
         MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
-            mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
+            mbe::syntax_node_to_token_tree(
+                speculative_args,
+                span_map,
+                span,
+                DocCommentDesugarMode::ProcMacro,
+            ),
             SyntaxFixupUndoInfo::NONE,
         ),
         MacroCallKind::Derive { derive_attr_index: index, .. }
@@ -176,7 +190,12 @@ pub fn expand_speculative(
 
             let censor_cfg =
                 cfg_process::process_cfg_attrs(db, speculative_args, &loc).unwrap_or_default();
-            let mut fixups = fixup::fixup_syntax(span_map, speculative_args, span);
+            let mut fixups = fixup::fixup_syntax(
+                span_map,
+                speculative_args,
+                span,
+                DocCommentDesugarMode::ProcMacro,
+            );
             fixups.append.retain(|it, _| match it {
                 syntax::NodeOrToken::Token(_) => true,
                 it => !censor.contains(it) && !censor_cfg.contains(it),
@@ -191,6 +210,7 @@ pub fn expand_speculative(
                     fixups.append,
                     fixups.remove,
                     span,
+                    DocCommentDesugarMode::ProcMacro,
                 ),
                 fixups.undo_info,
             )
@@ -212,7 +232,12 @@ pub fn expand_speculative(
             }?;
             match attr.token_tree() {
                 Some(token_tree) => {
-                    let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map, span);
+                    let mut tree = syntax_node_to_token_tree(
+                        token_tree.syntax(),
+                        span_map,
+                        span,
+                        DocCommentDesugarMode::ProcMacro,
+                    );
                     tree.delimiter = tt::Delimiter::invisible_spanned(span);
 
                     Some(tree)
@@ -332,9 +357,14 @@ fn parse_macro_expansion(
 fn parse_macro_expansion_error(
     db: &dyn ExpandDatabase,
     macro_call_id: MacroCallId,
-) -> ExpandResult<Box<[SyntaxError]>> {
-    db.parse_macro_expansion(MacroFileId { macro_call_id })
-        .map(|it| it.0.errors().into_boxed_slice())
+) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>> {
+    let e: ExpandResult<Arc<[SyntaxError]>> =
+        db.parse_macro_expansion(MacroFileId { macro_call_id }).map(|it| Arc::from(it.0.errors()));
+    if e.value.is_empty() && e.err.is_none() {
+        None
+    } else {
+        Some(Arc::new(e))
+    }
 }
 
 pub(crate) fn parse_with_map(
@@ -432,7 +462,16 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
                 return dummy_tt(kind);
             }
 
-            let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), span);
+            let mut tt = mbe::syntax_node_to_token_tree(
+                tt.syntax(),
+                map.as_ref(),
+                span,
+                if loc.def.is_proc_macro() {
+                    DocCommentDesugarMode::ProcMacro
+                } else {
+                    DocCommentDesugarMode::Mbe
+                },
+            );
             if loc.def.is_proc_macro() {
                 // proc macros expect their inputs without parentheses, MBEs expect it with them included
                 tt.delimiter.kind = tt::DelimiterKind::Invisible;
@@ -469,7 +508,8 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
     let (mut tt, undo_info) = {
         let syntax = item_node.syntax();
         let censor_cfg = cfg_process::process_cfg_attrs(db, syntax, &loc).unwrap_or_default();
-        let mut fixups = fixup::fixup_syntax(map.as_ref(), syntax, span);
+        let mut fixups =
+            fixup::fixup_syntax(map.as_ref(), syntax, span, DocCommentDesugarMode::ProcMacro);
         fixups.append.retain(|it, _| match it {
             syntax::NodeOrToken::Token(_) => true,
             it => !censor.contains(it) && !censor_cfg.contains(it),
@@ -484,6 +524,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
                 fixups.append,
                 fixups.remove,
                 span,
+                DocCommentDesugarMode::ProcMacro,
             ),
             fixups.undo_info,
         )
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
index 66465ce6005..7c3bf995b12 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
@@ -2,6 +2,7 @@
 use std::sync::OnceLock;
 
 use base_db::{CrateId, VersionReq};
+use mbe::DocCommentDesugarMode;
 use span::{Edition, MacroCallId, Span, SyntaxContextId};
 use stdx::TupleExt;
 use syntax::{ast, AstNode};
@@ -158,6 +159,7 @@ impl DeclarativeMacroExpander {
                             map.span_for_range(
                                 macro_rules.macro_rules_token().unwrap().text_range(),
                             ),
+                            DocCommentDesugarMode::Mbe,
                         );
 
                         mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars)
@@ -175,6 +177,7 @@ impl DeclarativeMacroExpander {
                             arg.syntax(),
                             map.as_ref(),
                             map.span_for_range(macro_def.macro_token().unwrap().text_range()),
+                            DocCommentDesugarMode::Mbe,
                         );
 
                         mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
index 8b147c88c13..64e04bc08f5 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
@@ -19,6 +19,7 @@
 //!
 //! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
 use base_db::CrateId;
+use mbe::DocCommentDesugarMode;
 use span::SyntaxContextId;
 use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent};
 use triomphe::Arc;
@@ -80,7 +81,12 @@ pub fn expand_eager_macro_input(
         return ExpandResult { value: None, err };
     };
 
-    let mut subtree = mbe::syntax_node_to_token_tree(&expanded_eager_input, arg_map, span);
+    let mut subtree = mbe::syntax_node_to_token_tree(
+        &expanded_eager_input,
+        arg_map,
+        span,
+        DocCommentDesugarMode::Mbe,
+    );
 
     subtree.delimiter.kind = crate::tt::DelimiterKind::Invisible;
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index 711acfeb3d8..9ec2a83162a 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -1,6 +1,7 @@
 //! To make attribute macros work reliably when typing, we need to take care to
 //! fix up syntax errors in the code we're passing to them.
 
+use mbe::DocCommentDesugarMode;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
 use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER};
@@ -49,6 +50,7 @@ pub(crate) fn fixup_syntax(
     span_map: SpanMapRef<'_>,
     node: &SyntaxNode,
     call_site: Span,
+    mode: DocCommentDesugarMode,
 ) -> SyntaxFixups {
     let mut append = FxHashMap::<SyntaxElement, _>::default();
     let mut remove = FxHashSet::<SyntaxElement>::default();
@@ -70,7 +72,7 @@ pub(crate) fn fixup_syntax(
         if can_handle_error(&node) && has_error_to_handle(&node) {
             remove.insert(node.clone().into());
             // the node contains an error node, we have to completely replace it by something valid
-            let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site);
+            let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site, mode);
             let idx = original.len() as u32;
             original.push(original_tree);
             let span = span_map.span_for_range(node_range);
@@ -360,6 +362,7 @@ fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
 mod tests {
     use base_db::FileId;
     use expect_test::{expect, Expect};
+    use mbe::DocCommentDesugarMode;
     use syntax::TextRange;
     use triomphe::Arc;
 
@@ -402,6 +405,7 @@ mod tests {
             span_map.as_ref(),
             &parsed.syntax_node(),
             span_map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::Mbe,
         );
         let mut tt = mbe::syntax_node_to_token_tree_modified(
             &parsed.syntax_node(),
@@ -409,6 +413,7 @@ mod tests {
             fixups.append,
             fixups.remove,
             span_map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::Mbe,
         );
 
         let actual = format!("{tt}\n");
@@ -436,6 +441,7 @@ mod tests {
             &parsed.syntax_node(),
             span_map.as_ref(),
             span_map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::Mbe,
         );
         assert!(
             check_subtree_eq(&tt, &original_as_tt),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 338bd25ede3..4ab989bec2f 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -132,13 +132,13 @@ pub enum ExpandError {
     MacroDefinition,
     Mbe(mbe::ExpandError),
     RecursionOverflow,
-    Other(Box<Box<str>>),
-    ProcMacroPanic(Box<Box<str>>),
+    Other(Arc<Box<str>>),
+    ProcMacroPanic(Arc<Box<str>>),
 }
 
 impl ExpandError {
     pub fn other(msg: impl Into<Box<str>>) -> Self {
-        ExpandError::Other(Box::new(msg.into()))
+        ExpandError::Other(Arc::new(msg.into()))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index abed16fecde..def2578b0e3 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -8,6 +8,7 @@ use rustc_hash::FxHashMap;
 use span::Span;
 use stdx::never;
 use syntax::SmolStr;
+use triomphe::Arc;
 
 use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
 
@@ -157,7 +158,7 @@ impl CustomProcMacroExpander {
                         ProcMacroExpansionError::System(text)
                         | ProcMacroExpansionError::Panic(text) => ExpandResult::new(
                             tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
-                            ExpandError::ProcMacroPanic(Box::new(text.into_boxed_str())),
+                            ExpandError::ProcMacroPanic(Arc::new(text.into_boxed_str())),
                         ),
                     },
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 46612242b09..84ac8740ecd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -806,7 +806,7 @@ pub(crate) fn impl_datum_query(
     krate: CrateId,
     impl_id: ImplId,
 ) -> Arc<ImplDatum> {
-    let _p = tracing::span!(tracing::Level::INFO, "impl_datum").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered();
     debug!("impl_datum {:?}", impl_id);
     let impl_: hir_def::ImplId = from_chalk(db, impl_id);
     impl_def_datum(db, krate, impl_id, impl_)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 0bf01b0bc6a..d99ef6679e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -27,6 +27,7 @@ pub trait TyExt {
     fn is_scalar(&self) -> bool;
     fn is_floating_point(&self) -> bool;
     fn is_never(&self) -> bool;
+    fn is_str(&self) -> bool;
     fn is_unknown(&self) -> bool;
     fn contains_unknown(&self) -> bool;
     fn is_ty_var(&self) -> bool;
@@ -87,6 +88,10 @@ impl TyExt for Ty {
         matches!(self.kind(Interner), TyKind::Never)
     }
 
+    fn is_str(&self) -> bool {
+        matches!(self.kind(Interner), TyKind::Str)
+    }
+
     fn is_unknown(&self) -> bool {
         matches!(self.kind(Interner), TyKind::Error)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index a357e850351..c010f5d22b6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -797,8 +797,20 @@ impl HirDisplay for Ty {
                 c.hir_fmt(f)?;
                 write!(f, "]")?;
             }
-            TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
-                if matches!(self.kind(Interner), TyKind::Raw(..)) {
+            kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => {
+                if let TyKind::Ref(_, l, _) = kind {
+                    f.write_char('&')?;
+                    if cfg!(test) {
+                        // rendering these unconditionally is probably too much (at least for inlay
+                        // hints) so we gate it to testing only for the time being
+                        l.hir_fmt(f)?;
+                        f.write_char(' ')?;
+                    }
+                    match m {
+                        Mutability::Not => (),
+                        Mutability::Mut => f.write_str("mut ")?,
+                    }
+                } else {
                     write!(
                         f,
                         "*{}",
@@ -807,15 +819,6 @@ impl HirDisplay for Ty {
                             Mutability::Mut => "mut ",
                         }
                     )?;
-                } else {
-                    write!(
-                        f,
-                        "&{}",
-                        match m {
-                            Mutability::Not => "",
-                            Mutability::Mut => "mut ",
-                        }
-                    )?;
                 }
 
                 // FIXME: all this just to decide whether to use parentheses...
@@ -1330,7 +1333,18 @@ fn hir_fmt_generics(
     }
 
     let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
-    if !parameters_to_write.is_empty() {
+
+    // FIXME: Remote this
+    // most of our lifetimes will be errors as we lack elision and inference
+    // so don't render them for now
+    let only_err_lifetimes = !cfg!(test)
+        && parameters_to_write.iter().all(|arg| {
+            matches!(
+                arg.data(Interner),
+                chalk_ir::GenericArgData::Lifetime(it) if *it.data(Interner) == LifetimeData::Error
+            )
+        });
+    if !parameters_to_write.is_empty() && !only_err_lifetimes {
         write!(f, "<")?;
         hir_fmt_generic_arguments(f, parameters_to_write)?;
         write!(f, ">")?;
@@ -1403,6 +1417,18 @@ fn hir_fmt_generic_arguments(
         None => (parameters, &[][..]),
     };
     for generic_arg in lifetimes.iter().chain(ty_or_const) {
+        // FIXME: Remove this
+        // most of our lifetimes will be errors as we lack elision and inference
+        // so don't render them for now
+        if !cfg!(test)
+            && matches!(
+                generic_arg.lifetime(Interner),
+                Some(l) if ***l.interned() == LifetimeData::Error
+            )
+        {
+            continue;
+        }
+
         if !first {
             write!(f, ", ")?;
         }
@@ -1728,9 +1754,9 @@ impl HirDisplay for LifetimeData {
             LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
             LifetimeData::InferenceVar(_) => write!(f, "_"),
             LifetimeData::Static => write!(f, "'static"),
-            LifetimeData::Error => write!(f, "'{{error}}"),
-            LifetimeData::Erased => Ok(()),
-            LifetimeData::Phantom(_, _) => Ok(()),
+            LifetimeData::Error => write!(f, "'?"),
+            LifetimeData::Erased => write!(f, "'<erased>"),
+            LifetimeData::Phantom(void, _) => match *void {},
         }
     }
 }
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 281386e1364..6f2f70dd40a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -198,6 +198,7 @@ pub enum InferenceDiagnostic {
     NoSuchField {
         field: ExprOrPatId,
         private: bool,
+        variant: VariantId,
     },
     PrivateField {
         expr: ExprId,
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 d011a62e77a..38076fce8f8 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
@@ -563,6 +563,7 @@ impl InferenceContext<'_> {
                                                 InferenceDiagnostic::NoSuchField {
                                                     field: field.expr.into(),
                                                     private: true,
+                                                    variant: def,
                                                 },
                                             );
                                         }
@@ -572,6 +573,7 @@ impl InferenceContext<'_> {
                                         self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                             field: field.expr.into(),
                                             private: false,
+                                            variant: def,
                                         });
                                         None
                                     }
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 1b354935a5b..dac5a5ea699 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
@@ -177,6 +177,7 @@ impl InferenceContext<'_> {
                                     self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                         field: inner.into(),
                                         private: true,
+                                        variant: def,
                                     });
                                 }
                                 let f = field_types[local_id].clone();
@@ -190,6 +191,7 @@ impl InferenceContext<'_> {
                                 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                     field: inner.into(),
                                     private: false,
+                                    variant: def,
                                 });
                                 self.err_ty()
                             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 4d0516ead67..04ace382021 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -345,51 +345,47 @@ impl<'a> TyLoweringContext<'a> {
                     }
                     ImplTraitLoweringState::Param(counter) => {
                         let idx = counter.get();
-                        // FIXME we're probably doing something wrong here
+                        // Count the number of `impl Trait` things that appear within our bounds.
+                        // Since t hose have been emitted as implicit type args already.
                         counter.set(idx + count_impl_traits(type_ref) as u16);
-                        if let Some(generics) = self.generics() {
-                            let param = generics
-                                .iter()
-                                .filter(|(_, data)| {
-                                    matches!(
-                                        data,
-                                        GenericParamDataRef::TypeParamData(data)
-                                        if data.provenance == TypeParamProvenance::ArgumentImplTrait
-                                    )
-                                })
-                                .nth(idx as usize)
-                                .map_or(TyKind::Error, |(id, _)| {
-                                    if let GenericParamId::TypeParamId(id) = id {
-                                        TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
-                                    } else {
-                                        // we just filtered them out
-                                        unreachable!("Unexpected lifetime or const argument");
-                                    }
-                                });
-                            param.intern(Interner)
-                        } else {
-                            TyKind::Error.intern(Interner)
-                        }
+                        let kind = self
+                            .generics()
+                            .expect("param impl trait lowering must be in a generic def")
+                            .iter()
+                            .filter_map(|(id, data)| match (id, data) {
+                                (
+                                    GenericParamId::TypeParamId(id),
+                                    GenericParamDataRef::TypeParamData(data),
+                                ) if data.provenance == TypeParamProvenance::ArgumentImplTrait => {
+                                    Some(id)
+                                }
+                                _ => None,
+                            })
+                            .nth(idx as usize)
+                            .map_or(TyKind::Error, |id| {
+                                TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
+                            });
+                        kind.intern(Interner)
                     }
                     ImplTraitLoweringState::Variable(counter) => {
                         let idx = counter.get();
-                        // FIXME we're probably doing something wrong here
+                        // Count the number of `impl Trait` things that appear within our bounds.
+                        // Since t hose have been emitted as implicit type args already.
                         counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
                             _parent_params,
                             self_params,
-                            list_params,
+                            type_params,
                             const_params,
                             _impl_trait_params,
                             _lifetime_params,
-                        ) = if let Some(generics) = self.generics() {
-                            generics.provenance_split()
-                        } else {
-                            (0, 0, 0, 0, 0, 0)
-                        };
+                        ) = self
+                            .generics()
+                            .expect("variable impl trait lowering must be in a generic def")
+                            .provenance_split();
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + self_params + list_params + const_params,
+                            idx as usize + self_params + type_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -1010,6 +1006,7 @@ impl<'a> TyLoweringContext<'a> {
     pub(crate) fn lower_where_predicate<'b>(
         &'b self,
         where_predicate: &'b WherePredicate,
+        &def: &GenericDefId,
         ignore_bindings: bool,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'b {
         match where_predicate {
@@ -1018,7 +1015,6 @@ impl<'a> TyLoweringContext<'a> {
                 let self_ty = match target {
                     WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
                     &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
-                        let def = self.resolver.generic_def().expect("generics in scope");
                         let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
                         match self.type_param_mode {
                             ParamLoweringMode::Placeholder => {
@@ -1056,23 +1052,7 @@ impl<'a> TyLoweringContext<'a> {
         let clause = match bound.as_ref() {
             TypeBound::Path(path, TraitBoundModifier::None) => {
                 trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
-                trait_ref
-                    .clone()
-                    .filter(|tr| {
-                        // ignore `T: Drop` or `T: Destruct` bounds.
-                        // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement.
-                        //   (So ideally, we'd only ignore `~const Drop` here)
-                        // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until
-                        //   the builtin impls are supported by Chalk, we ignore them here.
-                        if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) {
-                            if matches!(lang, LangItem::Drop | LangItem::Destruct) {
-                                return false;
-                            }
-                        }
-                        true
-                    })
-                    .map(WhereClause::Implemented)
-                    .map(crate::wrap_empty_binders)
+                trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
@@ -1166,84 +1146,77 @@ impl<'a> TyLoweringContext<'a> {
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = &binding.type_ref {
-                    if let (
-                        TypeRef::ImplTrait(bounds),
-                        ImplTraitLoweringState::Param(_)
-                        | ImplTraitLoweringState::Variable(_)
-                        | ImplTraitLoweringState::Disallowed,
-                    ) = (type_ref, &self.impl_trait_mode)
-                    {
-                        for bound in bounds {
-                            predicates.extend(
-                                self.lower_type_bound(
-                                    bound,
-                                    TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
-                                        .intern(Interner),
-                                    false,
-                                ),
-                            );
+                    match (type_ref, &self.impl_trait_mode) {
+                        (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
+                        (
+                            _,
+                            ImplTraitLoweringState::Disallowed | ImplTraitLoweringState::Opaque(_),
+                        ) => {
+                            let ty = self.lower_ty(type_ref);
+                            let alias_eq =
+                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                            predicates
+                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
                         }
-                    } else {
-                        let ty = 'ty: {
-                            if matches!(
-                                self.impl_trait_mode,
-                                ImplTraitLoweringState::Param(_)
-                                    | ImplTraitLoweringState::Variable(_)
-                            ) {
-                                // Find the generic index for the target of our `bound`
-                                let target_param_idx = self
-                                    .resolver
-                                    .where_predicates_in_scope()
-                                    .find_map(|p| match p {
-                                        WherePredicate::TypeBound {
-                                            target: WherePredicateTypeTarget::TypeOrConstParam(idx),
-                                            bound: b,
-                                        } if b == bound => Some(idx),
-                                        _ => None,
-                                    });
-                                if let Some(target_param_idx) = target_param_idx {
-                                    let mut counter = 0;
-                                    let generics = self.generics().expect("generics in scope");
-                                    for (idx, data) in generics.params.type_or_consts.iter() {
-                                        // Count the number of `impl Trait` things that appear before
-                                        // the target of our `bound`.
-                                        // Our counter within `impl_trait_mode` should be that number
-                                        // to properly lower each types within `type_ref`
-                                        if data.type_param().is_some_and(|p| {
-                                            p.provenance == TypeParamProvenance::ArgumentImplTrait
-                                        }) {
-                                            counter += 1;
-                                        }
-                                        if idx == *target_param_idx {
-                                            break;
-                                        }
+                        (
+                            _,
+                            ImplTraitLoweringState::Param(_) | ImplTraitLoweringState::Variable(_),
+                        ) => {
+                            // Find the generic index for the target of our `bound`
+                            let target_param_idx = self
+                                .resolver
+                                .where_predicates_in_scope()
+                                .find_map(|(p, _)| match p {
+                                    WherePredicate::TypeBound {
+                                        target: WherePredicateTypeTarget::TypeOrConstParam(idx),
+                                        bound: b,
+                                    } if b == bound => Some(idx),
+                                    _ => None,
+                                });
+                            let ty = if let Some(target_param_idx) = target_param_idx {
+                                let mut counter = 0;
+                                let generics = self.generics().expect("generics in scope");
+                                for (idx, data) in generics.params.type_or_consts.iter() {
+                                    // Count the number of `impl Trait` things that appear before
+                                    // the target of our `bound`.
+                                    // Our counter within `impl_trait_mode` should be that number
+                                    // to properly lower each types within `type_ref`
+                                    if data.type_param().is_some_and(|p| {
+                                        p.provenance == TypeParamProvenance::ArgumentImplTrait
+                                    }) {
+                                        counter += 1;
                                     }
-                                    let mut ext = TyLoweringContext::new_maybe_unowned(
-                                        self.db,
-                                        self.resolver,
-                                        self.owner,
-                                    )
-                                    .with_type_param_mode(self.type_param_mode);
-                                    match &self.impl_trait_mode {
-                                        ImplTraitLoweringState::Param(_) => {
-                                            ext.impl_trait_mode =
-                                                ImplTraitLoweringState::Param(Cell::new(counter));
-                                        }
-                                        ImplTraitLoweringState::Variable(_) => {
-                                            ext.impl_trait_mode = ImplTraitLoweringState::Variable(
-                                                Cell::new(counter),
-                                            );
-                                        }
-                                        _ => unreachable!(),
+                                    if idx == *target_param_idx {
+                                        break;
                                     }
-                                    break 'ty ext.lower_ty(type_ref);
                                 }
-                            }
-                            self.lower_ty(type_ref)
-                        };
-                        let alias_eq =
-                            AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
-                        predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                                let mut ext = TyLoweringContext::new_maybe_unowned(
+                                    self.db,
+                                    self.resolver,
+                                    self.owner,
+                                )
+                                .with_type_param_mode(self.type_param_mode);
+                                match &self.impl_trait_mode {
+                                    ImplTraitLoweringState::Param(_) => {
+                                        ext.impl_trait_mode =
+                                            ImplTraitLoweringState::Param(Cell::new(counter));
+                                    }
+                                    ImplTraitLoweringState::Variable(_) => {
+                                        ext.impl_trait_mode =
+                                            ImplTraitLoweringState::Variable(Cell::new(counter));
+                                    }
+                                    _ => unreachable!(),
+                                }
+                                ext.lower_ty(type_ref)
+                            } else {
+                                self.lower_ty(type_ref)
+                            };
+
+                            let alias_eq =
+                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                            predicates
+                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                        }
                     }
                 }
                 for bound in binding.bounds.iter() {
@@ -1338,11 +1311,10 @@ impl<'a> TyLoweringContext<'a> {
                 bounds,
                 lifetime: match lifetime {
                     Some(it) => match it.bound_var(Interner) {
-                        Some(bound_var) => LifetimeData::BoundVar(BoundVar::new(
-                            DebruijnIndex::INNERMOST,
-                            bound_var.index,
-                        ))
-                        .intern(Interner),
+                        Some(bound_var) => bound_var
+                            .shifted_out_to(DebruijnIndex::new(2))
+                            .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner))
+                            .unwrap_or(it),
                         None => it,
                     },
                     None => static_lifetime(),
@@ -1410,16 +1382,6 @@ impl<'a> TyLoweringContext<'a> {
     }
 }
 
-fn count_impl_traits(type_ref: &TypeRef) -> usize {
-    let mut count = 0;
-    type_ref.walk(&mut |type_ref| {
-        if matches!(type_ref, TypeRef::ImplTrait(_)) {
-            count += 1;
-        }
-    });
-    count
-}
-
 /// Build the signature of a callable item (function, struct or enum variant).
 pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
     match def {
@@ -1438,6 +1400,17 @@ pub fn associated_type_shorthand_candidates<R>(
     named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
 }
 
+// FIXME: This does not handle macros!
+fn count_impl_traits(type_ref: &TypeRef) -> usize {
+    let mut count = 0;
+    type_ref.walk(&mut |type_ref| {
+        if matches!(type_ref, TypeRef::ImplTrait(_)) {
+            count += 1;
+        }
+    });
+    count
+}
+
 fn named_associated_type_shorthand_candidates<R>(
     db: &dyn HirDatabase,
     // If the type parameter is defined in an impl and we're in a method, there
@@ -1575,7 +1548,7 @@ pub(crate) fn generic_predicates_for_param_query(
     let generics = generics(db.upcast(), def);
 
     // we have to filter out all other predicates *first*, before attempting to lower them
-    let predicate = |pred: &&_| match pred {
+    let predicate = |(pred, &def): &(&_, _)| match pred {
         WherePredicate::ForLifetime { target, bound, .. }
         | WherePredicate::TypeBound { target, bound, .. } => {
             let invalid_target = match target {
@@ -1617,8 +1590,8 @@ pub(crate) fn generic_predicates_for_param_query(
     let mut predicates: Vec<_> = resolver
         .where_predicates_in_scope()
         .filter(predicate)
-        .flat_map(|pred| {
-            ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
+        .flat_map(|(pred, def)| {
+            ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
         })
         .collect();
 
@@ -1671,8 +1644,8 @@ pub(crate) fn trait_environment_query(
     };
     let mut traits_in_scope = Vec::new();
     let mut clauses = Vec::new();
-    for pred in resolver.where_predicates_in_scope() {
-        for pred in ctx.lower_where_predicate(pred, false) {
+    for (pred, def) in resolver.where_predicates_in_scope() {
+        for pred in ctx.lower_where_predicate(pred, def, false) {
             if let WhereClause::Implemented(tr) = &pred.skip_binders() {
                 traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
             }
@@ -1726,8 +1699,8 @@ pub(crate) fn generic_predicates_query(
 
     let mut predicates = resolver
         .where_predicates_in_scope()
-        .flat_map(|pred| {
-            ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
+        .flat_map(|(pred, def)| {
+            ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
         })
         .collect::<Vec<_>>();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index cd723494713..cb56a6f0bfe 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -368,7 +368,7 @@ pub(crate) fn incoherent_inherent_impl_crates(
     krate: CrateId,
     fp: TyFingerprint,
 ) -> SmallVec<[CrateId; 2]> {
-    let _p = tracing::span!(tracing::Level::INFO, "inherent_impl_crates_query").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered();
     let mut res = SmallVec::new();
     let crate_graph = db.crate_graph();
 
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 045ffb418c8..2de1aa30c96 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
@@ -428,6 +428,17 @@ impl MirEvalError {
         }
         Ok(())
     }
+
+    pub fn is_panic(&self) -> Option<&str> {
+        let mut err = self;
+        while let MirEvalError::InFunction(e, _) = err {
+            err = e;
+        }
+        match err {
+            MirEvalError::Panic(msg) => Some(msg),
+            _ => None,
+        }
+    }
 }
 
 impl std::fmt::Debug for MirEvalError {
@@ -1138,7 +1149,7 @@ impl Evaluator<'_> {
                 let mut ty = self.operand_ty(lhs, locals)?;
                 while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
                     ty = z.clone();
-                    let size = if ty.kind(Interner) == &TyKind::Str {
+                    let size = if ty.is_str() {
                         if *op != BinOp::Eq {
                             never!("Only eq is builtin for `str`");
                         }
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 fee3dd3ada8..3438712049e 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
@@ -49,6 +49,7 @@ impl Evaluator<'_> {
         if self.not_special_fn_cache.borrow().contains(&def) {
             return Ok(false);
         }
+
         let function_data = self.db.function_data(def);
         let is_intrinsic = match &function_data.abi {
             Some(abi) => *abi == Interned::new_str("rust-intrinsic"),
@@ -131,9 +132,7 @@ impl Evaluator<'_> {
             return Ok(true);
         }
         if let Some(it) = self.detect_lang_function(def) {
-            let arg_bytes =
-                args.iter().map(|it| Ok(it.get(self)?.to_owned())).collect::<Result<Vec<_>>>()?;
-            let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?;
+            let result = self.exec_lang_item(it, generic_args, args, locals, span)?;
             destination.write_from_bytes(self, &result)?;
             return Ok(true);
         }
@@ -311,16 +310,20 @@ impl Evaluator<'_> {
 
     fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
         use LangItem::*;
-        let candidate = self.db.lang_attr(def.into())?;
+        let attrs = self.db.attrs(def.into());
+
+        if attrs.by_key("rustc_const_panic_str").exists() {
+            // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
+            return Some(LangItem::BeginPanic);
+        }
+
+        let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?;
         // We want to execute these functions with special logic
         // `PanicFmt` is not detected here as it's redirected later.
         if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
             return Some(candidate);
         }
-        if self.db.attrs(def.into()).by_key("rustc_const_panic_str").exists() {
-            // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
-            return Some(LangItem::BeginPanic);
-        }
+
         None
     }
 
@@ -328,18 +331,52 @@ impl Evaluator<'_> {
         &mut self,
         it: LangItem,
         generic_args: &Substitution,
-        args: &[Vec<u8>],
+        args: &[IntervalAndTy],
         locals: &Locals,
         span: MirSpan,
     ) -> Result<Vec<u8>> {
         use LangItem::*;
         let mut args = args.iter();
         match it {
-            BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_owned())),
+            BeginPanic => {
+                let mut arg = args
+                    .next()
+                    .ok_or(MirEvalError::InternalError(
+                        "argument of BeginPanic is not provided".into(),
+                    ))?
+                    .clone();
+                while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) {
+                    if ty.is_str() {
+                        let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size());
+                        let len = from_bytes!(usize, metadata);
+
+                        return {
+                            Err(MirEvalError::Panic(
+                                std::str::from_utf8(
+                                    self.read_memory(Address::from_bytes(pointee)?, len)?,
+                                )
+                                .unwrap()
+                                .to_owned(),
+                            ))
+                        };
+                    }
+                    let size = self.size_of_sized(ty, locals, "begin panic arg")?;
+                    let pointee = arg.interval.get(self)?;
+                    arg = IntervalAndTy {
+                        interval: Interval::new(Address::from_bytes(pointee)?, size),
+                        ty: ty.clone(),
+                    };
+                }
+                Err(MirEvalError::Panic(format!(
+                    "unknown-panic-payload: {:?}",
+                    arg.ty.kind(Interner)
+                )))
+            }
             SliceLen => {
                 let arg = args.next().ok_or(MirEvalError::InternalError(
                     "argument of <[T]>::len() is not provided".into(),
                 ))?;
+                let arg = arg.get(self)?;
                 let ptr_size = arg.len() / 2;
                 Ok(arg[ptr_size..].into())
             }
@@ -353,6 +390,7 @@ impl Evaluator<'_> {
                 let arg = args.next().ok_or(MirEvalError::InternalError(
                     "argument of drop_in_place is not provided".into(),
                 ))?;
+                let arg = arg.interval.get(self)?.to_owned();
                 self.run_drop_glue_deep(
                     ty.clone(),
                     locals,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 381522c9abe..4abbda56cbb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -31,6 +31,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
             db.trait_environment(func_id.into()),
         )
         .map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
+
     let (result, output) = interpret_mir(db, body, false, None);
     result?;
     Ok((output.stdout().into_owned(), output.stderr().into_owned()))
@@ -72,6 +73,13 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr
     }
 }
 
+fn check_panic(ra_fixture: &str, expected_panic: &str) {
+    let (db, file_ids) = TestDB::with_many_files(ra_fixture);
+    let file_id = *file_ids.last().unwrap();
+    let e = eval_main(&db, file_id).unwrap_err();
+    assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic);
+}
+
 #[test]
 fn function_with_extern_c_abi() {
     check_pass(
@@ -88,6 +96,43 @@ fn main() {
 }
 
 #[test]
+fn panic_fmt() {
+    // panic!
+    // -> panic_2021 (builtin macro redirection)
+    //   -> #[lang = "panic_fmt"] core::panicking::panic_fmt (hooked by CTFE for redirection)
+    //   -> core::panicking::const_panic_fmt
+    //     -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
+    //       -> Err(ConstEvalError::Panic)
+    check_panic(
+        r#"
+//- minicore: fmt, panic
+fn main() {
+    panic!("hello, world!");
+}
+    "#,
+        "hello, world!",
+    );
+}
+
+#[test]
+fn panic_display() {
+    // panic!
+    // -> panic_2021 (builtin macro redirection)
+    //   -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
+    //     -> Err(ConstEvalError::Panic)
+    check_panic(
+        r#"
+//- minicore: fmt, panic
+
+fn main() {
+    panic!("{}", "hello, world!");
+}
+    "#,
+        "hello, world!",
+    );
+}
+
+#[test]
 fn drop_basic() {
     check_pass(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index d56b15b9b74..526db2af6dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -186,7 +186,7 @@ fn test() {
     let x = match 1 {
         1 => t as *mut i32,
         2 => t as &i32,
-           //^^^^^^^^^ expected *mut i32, got &i32
+           //^^^^^^^^^ expected *mut i32, got &'? i32
         _ => t as *const i32,
           // ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
 
@@ -307,7 +307,7 @@ fn test() {
     let foo = Foo;
       //^^^ type: Foo<{unknown}>
     let _: &u32 = &Foo;
-                //^^^^ expected &u32, got &Foo<{unknown}>
+                //^^^^ expected &'? u32, got &'? Foo<{unknown}>
 }",
     );
 }
@@ -544,9 +544,9 @@ struct Bar<T>(Foo<T>);
 
 fn test() {
     let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
-                         //^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]>
+                         //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]>
     let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
-                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
+                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]>
 }
 "#,
     );
@@ -562,7 +562,7 @@ trait Foo {}
 fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
     let _: &dyn Foo = &f;
     let _: &dyn Foo = g;
-                    //^ expected &dyn Foo, got &impl Foo + ?Sized
+                    //^ expected &'? dyn Foo, got &'? impl Foo + ?Sized
 }
         "#,
     );
@@ -828,11 +828,11 @@ struct V<T> { t: T }
 fn main() {
     let a: V<&dyn Tr>;
     (a,) = V { t: &S };
-  //^^^^expected V<&S>, got (V<&dyn Tr>,)
+  //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
 
     let mut a: V<&dyn Tr> = V { t: &S };
     (a,) = V { t: &S };
-  //^^^^expected V<&S>, got (V<&dyn Tr>,)
+  //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
 }
         "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
index 119de7f050e..def06f2d59d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
@@ -8,7 +8,7 @@ fn function_return_type_mismatch_1() {
         r#"
 fn test() -> &'static str {
     5
-  //^ expected &str, got i32
+  //^ expected &'static str, got i32
 }
 "#,
     );
@@ -21,7 +21,7 @@ fn function_return_type_mismatch_2() {
 fn test(x: bool) -> &'static str {
     if x {
         return 1;
-             //^ expected &str, got i32
+             //^ expected &'static str, got i32
     }
     "ok"
 }
@@ -38,7 +38,7 @@ fn test(x: bool) -> &'static str {
         return "ok";
     }
     1
-  //^ expected &str, got i32
+  //^ expected &'static str, got i32
 }
 "#,
     );
@@ -53,7 +53,7 @@ fn test(x: bool) -> &'static str {
         "ok"
     } else {
         1
-      //^ expected &str, got i32
+      //^ expected &'static str, got i32
     }
 }
 "#,
@@ -67,7 +67,7 @@ fn function_return_type_mismatch_5() {
 fn test(x: bool) -> &'static str {
     if x {
         1
-      //^ expected &str, got i32
+      //^ expected &'static str, got i32
     } else {
         "ok"
     }
@@ -83,10 +83,10 @@ fn non_unit_block_expr_stmt_no_semi() {
 fn test(x: bool) {
     if x {
         "notok"
-      //^^^^^^^ expected (), got &str
+      //^^^^^^^ expected (), got &'static str
     } else {
         "ok"
-      //^^^^ expected (), got &str
+      //^^^^ expected (), got &'static str
     }
     match x { true => true, false => 0 }
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), got bool
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index e8369caa771..60c03b52246 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -67,11 +67,11 @@ trait B: A {}
 
 fn test(
     _: &(dyn A<Assoc = ()> + Send),
-  //^ &(dyn A<Assoc = ()> + Send)
+  //^ &'_ (dyn A<Assoc = ()> + Send)
     _: &(dyn Send + A<Assoc = ()>),
-  //^ &(dyn A<Assoc = ()> + Send)
+  //^ &'_ (dyn A<Assoc = ()> + Send)
     _: &dyn B<Assoc = ()>,
-  //^ &(dyn B<Assoc = ()>)
+  //^ &'_ (dyn B<Assoc = ()>)
 ) {}
         "#,
     );
@@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
 trait Foo<'a> {}
 
 fn foo(foo: &dyn for<'a> Foo<'a>) {}
-    // ^^^ &dyn Foo<'_>
+    // ^^^ &'_ dyn Foo<'_>
 "#,
     );
 }
@@ -111,11 +111,11 @@ fn test(
     b;
   //^ impl Foo
     c;
-  //^ &impl Foo + ?Sized
+  //^ &'_ impl Foo + ?Sized
     d;
   //^ S<impl Foo>
     ref_any;
-  //^^^^^^^ &impl ?Sized
+  //^^^^^^^ &'_ impl ?Sized
     empty;
 } //^^^^^ impl Sized
 "#,
@@ -192,7 +192,7 @@ fn test(
     b;
   //^ fn(impl Foo) -> impl Foo
     c;
-} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
+} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index 2f75338f994..a0899cb1d63 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -200,8 +200,8 @@ fn expr_macro_def_expanded_in_various_places() {
             100..119 'for _ ...!() {}': IntoIterator::IntoIter<isize>
             100..119 'for _ ...!() {}': !
             100..119 'for _ ...!() {}': IntoIterator::IntoIter<isize>
-            100..119 'for _ ...!() {}': &mut IntoIterator::IntoIter<isize>
-            100..119 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
+            100..119 'for _ ...!() {}': &'? mut IntoIterator::IntoIter<isize>
+            100..119 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&'? mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
             100..119 'for _ ...!() {}': Option<IntoIterator::Item<isize>>
             100..119 'for _ ...!() {}': ()
             100..119 'for _ ...!() {}': ()
@@ -221,7 +221,7 @@ fn expr_macro_def_expanded_in_various_places() {
             281..303 'Spam {...m!() }': {unknown}
             309..325 'spam!(...am!()]': {unknown}
             350..366 'spam!(... usize': usize
-            372..380 '&spam!()': &isize
+            372..380 '&spam!()': &'? isize
             386..394 '-spam!()': isize
             400..416 'spam!(...pam!()': {unknown}
             422..439 'spam!(...pam!()': isize
@@ -293,8 +293,8 @@ fn expr_macro_rules_expanded_in_various_places() {
             114..133 'for _ ...!() {}': IntoIterator::IntoIter<isize>
             114..133 'for _ ...!() {}': !
             114..133 'for _ ...!() {}': IntoIterator::IntoIter<isize>
-            114..133 'for _ ...!() {}': &mut IntoIterator::IntoIter<isize>
-            114..133 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
+            114..133 'for _ ...!() {}': &'? mut IntoIterator::IntoIter<isize>
+            114..133 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&'? mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
             114..133 'for _ ...!() {}': Option<IntoIterator::Item<isize>>
             114..133 'for _ ...!() {}': ()
             114..133 'for _ ...!() {}': ()
@@ -314,7 +314,7 @@ fn expr_macro_rules_expanded_in_various_places() {
             295..317 'Spam {...m!() }': {unknown}
             323..339 'spam!(...am!()]': {unknown}
             364..380 'spam!(... usize': usize
-            386..394 '&spam!()': &isize
+            386..394 '&spam!()': &'? isize
             400..408 '-spam!()': isize
             414..430 'spam!(...pam!()': {unknown}
             436..453 'spam!(...pam!()': isize
@@ -539,7 +539,7 @@ fn test() {
     let msg = foo::Message(foo::MessageRef);
     let r = msg.deref();
     r;
-  //^ &MessageRef
+  //^ &'? MessageRef
 }
 
 //- /lib.rs crate:foo
@@ -703,9 +703,9 @@ fn infer_builtin_macros_file() {
         }
         "#,
         expect![[r#"
-            !0..2 '""': &str
+            !0..2 '""': &'static str
             63..87 '{     ...!(); }': ()
-            73..74 'x': &str
+            73..74 'x': &'static str
         "#]],
     );
 }
@@ -741,9 +741,9 @@ fn infer_builtin_macros_concat() {
         }
         "#,
         expect![[r#"
-            !0..13 '"helloworld!"': &str
+            !0..13 '"helloworld!"': &'static str
             65..121 '{     ...")); }': ()
-            75..76 'x': &str
+            75..76 'x': &'static str
         "#]],
     );
 }
@@ -820,7 +820,7 @@ macro_rules! include_str {() => {}}
 fn main() {
     let a = include_str!("foo.rs");
     a;
-} //^ &str
+} //^ &'static str
 
 //- /foo.rs
 hello
@@ -847,7 +847,7 @@ macro_rules! m {
 fn main() {
     let a = include_str!(m!(".rs"));
     a;
-} //^ &str
+} //^ &'static str
 
 //- /foo.rs
 hello
@@ -960,9 +960,9 @@ fn infer_builtin_macros_concat_with_lazy() {
         }
         "#,
         expect![[r#"
-            !0..13 '"helloworld!"': &str
+            !0..13 '"helloworld!"': &'static str
             103..160 '{     ...")); }': ()
-            113..114 'x': &str
+            113..114 'x': &'static str
         "#]],
     );
 }
@@ -977,7 +977,7 @@ fn infer_builtin_macros_env() {
 
         fn main() {
             let x = env!("foo");
-              //^ &str
+              //^ &'static str
         }
         "#,
     );
@@ -991,7 +991,7 @@ fn infer_builtin_macros_option_env() {
 //- /main.rs env:foo=bar
 fn main() {
     let x = option_env!("foo");
-      //^ Option<&str>
+      //^ Option<&'static str>
 }
         "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 8609ba41039..63a83d403fa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -658,7 +658,7 @@ fn infer_call_trait_method_on_generic_param_1() {
         }
         "#,
         expect![[r#"
-            29..33 'self': &Self
+            29..33 'self': &'? Self
             63..64 't': T
             69..88 '{     ...d(); }': ()
             75..76 't': T
@@ -679,7 +679,7 @@ fn infer_call_trait_method_on_generic_param_2() {
         }
         "#,
         expect![[r#"
-            32..36 'self': &Self
+            32..36 'self': &'? Self
             70..71 't': T
             76..95 '{     ...d(); }': ()
             82..83 't': T
@@ -757,7 +757,7 @@ struct S;
 impl Clone for S {}
 impl Clone for &S {}
 fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
-          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
+          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &'? S)
 "#,
     );
 }
@@ -1150,12 +1150,12 @@ fn dyn_trait_super_trait_not_in_scope() {
         }
         "#,
         expect![[r#"
-            51..55 'self': &Self
+            51..55 'self': &'? Self
             64..69 '{ 0 }': u32
             66..67 '0': u32
-            176..177 'd': &dyn Trait
+            176..177 'd': &'? dyn Trait
             191..207 '{     ...o(); }': ()
-            197..198 'd': &dyn Trait
+            197..198 'd': &'? dyn Trait
             197..204 'd.foo()': u32
         "#]],
     );
@@ -1182,15 +1182,15 @@ fn test() {
 }
 "#,
         expect![[r#"
-            75..79 'self': &S
+            75..79 'self': &'? S
             89..109 '{     ...     }': bool
             99..103 'true': bool
             123..167 '{     ...o(); }': ()
-            133..134 's': &S
-            137..151 'unsafe { f() }': &S
-            146..147 'f': fn f() -> &S
-            146..149 'f()': &S
-            157..158 's': &S
+            133..134 's': &'? S
+            137..151 'unsafe { f() }': &'static S
+            146..147 'f': fn f() -> &'static S
+            146..149 'f()': &'static S
+            157..158 's': &'? S
             157..164 's.foo()': bool
         "#]],
     );
@@ -1601,11 +1601,11 @@ use core::IntoIterator;
 fn f() {
     let v = [4].into_iter();
     v;
-  //^ &i32
+  //^ &'? i32
 
     let a = [0, 1].into_iter();
     a;
-  //^ &i32
+  //^ &'? i32
 }
 
 //- /main2021.rs crate:main2021 deps:core edition:2021
@@ -1618,7 +1618,7 @@ fn f() {
 
     let a = [0, 1].into_iter();
     a;
-  //^ &i32
+  //^ &'? i32
 }
 
 //- /core.rs crate:core
@@ -1767,7 +1767,7 @@ fn test() {
     let a2 = A(make(), 1i32);
     let _: &str = a2.thing();
     a2;
-  //^^ A<C<&str>, i32>
+  //^^ A<C<&'? str>, i32>
 }
 "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
index 5d809b82392..0ccbcf63e2b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
@@ -104,7 +104,7 @@ enum Option<T> { None, Some(T) }
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
     a;
-  //^ Option<&str>
+  //^ Option<&'static str>
     match 42 {
         42 => a,
         _ => Option::Some("str"),
@@ -317,8 +317,8 @@ fn diverging_expression_2() {
             63..81 '{ loop...foo" }': u32
             65..72 'loop {}': !
             70..72 '{}': ()
-            74..79 '"foo"': &str
-            74..79: expected u32, got &str
+            74..79 '"foo"': &'static str
+            74..79: expected u32, got &'static str
         "#]],
     );
 }
@@ -365,8 +365,8 @@ fn diverging_expression_3_break() {
             151..172 'for a ...eak; }': {unknown}
             151..172 'for a ...eak; }': !
             151..172 'for a ...eak; }': {unknown}
-            151..172 'for a ...eak; }': &mut {unknown}
-            151..172 'for a ...eak; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            151..172 'for a ...eak; }': &'? mut {unknown}
+            151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             151..172 'for a ...eak; }': Option<{unknown}>
             151..172 'for a ...eak; }': ()
             151..172 'for a ...eak; }': ()
@@ -381,8 +381,8 @@ fn diverging_expression_3_break() {
             237..250 'for a in b {}': {unknown}
             237..250 'for a in b {}': !
             237..250 'for a in b {}': {unknown}
-            237..250 'for a in b {}': &mut {unknown}
-            237..250 'for a in b {}': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            237..250 'for a in b {}': &'? mut {unknown}
+            237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             237..250 'for a in b {}': Option<{unknown}>
             237..250 'for a in b {}': ()
             237..250 'for a in b {}': ()
@@ -396,8 +396,8 @@ fn diverging_expression_3_break() {
             315..337 'for a ...urn; }': {unknown}
             315..337 'for a ...urn; }': !
             315..337 'for a ...urn; }': {unknown}
-            315..337 'for a ...urn; }': &mut {unknown}
-            315..337 'for a ...urn; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            315..337 'for a ...urn; }': &'? mut {unknown}
+            315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             315..337 'for a ...urn; }': Option<{unknown}>
             315..337 'for a ...urn; }': ()
             315..337 'for a ...urn; }': ()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index 4355881d729..5e040a60e29 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -32,27 +32,27 @@ fn infer_pattern() {
         }
         "#,
         expect![[r#"
-            8..9 'x': &i32
+            8..9 'x': &'? i32
             17..400 '{     ...o_x; }': ()
-            27..28 'y': &i32
-            31..32 'x': &i32
-            42..44 '&z': &i32
+            27..28 'y': &'? i32
+            31..32 'x': &'? i32
+            42..44 '&z': &'? i32
             43..44 'z': i32
-            47..48 'x': &i32
+            47..48 'x': &'? i32
             58..59 'a': i32
             62..63 'z': i32
-            73..79 '(c, d)': (i32, &str)
+            73..79 '(c, d)': (i32, &'static str)
             74..75 'c': i32
-            77..78 'd': &str
-            82..94 '(1, "hello")': (i32, &str)
+            77..78 'd': &'static str
+            82..94 '(1, "hello")': (i32, &'static str)
             83..84 '1': i32
-            86..93 '"hello"': &str
+            86..93 '"hello"': &'static str
             101..151 'for (e...     }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
             101..151 'for (e...     }': {unknown}
             101..151 'for (e...     }': !
             101..151 'for (e...     }': {unknown}
-            101..151 'for (e...     }': &mut {unknown}
-            101..151 'for (e...     }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            101..151 'for (e...     }': &'? mut {unknown}
+            101..151 'for (e...     }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             101..151 'for (e...     }': Option<({unknown}, {unknown})>
             101..151 'for (e...     }': ()
             101..151 'for (e...     }': ()
@@ -74,10 +74,10 @@ fn infer_pattern() {
             194..197 'val': {unknown}
             210..236 'if let...rue {}': ()
             213..233 'let x ... &true': bool
-            217..225 'x @ true': &bool
+            217..225 'x @ true': &'? bool
             221..225 'true': bool
             221..225 'true': bool
-            228..233 '&true': &bool
+            228..233 '&true': &'? bool
             229..233 'true': bool
             234..236 '{}': ()
             246..252 'lambda': impl Fn(u64, u64, i32) -> i32
@@ -90,14 +90,14 @@ fn infer_pattern() {
             277..282 'a + b': u64
             281..282 'b': u64
             284..285 'c': i32
-            298..310 'ref ref_to_x': &&i32
-            313..314 'x': &i32
-            324..333 'mut mut_x': &i32
-            336..337 'x': &i32
-            347..367 'ref mu...f_to_x': &mut &i32
-            370..371 'x': &i32
-            381..382 'k': &mut &i32
-            385..397 'mut_ref_to_x': &mut &i32
+            298..310 'ref ref_to_x': &'? &'? i32
+            313..314 'x': &'? i32
+            324..333 'mut mut_x': &'? i32
+            336..337 'x': &'? i32
+            347..367 'ref mu...f_to_x': &'? mut &'? i32
+            370..371 'x': &'? i32
+            381..382 'k': &'? mut &'? i32
+            385..397 'mut_ref_to_x': &'? mut &'? i32
         "#]],
     );
 }
@@ -120,14 +120,14 @@ fn infer_literal_pattern() {
             17..28 '{ loop {} }': T
             19..26 'loop {}': !
             24..26 '{}': ()
-            37..38 'x': &i32
+            37..38 'x': &'? i32
             46..208 '{     ...) {} }': ()
             52..75 'if let...y() {}': ()
             55..72 'let "f... any()': bool
-            59..64 '"foo"': &str
-            59..64 '"foo"': &str
-            67..70 'any': fn any<&str>() -> &str
-            67..72 'any()': &str
+            59..64 '"foo"': &'static str
+            59..64 '"foo"': &'static str
+            67..70 'any': fn any<&'static str>() -> &'static str
+            67..72 'any()': &'static str
             73..75 '{}': ()
             80..99 'if let...y() {}': ()
             83..96 'let 1 = any()': bool
@@ -178,7 +178,7 @@ fn infer_range_pattern() {
         }
         "#,
         expect![[r#"
-            8..9 'x': &i32
+            8..9 'x': &'? i32
             17..75 '{     ...2 {} }': ()
             23..45 'if let...u32 {}': ()
             26..42 'let 1....= 2u32': bool
@@ -208,14 +208,14 @@ fn infer_pattern_match_ergonomics() {
         expect![[r#"
             27..78 '{     ...(1); }': ()
             37..41 'A(n)': A<i32>
-            39..40 'n': &i32
-            44..49 '&A(1)': &A<i32>
+            39..40 'n': &'? i32
+            44..49 '&A(1)': &'? A<i32>
             45..46 'A': extern "rust-call" A<i32>(i32) -> A<i32>
             45..49 'A(1)': A<i32>
             47..48 '1': i32
             59..63 'A(n)': A<i32>
-            61..62 'n': &mut i32
-            66..75 '&mut A(1)': &mut A<i32>
+            61..62 'n': &'? mut i32
+            66..75 '&mut A(1)': &'? mut A<i32>
             71..72 'A': extern "rust-call" A<i32>(i32) -> A<i32>
             71..75 'A(1)': A<i32>
             73..74 '1': i32
@@ -235,17 +235,17 @@ fn infer_pattern_match_ergonomics_ref() {
         "#,
         expect![[r#"
             10..56 '{     ...= v; }': ()
-            20..21 'v': &(i32, &i32)
-            24..32 '&(1, &2)': &(i32, &i32)
-            25..32 '(1, &2)': (i32, &i32)
+            20..21 'v': &'? (i32, &'? i32)
+            24..32 '&(1, &2)': &'? (i32, &'? i32)
+            25..32 '(1, &2)': (i32, &'? i32)
             26..27 '1': i32
-            29..31 '&2': &i32
+            29..31 '&2': &'? i32
             30..31 '2': i32
-            42..49 '(_, &w)': (i32, &i32)
+            42..49 '(_, &w)': (i32, &'? i32)
             43..44 '_': i32
-            46..48 '&w': &i32
+            46..48 '&w': &'? i32
             47..48 'w': i32
-            52..53 'v': &(i32, &i32)
+            52..53 'v': &'? (i32, &'? i32)
         "#]],
     );
 }
@@ -286,28 +286,28 @@ fn infer_pattern_match_slice() {
         "#,
         expect![[r#"
             10..209 '{     ...   } }': ()
-            20..25 'slice': &[f64]
-            36..42 '&[0.0]': &[f64; 1]
+            20..25 'slice': &'? [f64]
+            36..42 '&[0.0]': &'? [f64; 1]
             37..42 '[0.0]': [f64; 1]
             38..41 '0.0': f64
             48..207 'match ...     }': ()
-            54..59 'slice': &[f64]
-            70..73 '&[]': &[f64]
+            54..59 'slice': &'? [f64]
+            70..73 '&[]': &'? [f64]
             71..73 '[]': [f64]
             77..79 '{}': ()
-            89..93 '&[a]': &[f64]
+            89..93 '&[a]': &'? [f64]
             90..93 '[a]': [f64]
             91..92 'a': f64
             97..123 '{     ...     }': ()
             111..112 'a': f64
-            133..140 '&[b, c]': &[f64]
+            133..140 '&[b, c]': &'? [f64]
             134..140 '[b, c]': [f64]
             135..136 'b': f64
             138..139 'c': f64
             144..185 '{     ...     }': ()
             158..159 'b': f64
             173..174 'c': f64
-            194..195 '_': &[f64]
+            194..195 '_': &'? [f64]
             199..201 '{}': ()
         "#]],
     );
@@ -327,14 +327,14 @@ fn infer_pattern_match_string_literal() {
         "#,
         expect![[r#"
             10..98 '{     ...   } }': ()
-            20..21 's': &str
-            30..37 '"hello"': &str
+            20..21 's': &'? str
+            30..37 '"hello"': &'static str
             43..96 'match ...     }': ()
-            49..50 's': &str
-            61..68 '"hello"': &str
-            61..68 '"hello"': &str
+            49..50 's': &'? str
+            61..68 '"hello"': &'static str
+            61..68 '"hello"': &'static str
             72..74 '{}': ()
-            83..84 '_': &str
+            83..84 '_': &'? str
             88..90 '{}': ()
         "#]],
     );
@@ -358,27 +358,27 @@ fn infer_pattern_match_byte_string_literal() {
         }
         "#,
         expect![[r#"
-            105..109 'self': &[T; N]
+            105..109 'self': &'? [T; N]
             111..116 'index': {unknown}
-            157..180 '{     ...     }': &[u8]
+            157..180 '{     ...     }': &'? [u8]
             167..174 'loop {}': !
             172..174 '{}': ()
             191..192 'v': [u8; 3]
             203..261 '{     ...v {} }': ()
             209..233 'if let...[S] {}': ()
             212..230 'let b"... &v[S]': bool
-            216..222 'b"foo"': &[u8]
-            216..222 'b"foo"': &[u8]
-            225..230 '&v[S]': &[u8]
+            216..222 'b"foo"': &'static [u8]
+            216..222 'b"foo"': &'static [u8]
+            225..230 '&v[S]': &'? [u8]
             226..227 'v': [u8; 3]
             226..230 'v[S]': [u8]
             228..229 'S': S
             231..233 '{}': ()
             238..259 'if let... &v {}': ()
             241..256 'let b"foo" = &v': bool
-            245..251 'b"foo"': &[u8; 3]
-            245..251 'b"foo"': &[u8; 3]
-            254..256 '&v': &[u8; 3]
+            245..251 'b"foo"': &'static [u8; 3]
+            245..251 'b"foo"': &'static [u8; 3]
+            254..256 '&v': &'? [u8; 3]
             255..256 'v': [u8; 3]
             257..259 '{}': ()
         "#]],
@@ -399,17 +399,17 @@ fn infer_pattern_match_or() {
         "#,
         expect![[r#"
             10..108 '{     ...   } }': ()
-            20..21 's': &str
-            30..37 '"hello"': &str
+            20..21 's': &'? str
+            30..37 '"hello"': &'static str
             43..106 'match ...     }': ()
-            49..50 's': &str
-            61..68 '"hello"': &str
-            61..68 '"hello"': &str
-            61..78 '"hello...world"': &str
-            71..78 '"world"': &str
-            71..78 '"world"': &str
+            49..50 's': &'? str
+            61..68 '"hello"': &'static str
+            61..68 '"hello"': &'static str
+            61..78 '"hello...world"': &'? str
+            71..78 '"world"': &'static str
+            71..78 '"world"': &'static str
             82..84 '{}': ()
-            93..94 '_': &str
+            93..94 '_': &'? str
             98..100 '{}': ()
         "#]],
     );
@@ -505,10 +505,10 @@ fn infer_adt_pattern() {
             216..217 '1': usize
             227..231 'E::B': E
             235..237 '10': usize
-            255..274 'ref d ...{ .. }': &E
+            255..274 'ref d ...{ .. }': &'? E
             263..274 'E::A { .. }': E
             277..278 'e': E
-            284..285 'd': &E
+            284..285 'd': &'? E
         "#]],
     );
 }
@@ -529,14 +529,14 @@ impl Foo {
         expect![[r#"
             42..151 '{     ...     }': ()
             56..64 'Self(s,)': Foo
-            61..62 's': &usize
-            67..75 '&Foo(0,)': &Foo
+            61..62 's': &'? usize
+            67..75 '&Foo(0,)': &'? Foo
             68..71 'Foo': extern "rust-call" Foo(usize) -> Foo
             68..75 'Foo(0,)': Foo
             72..73 '0': usize
             89..97 'Self(s,)': Foo
-            94..95 's': &mut usize
-            100..112 '&mut Foo(0,)': &mut Foo
+            94..95 's': &'? mut usize
+            100..112 '&mut Foo(0,)': &'? mut Foo
             105..108 'Foo': extern "rust-call" Foo(usize) -> Foo
             105..112 'Foo(0,)': Foo
             109..110 '0': usize
@@ -669,7 +669,7 @@ fn main() {
 }
         "#,
         expect![[r#"
-            27..31 'self': &S
+            27..31 'self': &'? S
             41..50 '{ false }': bool
             43..48 'false': bool
             64..115 '{     ...   } }': ()
@@ -679,7 +679,7 @@ fn main() {
             93..94 's': S
             93..100 's.foo()': bool
             104..106 '()': ()
-    "#]],
+        "#]],
     )
 }
 
@@ -702,29 +702,29 @@ fn test() {
             51..58 'loop {}': !
             56..58 '{}': ()
             72..171 '{     ... x); }': ()
-            78..81 'foo': fn foo<&(i32, &str), i32, impl FnOnce(&(i32, &str)) -> i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> i32) -> i32
+            78..81 'foo': fn foo<&'? (i32, &'? str), i32, impl FnOnce(&'? (i32, &'? str)) -> i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> i32) -> i32
             78..105 'foo(&(...y)| x)': i32
-            82..91 '&(1, "a")': &(i32, &str)
-            83..91 '(1, "a")': (i32, &str)
+            82..91 '&(1, "a")': &'? (i32, &'static str)
+            83..91 '(1, "a")': (i32, &'static str)
             84..85 '1': i32
-            87..90 '"a"': &str
-            93..104 '|&(x, y)| x': impl FnOnce(&(i32, &str)) -> i32
-            94..101 '&(x, y)': &(i32, &str)
-            95..101 '(x, y)': (i32, &str)
+            87..90 '"a"': &'static str
+            93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> i32
+            94..101 '&(x, y)': &'? (i32, &'? str)
+            95..101 '(x, y)': (i32, &'? str)
             96..97 'x': i32
-            99..100 'y': &str
+            99..100 'y': &'? str
             103..104 'x': i32
-            142..145 'foo': fn foo<&(i32, &str), &i32, impl FnOnce(&(i32, &str)) -> &i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> &i32) -> &i32
-            142..168 'foo(&(...y)| x)': &i32
-            146..155 '&(1, "a")': &(i32, &str)
-            147..155 '(1, "a")': (i32, &str)
+            142..145 'foo': fn foo<&'? (i32, &'? str), &'? i32, impl FnOnce(&'? (i32, &'? str)) -> &'? i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> &'? i32) -> &'? i32
+            142..168 'foo(&(...y)| x)': &'? i32
+            146..155 '&(1, "a")': &'? (i32, &'static str)
+            147..155 '(1, "a")': (i32, &'static str)
             148..149 '1': i32
-            151..154 '"a"': &str
-            157..167 '|(x, y)| x': impl FnOnce(&(i32, &str)) -> &i32
-            158..164 '(x, y)': (i32, &str)
-            159..160 'x': &i32
-            162..163 'y': &&str
-            166..167 'x': &i32
+            151..154 '"a"': &'static str
+            157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> &'? i32
+            158..164 '(x, y)': (i32, &'? str)
+            159..160 'x': &'? i32
+            162..163 'y': &'? &'? str
+            166..167 'x': &'? i32
         "#]],
     );
 }
@@ -741,13 +741,13 @@ fn slice_tail_pattern() {
         }
         "#,
         expect![[r#"
-            7..13 'params': &[i32]
+            7..13 'params': &'? [i32]
             23..92 '{     ...   } }': ()
             29..90 'match ...     }': ()
-            35..41 'params': &[i32]
+            35..41 'params': &'? [i32]
             52..69 '[head,... @ ..]': [i32]
-            53..57 'head': &i32
-            59..68 'tail @ ..': &[i32]
+            53..57 'head': &'? i32
+            59..68 'tail @ ..': &'? [i32]
             66..68 '..': [i32]
             73..84 '{         }': ()
         "#]],
@@ -1109,7 +1109,7 @@ fn var_args() {
 #[lang = "va_list"]
 pub struct VaListImpl<'f>;
 fn my_fn(foo: ...) {}
-       //^^^ VaListImpl<'{error}>
+       //^^^ VaListImpl<'?>
 "#,
     );
 }
@@ -1122,9 +1122,9 @@ fn foo() {
     let &() = &();
     let &mut () = &mut ();
     let &mut () = &();
-      //^^^^^^^ expected &(), got &mut ()
+      //^^^^^^^ expected &'? (), got &'? mut ()
     let &() = &mut ();
-      //^^^ expected &mut (), got &()
+      //^^^ expected &'? mut (), got &'? ()
 }
 "#,
     );
@@ -1148,7 +1148,7 @@ fn main() {
     };
 
     if let Wrap::<X>::A { cool, ..} = &wrapped {}
-                        //^^^^ &u32
+                        //^^^^ &'? u32
 }
 "#,
     );
@@ -1182,7 +1182,7 @@ fn main() {
     };
 
     if let Wrap::<<S as Schematic>::Props>::A { cool, ..} = &wrapped {}
-                                              //^^^^ &u32
+                                              //^^^^ &'? u32
 }
 "#,
     );
@@ -1217,7 +1217,7 @@ fn main() {
     match &6 {
         Foo::<i32>::TEST_I32_REF => (),
         Foo::<i32>::TEST_I32 => (),
-      //^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
+      //^^^^^^^^^^^^^^^^^^^^ expected &'? i32, got i32
         _ => (),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index c2d2047e6f9..3aa94be755c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -99,7 +99,7 @@ fn recursive_vars() {
             24..31 'unknown': {unknown}
             37..44 '[y, &y]': [{unknown}; 2]
             38..39 'y': {unknown}
-            41..43 '&y': &{unknown}
+            41..43 '&y': &'? {unknown}
             42..43 'y': {unknown}
         "#]],
     );
@@ -117,19 +117,19 @@ fn recursive_vars_2() {
         "#,
         expect![[r#"
             10..79 '{     ...x)]; }': ()
-            20..21 'x': &{unknown}
-            24..31 'unknown': &{unknown}
+            20..21 'x': &'? {unknown}
+            24..31 'unknown': &'? {unknown}
             41..42 'y': {unknown}
             45..52 'unknown': {unknown}
-            58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2]
-            59..65 '(x, y)': (&{unknown}, {unknown})
-            60..61 'x': &{unknown}
+            58..76 '[(x, y..., &x)]': [(&'? {unknown}, {unknown}); 2]
+            59..65 '(x, y)': (&'? {unknown}, {unknown})
+            60..61 'x': &'? {unknown}
             63..64 'y': {unknown}
-            67..75 '(&y, &x)': (&{unknown}, {unknown})
-            68..70 '&y': &{unknown}
+            67..75 '(&y, &x)': (&'? {unknown}, {unknown})
+            68..70 '&y': &'? {unknown}
             69..70 'y': {unknown}
-            72..74 '&x': &&{unknown}
-            73..74 'x': &{unknown}
+            72..74 '&x': &'? &'? {unknown}
+            73..74 'x': &'? {unknown}
         "#]],
     );
 }
@@ -166,7 +166,7 @@ fn infer_std_crash_1() {
             59..136 'match ...     }': ()
             65..82 'someth...nknown': Maybe<{unknown}>
             93..123 'Maybe:...thing)': Maybe<{unknown}>
-            105..122 'ref mu...ething': &mut {unknown}
+            105..122 'ref mu...ething': &'? mut {unknown}
             127..129 '()': ()
         "#]],
     );
@@ -183,7 +183,7 @@ fn infer_std_crash_2() {
         "#,
         expect![[r#"
             22..52 '{     ...n']; }': ()
-            28..49 '&[0, b...b'\n']': &[u8; 4]
+            28..49 '&[0, b...b'\n']': &'? [u8; 4]
             29..49 '[0, b'...b'\n']': [u8; 4]
             30..31 '0': u8
             33..38 'b'\n'': u8
@@ -269,8 +269,8 @@ fn infer_std_crash_5() {
             32..320 'for co...     }': {unknown}
             32..320 'for co...     }': !
             32..320 'for co...     }': {unknown}
-            32..320 'for co...     }': &mut {unknown}
-            32..320 'for co...     }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            32..320 'for co...     }': &'? mut {unknown}
+            32..320 'for co...     }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             32..320 'for co...     }': Option<{unknown}>
             32..320 'for co...     }': ()
             32..320 'for co...     }': ()
@@ -278,22 +278,22 @@ fn infer_std_crash_5() {
             36..43 'content': {unknown}
             47..60 'doesnt_matter': {unknown}
             61..320 '{     ...     }': ()
-            75..79 'name': &{unknown}
-            82..166 'if doe...     }': &{unknown}
+            75..79 'name': &'? {unknown}
+            82..166 'if doe...     }': &'? {unknown}
             85..98 'doesnt_matter': bool
-            99..128 '{     ...     }': &{unknown}
-            113..118 'first': &{unknown}
-            134..166 '{     ...     }': &{unknown}
-            148..156 '&content': &{unknown}
+            99..128 '{     ...     }': &'? {unknown}
+            113..118 'first': &'? {unknown}
+            134..166 '{     ...     }': &'? {unknown}
+            148..156 '&content': &'? {unknown}
             149..156 'content': {unknown}
-            181..188 'content': &{unknown}
-            191..313 'if ICE...     }': &{unknown}
+            181..188 'content': &'? {unknown}
+            191..313 'if ICE...     }': &'? {unknown}
             194..231 'ICE_RE..._VALUE': {unknown}
             194..247 'ICE_RE...&name)': bool
-            241..246 '&name': &&{unknown}
-            242..246 'name': &{unknown}
-            248..276 '{     ...     }': &{unknown}
-            262..266 'name': &{unknown}
+            241..246 '&name': &'? &'? {unknown}
+            242..246 'name': &'? {unknown}
+            248..276 '{     ...     }': &'? {unknown}
+            262..266 'name': &'? {unknown}
             282..313 '{     ...     }': {unknown}
             296..303 'content': {unknown}
         "#]],
@@ -318,7 +318,7 @@ fn infer_nested_generics_crash() {
         expect![[r#"
             91..105 'query_response': Canonical<QueryResponse<R>>
             136..166 '{     ...lue; }': ()
-            142..163 '&query....value': &QueryResponse<R>
+            142..163 '&query....value': &'? QueryResponse<R>
             143..157 'query_response': Canonical<QueryResponse<R>>
             143..163 'query_....value': QueryResponse<R>
         "#]],
@@ -465,12 +465,12 @@ fn issue_3999_slice() {
         }
         "#,
         expect![[r#"
-            7..13 'params': &[usize]
+            7..13 'params': &'? [usize]
             25..80 '{     ...   } }': ()
             31..78 'match ...     }': ()
-            37..43 'params': &[usize]
+            37..43 'params': &'? [usize]
             54..66 '[ps @ .., _]': [usize]
-            55..62 'ps @ ..': &[usize]
+            55..62 'ps @ ..': &'? [usize]
             60..62 '..': [usize]
             64..65 '_': usize
             70..72 '{}': ()
@@ -523,13 +523,13 @@ fn issue_4235_name_conflicts() {
         "#,
         expect![[r#"
             31..37 'FOO {}': FOO
-            63..67 'self': &FOO
+            63..67 'self': &'? FOO
             69..71 '{}': ()
             85..119 '{     ...o(); }': ()
-            95..96 'a': &FOO
-            99..103 '&FOO': &FOO
+            95..96 'a': &'? FOO
+            99..103 '&FOO': &'? FOO
             100..103 'FOO': FOO
-            109..110 'a': &FOO
+            109..110 'a': &'? FOO
             109..116 'a.foo()': ()
         "#]],
     );
@@ -715,12 +715,12 @@ fn issue_4885() {
         }
         "#,
         expect![[r#"
-            70..73 'key': &K
+            70..73 'key': &'? K
             132..148 '{     ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
-            138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
+            138..141 'bar': fn bar<R, K>(&'? K) -> impl Future<Output = <K as Foo<R>>::Bar>
             138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
-            142..145 'key': &K
-            162..165 'key': &K
+            142..145 'key': &'? K
+            162..165 'key': &'? K
             224..227 '{ }': ()
         "#]],
     );
@@ -771,11 +771,11 @@ fn issue_4800() {
         }
         "#,
         expect![[r#"
-            379..383 'self': &mut PeerSet<D>
+            379..383 'self': &'? mut PeerSet<D>
             401..424 '{     ...     }': dyn Future<Output = ()>
             411..418 'loop {}': !
             416..418 '{}': ()
-            575..579 'self': &mut Self
+            575..579 'self': &'? mut Self
         "#]],
     );
 }
@@ -815,19 +815,19 @@ fn issue_4966() {
             225..229 'iter': T
             244..246 '{}': Vec<A>
             258..402 '{     ...r(); }': ()
-            268..273 'inner': Map<impl Fn(&f64) -> f64>
-            276..300 'Map { ... 0.0 }': Map<impl Fn(&f64) -> f64>
-            285..298 '|_: &f64| 0.0': impl Fn(&f64) -> f64
-            286..287 '_': &f64
+            268..273 'inner': Map<impl Fn(&'? f64) -> f64>
+            276..300 'Map { ... 0.0 }': Map<impl Fn(&'? f64) -> f64>
+            285..298 '|_: &f64| 0.0': impl Fn(&'? f64) -> f64
+            286..287 '_': &'? f64
             295..298 '0.0': f64
-            311..317 'repeat': Repeat<Map<impl Fn(&f64) -> f64>>
-            320..345 'Repeat...nner }': Repeat<Map<impl Fn(&f64) -> f64>>
-            338..343 'inner': Map<impl Fn(&f64) -> f64>
-            356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
-            362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>, Repeat<Map<impl Fn(&f64) -> f64>>>(Repeat<Map<impl Fn(&f64) -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
-            362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
-            372..378 'repeat': Repeat<Map<impl Fn(&f64) -> f64>>
-            386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
+            311..317 'repeat': Repeat<Map<impl Fn(&'? f64) -> f64>>
+            320..345 'Repeat...nner }': Repeat<Map<impl Fn(&'? f64) -> f64>>
+            338..343 'inner': Map<impl Fn(&'? f64) -> f64>
+            356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
+            362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>, Repeat<Map<impl Fn(&'? f64) -> f64>>>(Repeat<Map<impl Fn(&'? f64) -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
+            362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
+            372..378 'repeat': Repeat<Map<impl Fn(&'? f64) -> f64>>
+            386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
             386..399 'vec.foo_bar()': {unknown}
         "#]],
     );
@@ -850,10 +850,10 @@ fn main() {
 }
 "#,
         expect![[r#"
-            40..44 'self': &S<T>
+            40..44 'self': &'? S<T>
             46..48 '_t': T
             53..55 '{}': ()
-            81..85 'self': &S<T>
+            81..85 'self': &'? S<T>
             87..89 '_f': F
             94..96 '{}': ()
             109..160 '{     ...10); }': ()
@@ -862,8 +862,8 @@ fn main() {
             123..126 'S()': S<i32>
             132..133 's': S<i32>
             132..144 's.g(|_x| {})': ()
-            136..143 '|_x| {}': impl FnOnce(&i32)
-            137..139 '_x': &i32
+            136..143 '|_x| {}': impl FnOnce(&'? i32)
+            137..139 '_x': &'? i32
             141..143 '{}': ()
             150..151 's': S<i32>
             150..157 's.f(10)': ()
@@ -895,14 +895,14 @@ fn flush(&self) {
 }
 "#,
         expect![[r#"
-            123..127 'self': &Mutex<T>
-            150..152 '{}': MutexGuard<'{error}, T>
-            234..238 'self': &{unknown}
+            123..127 'self': &'? Mutex<T>
+            150..152 '{}': MutexGuard<'?, T>
+            234..238 'self': &'? {unknown}
             240..290 '{     ...()); }': ()
-            250..251 'w': &Mutex<BufWriter>
+            250..251 'w': &'? Mutex<BufWriter>
             276..287 '*(w.lock())': BufWriter
-            278..279 'w': &Mutex<BufWriter>
-            278..286 'w.lock()': MutexGuard<'{error}, BufWriter>
+            278..279 'w': &'? Mutex<BufWriter>
+            278..286 'w.lock()': MutexGuard<'?, BufWriter>
         "#]],
     );
 }
@@ -1023,20 +1023,20 @@ fn cfg_tail() {
         expect![[r#"
             14..53 '{     ...)] 9 }': ()
             20..31 '{ "first" }': ()
-            22..29 '"first"': &str
+            22..29 '"first"': &'static str
             72..190 '{     ...] 13 }': ()
             78..88 '{ "fake" }': ()
-            80..86 '"fake"': &str
+            80..86 '"fake"': &'static str
             93..103 '{ "fake" }': ()
-            95..101 '"fake"': &str
+            95..101 '"fake"': &'static str
             108..120 '{ "second" }': ()
-            110..118 '"second"': &str
+            110..118 '"second"': &'static str
             210..273 '{     ... 15; }': ()
             216..227 '{ "third" }': ()
-            218..225 '"third"': &str
+            218..225 '"third"': &'static str
             293..357 '{     ...] 15 }': ()
-            299..311 '{ "fourth" }': &str
-            301..309 '"fourth"': &str
+            299..311 '{ "fourth" }': &'static str
+            301..309 '"fourth"': &'static str
         "#]],
     )
 }
@@ -1238,8 +1238,8 @@ fn test() {
             16..66 'for _ ...     }': IntoIterator::IntoIter<()>
             16..66 'for _ ...     }': !
             16..66 'for _ ...     }': IntoIterator::IntoIter<()>
-            16..66 'for _ ...     }': &mut IntoIterator::IntoIter<()>
-            16..66 'for _ ...     }': fn next<IntoIterator::IntoIter<()>>(&mut IntoIterator::IntoIter<()>) -> Option<<IntoIterator::IntoIter<()> as Iterator>::Item>
+            16..66 'for _ ...     }': &'? mut IntoIterator::IntoIter<()>
+            16..66 'for _ ...     }': fn next<IntoIterator::IntoIter<()>>(&'? mut IntoIterator::IntoIter<()>) -> Option<<IntoIterator::IntoIter<()> as Iterator>::Item>
             16..66 'for _ ...     }': Option<IntoIterator::Item<()>>
             16..66 'for _ ...     }': ()
             16..66 'for _ ...     }': ()
@@ -1600,85 +1600,6 @@ fn f(s: S) {
 }
 
 #[test]
-fn rust_161_option_clone() {
-    check_types(
-        r#"
-//- minicore: option, drop
-
-fn test(o: &Option<i32>) {
-    o.my_clone();
-  //^^^^^^^^^^^^ Option<i32>
-}
-
-pub trait MyClone: Sized {
-    fn my_clone(&self) -> Self;
-}
-
-impl<T> const MyClone for Option<T>
-where
-    T: ~const MyClone + ~const Drop + ~const Destruct,
-{
-    fn my_clone(&self) -> Self {
-        match self {
-            Some(x) => Some(x.my_clone()),
-            None => None,
-        }
-    }
-}
-
-impl const MyClone for i32 {
-    fn my_clone(&self) -> Self {
-        *self
-    }
-}
-
-pub trait Destruct {}
-
-impl<T: ?Sized> const Destruct for T {}
-"#,
-    );
-}
-
-#[test]
-fn rust_162_option_clone() {
-    check_types(
-        r#"
-//- minicore: option, drop
-
-fn test(o: &Option<i32>) {
-    o.my_clone();
-  //^^^^^^^^^^^^ Option<i32>
-}
-
-pub trait MyClone: Sized {
-    fn my_clone(&self) -> Self;
-}
-
-impl<T> const MyClone for Option<T>
-where
-    T: ~const MyClone + ~const Destruct,
-{
-    fn my_clone(&self) -> Self {
-        match self {
-            Some(x) => Some(x.my_clone()),
-            None => None,
-        }
-    }
-}
-
-impl const MyClone for i32 {
-    fn my_clone(&self) -> Self {
-        *self
-    }
-}
-
-#[lang = "destruct"]
-pub trait Destruct {}
-"#,
-    );
-}
-
-#[test]
 fn tuple_struct_pattern_with_unmatched_args_crash() {
     check_infer(
         r#"
@@ -1727,7 +1648,7 @@ fn dyn_with_unresolved_trait() {
         r#"
 fn foo(a: &dyn DoesNotExist) {
     a.bar();
-  //^&{unknown}
+  //^&'? {unknown}
 }
         "#,
     );
@@ -1851,9 +1772,9 @@ fn foo() {
     match &E::A {
         b @ (x @ E::A | x) => {
             b;
-          //^ &E
+          //^ &'? E
             x;
-          //^ &E
+          //^ &'? E
         }
     }
 }",
@@ -2040,3 +1961,41 @@ fn main() {
 "#,
     )
 }
+
+#[test]
+fn cfg_first_trait_param_16141() {
+    check_no_mismatches(
+        r#"
+//- minicore: sized, coerce_unsized
+trait Bar {
+    fn bar(&self) {}
+}
+
+impl<#[cfg(feature = "a-feature")] A> Bar for (){}
+"#,
+    )
+}
+
+#[test]
+fn nested_anon_generics_and_where_bounds_17173() {
+    check_types(
+        r#"
+//- minicore: sized, fn
+pub trait Lookup {
+    type Data;
+    fn lookup(&self) -> Self::Data;
+}
+pub trait ItemTreeLoc {
+    type Id;
+}
+fn id_to_generics(id: impl Lookup<Data = impl ItemTreeLoc<Id = ()>>,
+                //^^ impl Lookup<Data = impl ItemTreeLoc<Id = ()>>
+                enabled_params: impl Fn(),
+              //^^^^^^^^^^^^^^  impl Fn()
+                )
+where
+    (): Sized,
+{}
+"#,
+    );
+}
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 a9d28ebfef5..e2cd7fa26b2 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
@@ -115,15 +115,15 @@ fn test(a: u32, b: isize, c: !, d: &str) {
             8..9 'a': u32
             16..17 'b': isize
             26..27 'c': !
-            32..33 'd': &str
+            32..33 'd': &'? str
             41..120 '{     ...f32; }': ()
             47..48 'a': u32
             54..55 'b': isize
             61..62 'c': !
-            68..69 'd': &str
+            68..69 'd': &'? str
             75..81 '1usize': usize
             87..93 '1isize': isize
-            99..105 '"test"': &str
+            99..105 '"test"': &'static str
             111..117 '1.0f32': f32
         "#]],
     );
@@ -344,23 +344,23 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
 }
         "#,
         expect![[r#"
-            8..9 'a': &u32
-            17..18 'b': &mut u32
+            8..9 'a': &'? u32
+            17..18 'b': &'? mut u32
             30..31 'c': *const u32
             45..46 'd': *mut u32
             58..149 '{     ... *d; }': ()
-            64..65 'a': &u32
+            64..65 'a': &'? u32
             71..73 '*a': u32
-            72..73 'a': &u32
-            79..81 '&a': &&u32
-            80..81 'a': &u32
-            87..93 '&mut a': &mut &u32
-            92..93 'a': &u32
-            99..100 'b': &mut u32
+            72..73 'a': &'? u32
+            79..81 '&a': &'? &'? u32
+            80..81 'a': &'? u32
+            87..93 '&mut a': &'? mut &'? u32
+            92..93 'a': &'? u32
+            99..100 'b': &'? mut u32
             106..108 '*b': u32
-            107..108 'b': &mut u32
-            114..116 '&b': &&mut u32
-            115..116 'b': &mut u32
+            107..108 'b': &'? mut u32
+            114..116 '&b': &'? &'? mut u32
+            115..116 'b': &'? mut u32
             122..123 'c': *const u32
             129..131 '*c': u32
             130..131 'c': *const u32
@@ -425,22 +425,22 @@ h";
             32..36 '5i32': i32
             50..54 '5f32': f32
             68..72 '5f64': f64
-            86..93 '"hello"': &str
-            107..115 'b"bytes"': &[u8; 5]
+            86..93 '"hello"': &'static str
+            107..115 'b"bytes"': &'static [u8; 5]
             129..132 ''c'': char
             146..150 'b'b'': u8
             164..168 '3.14': f64
             182..186 '5000': i32
             200..205 'false': bool
             219..223 'true': bool
-            237..333 'r#"   ...    "#': &str
-            347..357 'br#"yolo"#': &[u8; 4]
-            375..376 'a': &[u8; 4]
-            379..403 'b"a\x2...    c"': &[u8; 4]
-            421..422 'b': &[u8; 4]
-            425..433 'br"g\ h"': &[u8; 4]
-            451..452 'c': &[u8; 6]
-            455..467 'br#"x"\"yb"#': &[u8; 6]
+            237..333 'r#"   ...    "#': &'static str
+            347..357 'br#"yolo"#': &'static [u8; 4]
+            375..376 'a': &'static [u8; 4]
+            379..403 'b"a\x2...    c"': &'static [u8; 4]
+            421..422 'b': &'static [u8; 4]
+            425..433 'br"g\ h"': &'static [u8; 4]
+            451..452 'c': &'static [u8; 6]
+            455..467 'br#"x"\"yb"#': &'static [u8; 6]
         "##]],
     );
 }
@@ -508,9 +508,9 @@ fn test(x: SomeType) {
             238..240 '!x': {unknown}
             239..240 'x': SomeType
             246..254 '-"hello"': {unknown}
-            247..254 '"hello"': &str
+            247..254 '"hello"': &'static str
             260..268 '!"hello"': {unknown}
-            261..268 '"hello"': &str
+            261..268 '"hello"': &'static str
         "#]],
     );
 }
@@ -535,7 +535,7 @@ fn test() -> &mut &f64 {
         expect![[r#"
             13..14 'x': u32
             21..23 '{}': ()
-            77..230 '{     ...t &c }': &mut &f64
+            77..230 '{     ...t &c }': &'? mut &'? f64
             87..88 'a': u32
             91..107 'unknow...nction': {unknown}
             91..109 'unknow...tion()': u32
@@ -550,8 +550,8 @@ fn test() -> &mut &f64 {
             193..194 'c': f64
             197..213 'unknow...nction': {unknown}
             197..215 'unknow...tion()': f64
-            221..228 '&mut &c': &mut &f64
-            226..228 '&c': &f64
+            221..228 '&mut &c': &'? mut &'? f64
+            226..228 '&c': &'? f64
             227..228 'c': f64
         "#]],
     );
@@ -579,12 +579,12 @@ impl S {
 }
 "#,
         expect![[r#"
-            33..37 'self': &S
+            33..37 'self': &'? S
             39..60 '{     ...     }': ()
-            49..53 'self': &S
-            74..78 'self': &S
+            49..53 'self': &'? S
+            74..78 'self': &'? S
             87..108 '{     ...     }': ()
-            97..101 'self': &S
+            97..101 'self': &'? S
             132..152 '{     ...     }': S
             142..146 'S {}': S
             176..199 '{     ...     }': S
@@ -771,35 +771,35 @@ fn test2(a1: *const A, a2: *mut A) {
             64..65 'a': A
             71..73 'a1': A
             71..75 'a1.b': B
-            85..87 'a2': &A
-            90..92 '&a': &A
+            85..87 'a2': &'? A
+            90..92 '&a': &'? A
             91..92 'a': A
-            98..100 'a2': &A
+            98..100 'a2': &'? A
             98..102 'a2.b': B
-            112..114 'a3': &mut A
-            117..123 '&mut a': &mut A
+            112..114 'a3': &'? mut A
+            117..123 '&mut a': &'? mut A
             122..123 'a': A
-            129..131 'a3': &mut A
+            129..131 'a3': &'? mut A
             129..133 'a3.b': B
-            143..145 'a4': &&&&&&&A
-            148..156 '&&&&&&&a': &&&&&&&A
-            149..156 '&&&&&&a': &&&&&&A
-            150..156 '&&&&&a': &&&&&A
-            151..156 '&&&&a': &&&&A
-            152..156 '&&&a': &&&A
-            153..156 '&&a': &&A
-            154..156 '&a': &A
+            143..145 'a4': &'? &'? &'? &'? &'? &'? &'? A
+            148..156 '&&&&&&&a': &'? &'? &'? &'? &'? &'? &'? A
+            149..156 '&&&&&&a': &'? &'? &'? &'? &'? &'? A
+            150..156 '&&&&&a': &'? &'? &'? &'? &'? A
+            151..156 '&&&&a': &'? &'? &'? &'? A
+            152..156 '&&&a': &'? &'? &'? A
+            153..156 '&&a': &'? &'? A
+            154..156 '&a': &'? A
             155..156 'a': A
-            162..164 'a4': &&&&&&&A
+            162..164 'a4': &'? &'? &'? &'? &'? &'? &'? A
             162..166 'a4.b': B
-            176..178 'a5': &mut &&mut &&mut A
-            181..199 '&mut &...&mut a': &mut &&mut &&mut A
-            186..199 '&&mut &&mut a': &&mut &&mut A
-            187..199 '&mut &&mut a': &mut &&mut A
-            192..199 '&&mut a': &&mut A
-            193..199 '&mut a': &mut A
+            176..178 'a5': &'? mut &'? &'? mut &'? &'? mut A
+            181..199 '&mut &...&mut a': &'? mut &'? &'? mut &'? &'? mut A
+            186..199 '&&mut &&mut a': &'? &'? mut &'? &'? mut A
+            187..199 '&mut &&mut a': &'? mut &'? &'? mut A
+            192..199 '&&mut a': &'? &'? mut A
+            193..199 '&mut a': &'? mut A
             198..199 'a': A
-            205..207 'a5': &mut &&mut &&mut A
+            205..207 'a5': &'? mut &'? &'? mut &'? &'? mut A
             205..209 'a5.b': B
             223..225 'a1': *const A
             237..239 'a2': *mut A
@@ -840,22 +840,22 @@ fn test() {
 }
 "#,
         expect![[r#"
-            66..70 'self': &A<T>
-            78..101 '{     ...     }': &T
-            88..95 '&self.0': &T
-            89..93 'self': &A<T>
+            66..70 'self': &'? A<T>
+            78..101 '{     ...     }': &'? T
+            88..95 '&self.0': &'? T
+            89..93 'self': &'? A<T>
             89..95 'self.0': T
-            182..186 'self': &B<T>
-            205..228 '{     ...     }': &T
-            215..222 '&self.0': &T
-            216..220 'self': &B<T>
+            182..186 'self': &'? B<T>
+            205..228 '{     ...     }': &'? T
+            215..222 '&self.0': &'? T
+            216..220 'self': &'? B<T>
             216..222 'self.0': T
             242..280 '{     ...))); }': ()
-            252..253 't': &i32
-            256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32
-            256..277 'A::foo...42))))': &i32
-            263..276 '&&B(B(A(42)))': &&B<B<A<i32>>>
-            264..276 '&B(B(A(42)))': &B<B<A<i32>>>
+            252..253 't': &'? i32
+            256..262 'A::foo': fn foo<i32>(&'? A<i32>) -> &'? i32
+            256..277 'A::foo...42))))': &'? i32
+            263..276 '&&B(B(A(42)))': &'? &'? B<B<A<i32>>>
+            264..276 '&B(B(A(42)))': &'? B<B<A<i32>>>
             265..266 'B': extern "rust-call" B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
             265..276 'B(B(A(42)))': B<B<A<i32>>>
             267..268 'B': extern "rust-call" B<A<i32>>(A<i32>) -> B<A<i32>>
@@ -895,28 +895,28 @@ fn test(a: A<i32>) {
 }
 "#,
         expect![[r#"
-            71..75 'self': &A<T>
-            77..78 'x': &A<T>
-            93..114 '{     ...     }': &T
-            103..108 '&*x.0': &T
+            71..75 'self': &'? A<T>
+            77..78 'x': &'? A<T>
+            93..114 '{     ...     }': &'? T
+            103..108 '&*x.0': &'? T
             104..108 '*x.0': T
-            105..106 'x': &A<T>
+            105..106 'x': &'? A<T>
             105..108 'x.0': *mut T
-            195..199 'self': &B<T>
-            218..241 '{     ...     }': &T
-            228..235 '&self.0': &T
-            229..233 'self': &B<T>
+            195..199 'self': &'? B<T>
+            218..241 '{     ...     }': &'? T
+            228..235 '&self.0': &'? T
+            229..233 'self': &'? B<T>
             229..235 'self.0': T
             253..254 'a': A<i32>
             264..310 '{     ...))); }': ()
-            274..275 't': &i32
+            274..275 't': &'? i32
             278..279 'A': extern "rust-call" A<i32>(*mut i32) -> A<i32>
             278..292 'A(0 as *mut _)': A<i32>
-            278..307 'A(0 as...B(a)))': &i32
+            278..307 'A(0 as...B(a)))': &'? i32
             280..281 '0': i32
             280..291 '0 as *mut _': *mut i32
-            297..306 '&&B(B(a))': &&B<B<A<i32>>>
-            298..306 '&B(B(a))': &B<B<A<i32>>>
+            297..306 '&&B(B(a))': &'? &'? B<B<A<i32>>>
+            298..306 '&B(B(a))': &'? B<B<A<i32>>>
             299..300 'B': extern "rust-call" B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
             299..306 'B(B(a))': B<B<A<i32>>>
             301..302 'B': extern "rust-call" B<A<i32>>(A<i32>) -> B<A<i32>>
@@ -1044,7 +1044,7 @@ fn infer_inherent_method() {
             31..35 'self': A
             37..38 'x': u32
             52..54 '{}': i32
-            106..110 'self': &A
+            106..110 'self': &'? A
             112..113 'x': u64
             127..129 '{}': i64
             147..148 'a': A
@@ -1053,7 +1053,7 @@ fn infer_inherent_method() {
             159..167 'a.foo(1)': i32
             165..166 '1': u32
             173..184 '(&a).bar(1)': i64
-            174..176 '&a': &A
+            174..176 '&a': &'? A
             175..176 'a': A
             182..183 '1': u64
             190..191 'a': A
@@ -1078,10 +1078,10 @@ fn test() {
 }
 "#,
         expect![[r#"
-            67..71 'self': &str
+            67..71 'self': &'? str
             80..82 '{}': i32
             96..116 '{     ...o(); }': ()
-            102..107 '"foo"': &str
+            102..107 '"foo"': &'static str
             102..113 '"foo".foo()': i32
         "#]],
     );
@@ -1101,33 +1101,33 @@ fn infer_tuple() {
         }
         "#,
         expect![[r#"
-            8..9 'x': &str
+            8..9 'x': &'? str
             17..18 'y': isize
             27..169 '{     ...d"); }': ()
-            37..38 'a': (u32, &str)
-            54..62 '(1, "a")': (u32, &str)
+            37..38 'a': (u32, &'? str)
+            54..62 '(1, "a")': (u32, &'? str)
             55..56 '1': u32
-            58..61 '"a"': &str
-            72..73 'b': ((u32, &str), &str)
-            76..82 '(a, x)': ((u32, &str), &str)
-            77..78 'a': (u32, &str)
-            80..81 'x': &str
-            92..93 'c': (isize, &str)
-            96..102 '(y, x)': (isize, &str)
+            58..61 '"a"': &'static str
+            72..73 'b': ((u32, &'? str), &'? str)
+            76..82 '(a, x)': ((u32, &'? str), &'? str)
+            77..78 'a': (u32, &'? str)
+            80..81 'x': &'? str
+            92..93 'c': (isize, &'? str)
+            96..102 '(y, x)': (isize, &'? str)
             97..98 'y': isize
-            100..101 'x': &str
-            112..113 'd': ((isize, &str), &str)
-            116..122 '(c, x)': ((isize, &str), &str)
-            117..118 'c': (isize, &str)
-            120..121 'x': &str
-            132..133 'e': (i32, &str)
-            136..144 '(1, "e")': (i32, &str)
+            100..101 'x': &'? str
+            112..113 'd': ((isize, &'? str), &'? str)
+            116..122 '(c, x)': ((isize, &'? str), &'? str)
+            117..118 'c': (isize, &'? str)
+            120..121 'x': &'? str
+            132..133 'e': (i32, &'static str)
+            136..144 '(1, "e")': (i32, &'static str)
             137..138 '1': i32
-            140..143 '"e"': &str
-            154..155 'f': ((i32, &str), &str)
-            158..166 '(e, "d")': ((i32, &str), &str)
-            159..160 'e': (i32, &str)
-            162..165 '"d"': &str
+            140..143 '"e"': &'static str
+            154..155 'f': ((i32, &'static str), &'static str)
+            158..166 '(e, "d")': ((i32, &'static str), &'static str)
+            159..160 'e': (i32, &'static str)
+            162..165 '"d"': &'static str
         "#]],
     );
 }
@@ -1156,20 +1156,20 @@ fn infer_array() {
         }
         "#,
         expect![[r#"
-            8..9 'x': &str
+            8..9 'x': &'? str
             17..18 'y': isize
             27..326 '{     ...,4]; }': ()
-            37..38 'a': [&str; 1]
-            41..44 '[x]': [&str; 1]
-            42..43 'x': &str
-            54..55 'b': [[&str; 1]; 2]
-            58..64 '[a, a]': [[&str; 1]; 2]
-            59..60 'a': [&str; 1]
-            62..63 'a': [&str; 1]
-            74..75 'c': [[[&str; 1]; 2]; 2]
-            78..84 '[b, b]': [[[&str; 1]; 2]; 2]
-            79..80 'b': [[&str; 1]; 2]
-            82..83 'b': [[&str; 1]; 2]
+            37..38 'a': [&'? str; 1]
+            41..44 '[x]': [&'? str; 1]
+            42..43 'x': &'? str
+            54..55 'b': [[&'? str; 1]; 2]
+            58..64 '[a, a]': [[&'? str; 1]; 2]
+            59..60 'a': [&'? str; 1]
+            62..63 'a': [&'? str; 1]
+            74..75 'c': [[[&'? str; 1]; 2]; 2]
+            78..84 '[b, b]': [[[&'? str; 1]; 2]; 2]
+            79..80 'b': [[&'? str; 1]; 2]
+            82..83 'b': [[&'? str; 1]; 2]
             95..96 'd': [isize; 4]
             99..111 '[y, 1, 2, 3]': [isize; 4]
             100..101 'y': isize
@@ -1197,15 +1197,15 @@ fn infer_array() {
             209..215 '[1, 2]': [i32; 2]
             210..211 '1': i32
             213..214 '2': i32
-            225..226 'i': [&str; 2]
-            229..239 '["a", "b"]': [&str; 2]
-            230..233 '"a"': &str
-            235..238 '"b"': &str
-            250..251 'b': [[&str; 1]; 2]
-            254..264 '[a, ["b"]]': [[&str; 1]; 2]
-            255..256 'a': [&str; 1]
-            258..263 '["b"]': [&str; 1]
-            259..262 '"b"': &str
+            225..226 'i': [&'? str; 2]
+            229..239 '["a", "b"]': [&'? str; 2]
+            230..233 '"a"': &'static str
+            235..238 '"b"': &'static str
+            250..251 'b': [[&'? str; 1]; 2]
+            254..264 '[a, ["b"]]': [[&'? str; 1]; 2]
+            255..256 'a': [&'? str; 1]
+            258..263 '["b"]': [&'? str; 1]
+            259..262 '"b"': &'static str
             274..275 'x': [u8; 0]
             287..289 '[]': [u8; 0]
             299..300 'y': [u8; 4]
@@ -1279,12 +1279,12 @@ fn infer_tuple_struct_generics() {
             92..93 'A': extern "rust-call" A<u128>(u128) -> A<u128>
             92..101 'A(42u128)': A<u128>
             94..100 '42u128': u128
-            107..111 'Some': extern "rust-call" Some<&str>(&str) -> Option<&str>
-            107..116 'Some("x")': Option<&str>
-            112..115 '"x"': &str
-            122..134 'Option::Some': extern "rust-call" Some<&str>(&str) -> Option<&str>
-            122..139 'Option...e("x")': Option<&str>
-            135..138 '"x"': &str
+            107..111 'Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str>
+            107..116 'Some("x")': Option<&'static str>
+            112..115 '"x"': &'static str
+            122..134 'Option::Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str>
+            122..139 'Option...e("x")': Option<&'static str>
+            135..138 '"x"': &'static str
             145..149 'None': Option<{unknown}>
             159..160 'x': Option<i64>
             176..180 'None': Option<i64>
@@ -1405,15 +1405,15 @@ fn infer_impl_generics_with_autoderef() {
         }
         "#,
         expect![[r#"
-            77..81 'self': &Option<T>
-            97..99 '{}': Option<&T>
+            77..81 'self': &'? Option<T>
+            97..99 '{}': Option<&'? T>
             110..111 'o': Option<u32>
             126..164 '{     ...f(); }': ()
-            132..145 '(&o).as_ref()': Option<&u32>
-            133..135 '&o': &Option<u32>
+            132..145 '(&o).as_ref()': Option<&'? u32>
+            133..135 '&o': &'? Option<u32>
             134..135 'o': Option<u32>
             151..152 'o': Option<u32>
-            151..161 'o.as_ref()': Option<&u32>
+            151..161 'o.as_ref()': Option<&'? u32>
         "#]],
     );
 }
@@ -1551,16 +1551,16 @@ fn infer_type_alias() {
         "#,
         expect![[r#"
             115..116 'x': A<u32, i128>
-            123..124 'y': A<&str, u128>
+            123..124 'y': A<&'? str, u128>
             137..138 'z': A<u8, i8>
             153..210 '{     ...z.y; }': ()
             159..160 'x': A<u32, i128>
             159..162 'x.x': u32
             168..169 'x': A<u32, i128>
             168..171 'x.y': i128
-            177..178 'y': A<&str, u128>
-            177..180 'y.x': &str
-            186..187 'y': A<&str, u128>
+            177..178 'y': A<&'? str, u128>
+            177..180 'y.x': &'? str
+            186..187 'y': A<&'? str, u128>
             186..189 'y.y': u128
             195..196 'z': A<u8, i8>
             195..198 'z.x': u8
@@ -1572,8 +1572,8 @@ fn infer_type_alias() {
             312..328 'm::Ali...Foo(0)': Enum
             326..327 '0': u8
             338..354 'm::Ali...Foo(x)': Enum
-            352..353 'x': &u8
-            357..359 '&e': &Enum
+            352..353 'x': &'? u8
+            357..359 '&e': &'? Enum
             358..359 'e': Enum
         "#]],
     )
@@ -1618,10 +1618,10 @@ fn infer_type_param() {
             9..10 'x': T
             20..29 '{     x }': T
             26..27 'x': T
-            43..44 'x': &T
+            43..44 'x': &'? T
             55..65 '{     *x }': T
             61..63 '*x': T
-            62..63 'x': &T
+            62..63 'x': &'? T
             77..157 '{     ...(1); }': ()
             87..88 'y': u32
             91..96 '10u32': u32
@@ -1629,9 +1629,9 @@ fn infer_type_param() {
             102..107 'id(y)': u32
             105..106 'y': u32
             117..118 'x': bool
-            127..132 'clone': fn clone<bool>(&bool) -> bool
+            127..132 'clone': fn clone<bool>(&'? bool) -> bool
             127..135 'clone(z)': bool
-            133..134 'z': &bool
+            133..134 'z': &'? bool
             141..151 'id::<i128>': fn id<i128>(i128) -> i128
             141..154 'id::<i128>(1)': i128
             152..153 '1': i128
@@ -1842,7 +1842,7 @@ fn foo() -> &'static str { "" }
 
 fn main() {
     foo();
-  //^^^^^ &str
+  //^^^^^ &'static str
 }"#,
     );
 }
@@ -1940,10 +1940,10 @@ fn closure_return_inferred() {
         "#,
         expect![[r#"
             16..46 '{     ..." }; }': u32
-            26..27 'x': impl Fn() -> &str
-            30..43 '|| { "test" }': impl Fn() -> &str
-            33..43 '{ "test" }': &str
-            35..41 '"test"': &str
+            26..27 'x': impl Fn() -> &'static str
+            30..43 '|| { "test" }': impl Fn() -> &'static str
+            33..43 '{ "test" }': &'static str
+            35..41 '"test"': &'static str
         "#]],
     );
 }
@@ -1975,10 +1975,10 @@ fn test() {
             70..71 'v': i64
             78..80 '{}': ()
             91..362 '{     ...   } }': ()
-            101..106 'mut g': |usize| yields i64 -> &str
-            109..218 '|r| { ...     }': |usize| yields i64 -> &str
+            101..106 'mut g': |usize| yields i64 -> &'static str
+            109..218 '|r| { ...     }': |usize| yields i64 -> &'static str
             110..111 'r': usize
-            113..218 '{     ...     }': &str
+            113..218 '{     ...     }': &'static str
             127..128 'a': usize
             131..138 'yield 0': usize
             137..138 '0': i64
@@ -1988,22 +1988,22 @@ fn test() {
             177..178 'a': usize
             181..188 'yield 2': usize
             187..188 '2': i64
-            198..212 '"return value"': &str
+            198..212 '"return value"': &'static str
             225..360 'match ...     }': ()
-            231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
-            231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
-            231..262 'Pin::n...usize)': CoroutineState<i64, &str>
-            240..246 '&mut g': &mut |usize| yields i64 -> &str
-            245..246 'g': |usize| yields i64 -> &str
+            231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str>
+            231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str>
+            231..262 'Pin::n...usize)': CoroutineState<i64, &'static str>
+            240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str
+            245..246 'g': |usize| yields i64 -> &'static str
             255..261 '0usize': usize
-            273..299 'Corout...ded(y)': CoroutineState<i64, &str>
+            273..299 'Corout...ded(y)': CoroutineState<i64, &'static str>
             297..298 'y': i64
             303..312 '{ f(y); }': ()
             305..306 'f': fn f(i64)
             305..309 'f(y)': ()
             307..308 'y': i64
-            321..348 'Corout...ete(r)': CoroutineState<i64, &str>
-            346..347 'r': &str
+            321..348 'Corout...ete(r)': CoroutineState<i64, &'static str>
+            346..347 'r': &'static str
             352..354 '{}': ()
         "#]],
     );
@@ -2050,7 +2050,7 @@ fn f(x: (&&&&i32, &&&i32)) {
         _ => loop {},
     };
     f;
-  //^ (&&&&i32, &&&i32)
+  //^ (&'? &'? &'? &'? i32, &'? &'? &'? i32)
 }
         "#,
     );
@@ -2059,10 +2059,10 @@ fn f(x: (&&&&i32, &&&i32)) {
 fn f() {
     let x = &&&(&&&2, &&&&&3);
     let (y, z) = x;
-       //^ &&&&i32
+       //^ &'? &'? &'? &'? i32
     let t @ (y, z) = x;
     t;
-  //^ &&&(&&&i32, &&&&&i32)
+  //^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32)
 }
         "#,
     );
@@ -2071,10 +2071,10 @@ fn f() {
 fn f() {
     let x = &&&(&&&2, &&&&&3);
     let (y, z) = x;
-       //^ &&&&i32
+       //^ &'? &'? &'? &'? i32
     let t @ (y, z) = x;
     t;
-  //^ &&&(&&&i32, &&&&&i32)
+  //^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32)
 }
         "#,
     );
@@ -2761,23 +2761,23 @@ impl S {
 fn f() {
     let x = S;
     let c1 = || x.read();
-      //^^ impl Fn() -> &S
+      //^^ impl Fn() -> &'? S
     let c2 = || x.write();
-      //^^ impl FnMut() -> &mut S
+      //^^ impl FnMut() -> &'? mut S
     let c3 = || x.consume();
       //^^ impl FnOnce() -> S
     let c3 = || x.consume().consume().consume();
       //^^ impl FnOnce() -> S
     let c3 = || x.consume().write().read();
-      //^^ impl FnOnce() -> &S
+      //^^ impl FnOnce() -> &'? S
     let x = &mut x;
     let c1 = || x.write();
-      //^^ impl FnMut() -> &mut S
+      //^^ impl FnMut() -> &'? mut S
     let x = S;
     let c1 = || { let ref t = x; t };
-      //^^ impl Fn() -> &S
+      //^^ impl Fn() -> &'? S
     let c2 = || { let ref mut t = x; t };
-      //^^ impl FnMut() -> &mut S
+      //^^ impl FnMut() -> &'? mut S
     let c3 = || { let t = x; t };
       //^^ impl FnOnce() -> S
 }
@@ -3074,11 +3074,11 @@ fn main() {
 }
         "#,
         expect![[r#"
-            104..108 'self': &Box<T>
-            188..192 'self': &Box<Foo<T>>
-            218..220 '{}': &T
-            242..246 'self': &Box<Foo<T>>
-            275..277 '{}': &Foo<T>
+            104..108 'self': &'? Box<T>
+            188..192 'self': &'a Box<Foo<T>>
+            218..220 '{}': &'a T
+            242..246 'self': &'a Box<Foo<T>>
+            275..277 '{}': &'a Foo<T>
             297..301 'self': Box<Foo<T>>
             322..324 '{}': Foo<T>
             338..559 '{     ...r(); }': ()
@@ -3088,21 +3088,21 @@ fn main() {
             360..363 'Foo': extern "rust-call" Foo<i32>(i32) -> Foo<i32>
             360..370 'Foo(0_i32)': Foo<i32>
             364..369 '0_i32': i32
-            382..386 'bad1': &i32
+            382..386 'bad1': &'? i32
             389..394 'boxed': Box<Foo<i32>>
-            389..406 'boxed....nner()': &i32
-            416..421 'good1': &i32
-            424..438 'Foo::get_inner': fn get_inner<i32, '{error}>(&Box<Foo<i32>>) -> &i32
-            424..446 'Foo::g...boxed)': &i32
-            439..445 '&boxed': &Box<Foo<i32>>
+            389..406 'boxed....nner()': &'? i32
+            416..421 'good1': &'? i32
+            424..438 'Foo::get_inner': fn get_inner<i32, '?>(&'? Box<Foo<i32>>) -> &'? i32
+            424..446 'Foo::g...boxed)': &'? i32
+            439..445 '&boxed': &'? Box<Foo<i32>>
             440..445 'boxed': Box<Foo<i32>>
-            457..461 'bad2': &Foo<i32>
+            457..461 'bad2': &'? Foo<i32>
             464..469 'boxed': Box<Foo<i32>>
-            464..480 'boxed....self()': &Foo<i32>
-            490..495 'good2': &Foo<i32>
-            498..511 'Foo::get_self': fn get_self<i32, '{error}>(&Box<Foo<i32>>) -> &Foo<i32>
-            498..519 'Foo::g...boxed)': &Foo<i32>
-            512..518 '&boxed': &Box<Foo<i32>>
+            464..480 'boxed....self()': &'? Foo<i32>
+            490..495 'good2': &'? Foo<i32>
+            498..511 'Foo::get_self': fn get_self<i32, '?>(&'? Box<Foo<i32>>) -> &'? Foo<i32>
+            498..519 'Foo::g...boxed)': &'? Foo<i32>
+            512..518 '&boxed': &'? Box<Foo<i32>>
             513..518 'boxed': Box<Foo<i32>>
             530..535 'inner': Foo<i32>
             538..543 'boxed': Box<Foo<i32>>
@@ -3414,31 +3414,31 @@ struct TS(usize);
 fn main() {
     let x;
     [x,] = &[1,];
-  //^^^^expected &[i32; 1], got [{unknown}; _]
+  //^^^^expected &'? [i32; 1], got [{unknown}; _]
 
     let x;
     [(x,),] = &[(1,),];
-  //^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
+  //^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
 
     let x;
     ((x,),) = &((1,),);
-  //^^^^^^^expected &((i32,),), got (({unknown},),)
+  //^^^^^^^expected &'? ((i32,),), got (({unknown},),)
 
     let x;
     (x,) = &(1,);
-  //^^^^expected &(i32,), got ({unknown},)
+  //^^^^expected &'? (i32,), got ({unknown},)
 
     let x;
     (S { a: x },) = &(S { a: 42 },);
-  //^^^^^^^^^^^^^expected &(S,), got (S,)
+  //^^^^^^^^^^^^^expected &'? (S,), got (S,)
 
     let x;
     S { a: x } = &S { a: 42 };
-  //^^^^^^^^^^expected &S, got S
+  //^^^^^^^^^^expected &'? S, got S
 
     let x;
     TS(x) = &TS(42);
-  //^^^^^expected &TS, got TS
+  //^^^^^expected &'? TS, got TS
 }
         "#,
     );
@@ -3548,17 +3548,17 @@ fn f<T>(t: Ark<T>) {
 }
 "#,
         expect![[r#"
-            47..51 'self': &Ark<T>
+            47..51 'self': &'? Ark<T>
             65..88 '{     ...     }': *const T
-            75..82 '&self.0': &T
-            76..80 'self': &Ark<T>
+            75..82 '&self.0': &'? T
+            76..80 'self': &'? Ark<T>
             76..82 'self.0': T
             99..100 't': Ark<T>
             110..144 '{     ... (); }': ()
-            116..124 'Ark::foo': fn foo<T>(&Ark<T>) -> *const T
+            116..124 'Ark::foo': fn foo<T>(&'? Ark<T>) -> *const T
             116..128 'Ark::foo(&t)': *const T
             116..141 'Ark::f...nst ()': *const ()
-            125..127 '&t': &Ark<T>
+            125..127 '&t': &'? Ark<T>
             126..127 't': Ark<T>
         "#]],
     );
@@ -3632,7 +3632,7 @@ pub struct CStr;
 
 fn main() {
     c"ello";
-  //^^^^^^^ &CStr
+  //^^^^^^^ &'static CStr
 }
 "#,
     );
@@ -3659,7 +3659,25 @@ fn main() {
     let are = "are";
     let count = 10;
     builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'{error}>
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'?>
+}
+"#,
+    );
+}
+
+#[test]
+fn inline_const_expression() {
+    check(
+        r#"
+fn main() {
+    let foo = 0;
+    const {
+        let bar = 1;
+        let unresolved = foo;
+         // ^^^^^^^^^^ type: {unknown}
+        let resolved = bar;
+         // ^^^^^^^^ type: i32
+    }
 }
 "#,
     );
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 dfcd322a39c..18fc8afd183 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
@@ -238,6 +238,7 @@ fn infer_for_loop() {
 //- minicore: iterator
 //- /main.rs crate:main deps:alloc
 #![no_std]
+extern crate alloc;
 use alloc::collections::Vec;
 
 fn test() {
@@ -245,7 +246,7 @@ fn test() {
     v.push("foo");
     for x in v {
         x;
-    } //^ &str
+    } //^ &'static str
 }
 
 //- /alloc.rs crate:alloc
@@ -575,7 +576,7 @@ fn indexing_arrays() {
         "fn main() { &mut [9][2]; }",
         expect![[r#"
             10..26 '{ &mut...[2]; }': ()
-            12..23 '&mut [9][2]': &mut {unknown}
+            12..23 '&mut [9][2]': &'? mut {unknown}
             17..20 '[9]': [i32; 1]
             17..23 '[9][2]': {unknown}
             18..19 '9': i32
@@ -873,7 +874,7 @@ impl<U, T: Trait<U>> O<T> {
 
 fn test(o: O<S>) {
     o.foo();
-} //^^^^^^^ &str
+} //^^^^^^^ &'? str
 "#,
     );
 }
@@ -1016,15 +1017,15 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
     z.foo2();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
-            54..58 'self': &Self
+            29..33 'self': &'? Self
+            54..58 'self': &'? Self
             77..78 'x': impl Trait<u16>
             97..99 '{}': ()
             154..155 'x': impl Trait<u64>
-            174..175 'y': &impl Trait<u32>
+            174..175 'y': &'? impl Trait<u32>
             195..323 '{     ...2(); }': ()
             201..202 'x': impl Trait<u64>
-            208..209 'y': &impl Trait<u32>
+            208..209 'y': &'? impl Trait<u32>
             219..220 'z': S<u16>
             223..224 'S': extern "rust-call" S<u16>(u16) -> S<u16>
             223..227 'S(1)': S<u16>
@@ -1034,13 +1035,13 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
             237..238 'z': S<u16>
             245..246 'x': impl Trait<u64>
             245..252 'x.foo()': u64
-            258..259 'y': &impl Trait<u32>
+            258..259 'y': &'? impl Trait<u32>
             258..265 'y.foo()': u32
             271..272 'z': S<u16>
             271..278 'z.foo()': u16
             284..285 'x': impl Trait<u64>
             284..292 'x.foo2()': i64
-            298..299 'y': &impl Trait<u32>
+            298..299 'y': &'? impl Trait<u32>
             298..306 'y.foo2()': i64
             312..313 'z': S<u16>
             312..320 'z.foo2()': i64
@@ -1204,26 +1205,26 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
     z.foo2();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
-            54..58 'self': &Self
+            29..33 'self': &'? Self
+            54..58 'self': &'? Self
             98..100 '{}': ()
             110..111 'x': impl Trait<u64>
-            130..131 'y': &impl Trait<u64>
+            130..131 'y': &'? impl Trait<u64>
             151..268 '{     ...2(); }': ()
             157..158 'x': impl Trait<u64>
-            164..165 'y': &impl Trait<u64>
+            164..165 'y': &'? impl Trait<u64>
             175..176 'z': impl Trait<u64>
             179..182 'bar': fn bar() -> impl Trait<u64>
             179..184 'bar()': impl Trait<u64>
             190..191 'x': impl Trait<u64>
             190..197 'x.foo()': u64
-            203..204 'y': &impl Trait<u64>
+            203..204 'y': &'? impl Trait<u64>
             203..210 'y.foo()': u64
             216..217 'z': impl Trait<u64>
             216..223 'z.foo()': u64
             229..230 'x': impl Trait<u64>
             229..237 'x.foo2()': i64
-            243..244 'y': &impl Trait<u64>
+            243..244 'y': &'? impl Trait<u64>
             243..251 'y.foo2()': i64
             257..258 'z': impl Trait<u64>
             257..265 'z.foo2()': i64
@@ -1328,7 +1329,7 @@ fn test() {
     a.foo();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
+            29..33 'self': &'? Self
             71..82 '{ loop {} }': !
             73..80 'loop {}': !
             78..80 '{}': ()
@@ -1366,8 +1367,8 @@ fn test() {
     d.foo();
 }"#,
         expect![[r#"
-            49..53 'self': &mut Self
-            101..105 'self': &Self
+            49..53 'self': &'? mut Self
+            101..105 'self': &'? Self
             184..195 '{ loop {} }': ({unknown}, {unknown})
             186..193 'loop {}': !
             191..193 '{}': ()
@@ -1414,10 +1415,10 @@ fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
 }
 "#,
         expect![[r#"
-            134..165 '{     ...(C)) }': (impl FnOnce(&str, T), Bar<u8>)
-            140..163 '(|inpu...ar(C))': (impl FnOnce(&str, T), Bar<u8>)
-            141..154 '|input, t| {}': impl FnOnce(&str, T)
-            142..147 'input': &str
+            134..165 '{     ...(C)) }': (impl FnOnce(&'? str, T), Bar<u8>)
+            140..163 '(|inpu...ar(C))': (impl FnOnce(&'? str, T), Bar<u8>)
+            141..154 '|input, t| {}': impl FnOnce(&'? str, T)
+            142..147 'input': &'? str
             149..150 't': T
             152..154 '{}': ()
             156..159 'Bar': extern "rust-call" Bar<u8>(u8) -> Bar<u8>
@@ -1466,26 +1467,26 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
     z.foo2();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
-            54..58 'self': &Self
+            29..33 'self': &'? Self
+            54..58 'self': &'? Self
             97..99 '{}': dyn Trait<u64>
             109..110 'x': dyn Trait<u64>
-            128..129 'y': &dyn Trait<u64>
+            128..129 'y': &'? dyn Trait<u64>
             148..265 '{     ...2(); }': ()
             154..155 'x': dyn Trait<u64>
-            161..162 'y': &dyn Trait<u64>
+            161..162 'y': &'? dyn Trait<u64>
             172..173 'z': dyn Trait<u64>
             176..179 'bar': fn bar() -> dyn Trait<u64>
             176..181 'bar()': dyn Trait<u64>
             187..188 'x': dyn Trait<u64>
             187..194 'x.foo()': u64
-            200..201 'y': &dyn Trait<u64>
+            200..201 'y': &'? dyn Trait<u64>
             200..207 'y.foo()': u64
             213..214 'z': dyn Trait<u64>
             213..220 'z.foo()': u64
             226..227 'x': dyn Trait<u64>
             226..234 'x.foo2()': i64
-            240..241 'y': &dyn Trait<u64>
+            240..241 'y': &'? dyn Trait<u64>
             240..248 'y.foo2()': i64
             254..255 'z': dyn Trait<u64>
             254..262 'z.foo2()': i64
@@ -1514,16 +1515,16 @@ fn test(s: S<u32, i32>) {
     s.bar().baz();
 }"#,
         expect![[r#"
-            32..36 'self': &Self
-            102..106 'self': &S<T, U>
-            128..139 '{ loop {} }': &dyn Trait<T, U>
+            32..36 'self': &'? Self
+            102..106 'self': &'? S<T, U>
+            128..139 '{ loop {} }': &'? dyn Trait<T, U>
             130..137 'loop {}': !
             135..137 '{}': ()
-            175..179 'self': &Self
+            175..179 'self': &'? Self
             251..252 's': S<u32, i32>
             267..289 '{     ...z(); }': ()
             273..274 's': S<u32, i32>
-            273..280 's.bar()': &dyn Trait<u32, i32>
+            273..280 's.bar()': &'? dyn Trait<u32, i32>
             273..286 's.bar().baz()': (u32, i32)
         "#]],
     );
@@ -1548,19 +1549,19 @@ fn test(x: Trait, y: &Trait) -> u64 {
     z.foo();
 }"#,
         expect![[r#"
-            26..30 'self': &Self
+            26..30 'self': &'? Self
             60..62 '{}': dyn Trait
             72..73 'x': dyn Trait
-            82..83 'y': &dyn Trait
+            82..83 'y': &'? dyn Trait
             100..175 '{     ...o(); }': u64
             106..107 'x': dyn Trait
-            113..114 'y': &dyn Trait
+            113..114 'y': &'? dyn Trait
             124..125 'z': dyn Trait
             128..131 'bar': fn bar() -> dyn Trait
             128..133 'bar()': dyn Trait
             139..140 'x': dyn Trait
             139..146 'x.foo()': u64
-            152..153 'y': &dyn Trait
+            152..153 'y': &'? dyn Trait
             152..159 'y.foo()': u64
             165..166 'z': dyn Trait
             165..172 'z.foo()': u64
@@ -1580,14 +1581,14 @@ fn main() {
 }
         "#,
         expect![[r#"
-            31..35 'self': &S
+            31..35 'self': &'? S
             37..39 '{}': ()
-            47..48 '_': &dyn Fn(S)
+            47..48 '_': &'? dyn Fn(S)
             58..60 '{}': ()
             71..105 '{     ...()); }': ()
-            77..78 'f': fn f(&dyn Fn(S))
+            77..78 'f': fn f(&'? dyn Fn(S))
             77..102 'f(&|nu...foo())': ()
-            79..101 '&|numb....foo()': &impl Fn(S)
+            79..101 '&|numb....foo()': &'? impl Fn(S)
             80..101 '|numbe....foo()': impl Fn(S)
             81..87 'number': S
             89..95 'number': S
@@ -1790,7 +1791,7 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
     y.foo();
 }"#,
         expect![[r#"
-            53..57 'self': &Self
+            53..57 'self': &'? Self
             66..68 '{}': u32
             185..186 'x': T
             191..192 'y': U
@@ -1819,11 +1820,11 @@ fn test(x: &impl Trait1) {
     x.foo();
 }"#,
         expect![[r#"
-            53..57 'self': &Self
+            53..57 'self': &'? Self
             66..68 '{}': u32
-            119..120 'x': &impl Trait1
+            119..120 'x': &'? impl Trait1
             136..152 '{     ...o(); }': ()
-            142..143 'x': &impl Trait1
+            142..143 'x': &'? impl Trait1
             142..149 'x.foo()': u32
         "#]],
     );
@@ -1934,8 +1935,8 @@ fn test() {
     opt.map(f);
 }"#,
         expect![[r#"
-            28..32 'self': &Self
-            132..136 'self': &Bar<F>
+            28..32 'self': &'? Self
+            132..136 'self': &'? Bar<F>
             149..160 '{ loop {} }': (A1, R)
             151..158 'loop {}': !
             156..158 '{}': ()
@@ -1988,7 +1989,7 @@ fn test() {
     let r2 = lazy2.foo();
 }"#,
         expect![[r#"
-            36..40 'self': &Foo
+            36..40 'self': &'? Foo
             51..53 '{}': usize
             131..132 'f': F
             151..153 '{}': Lazy<T, F>
@@ -2262,14 +2263,14 @@ impl Trait for S2 {
     fn f(&self, x: <Self>::Item) { let y = x; }
 }"#,
         expect![[r#"
-            40..44 'self': &Self
+            40..44 'self': &'? Self
             46..47 'x': Trait::Item<Self>
-            126..130 'self': &S
+            126..130 'self': &'? S
             132..133 'x': u32
             147..161 '{ let y = x; }': ()
             153..154 'y': u32
             157..158 'x': u32
-            228..232 'self': &S2
+            228..232 'self': &'? S2
             234..235 'x': i32
             251..265 '{ let y = x; }': ()
             257..258 'y': i32
@@ -2643,12 +2644,12 @@ fn main() {
             72..74 '_v': F
             117..120 '{ }': ()
             132..163 '{     ... }); }': ()
-            138..148 'f::<(), _>': fn f<(), impl FnOnce(&())>(impl FnOnce(&()))
+            138..148 'f::<(), _>': fn f<(), impl FnOnce(&'? ())>(impl FnOnce(&'? ()))
             138..160 'f::<()... z; })': ()
-            149..159 '|z| { z; }': impl FnOnce(&())
-            150..151 'z': &()
+            149..159 '|z| { z; }': impl FnOnce(&'? ())
+            150..151 'z': &'? ()
             153..159 '{ z; }': ()
-            155..156 'z': &()
+            155..156 'z': &'? ()
         "#]],
     );
 }
@@ -2897,13 +2898,13 @@ fn test(x: &dyn Foo) {
     foo(x);
 }"#,
         expect![[r#"
-            21..22 'x': &dyn Foo
+            21..22 'x': &'? dyn Foo
             34..36 '{}': ()
-            46..47 'x': &dyn Foo
+            46..47 'x': &'? dyn Foo
             59..74 '{     foo(x); }': ()
-            65..68 'foo': fn foo(&dyn Foo)
+            65..68 'foo': fn foo(&'? dyn Foo)
             65..71 'foo(x)': ()
-            69..70 'x': &dyn Foo
+            69..70 'x': &'? dyn Foo
         "#]],
     );
 }
@@ -2927,7 +2928,7 @@ fn test() {
     (IsCopy, NotCopy).test();
 }"#,
         expect![[r#"
-            78..82 'self': &Self
+            78..82 'self': &'? Self
             134..235 '{     ...t(); }': ()
             140..146 'IsCopy': IsCopy
             140..153 'IsCopy.test()': bool
@@ -2969,7 +2970,7 @@ fn test() {
             28..29 'T': {unknown}
             36..38 '{}': T
             36..38: expected T, got ()
-            113..117 'self': &Self
+            113..117 'self': &'? Self
             169..249 '{     ...t(); }': ()
             175..178 'foo': fn foo()
             175..185 'foo.test()': bool
@@ -2997,16 +2998,16 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
     f3.test();
 }"#,
         expect![[r#"
-            22..26 'self': &Self
+            22..26 'self': &'? Self
             76..78 'f1': fn()
             86..88 'f2': fn(usize) -> u8
-            107..109 'f3': fn(u8, u8) -> &u8
+            107..109 'f3': fn(u8, u8) -> &'? u8
             130..178 '{     ...t(); }': ()
             136..138 'f1': fn()
             136..145 'f1.test()': bool
             151..153 'f2': fn(usize) -> u8
             151..160 'f2.test()': bool
-            166..168 'f3': fn(u8, u8) -> &u8
+            166..168 'f3': fn(u8, u8) -> &'? u8
             166..175 'f3.test()': bool
         "#]],
     );
@@ -3027,13 +3028,13 @@ fn test() {
     (1u8, *"foo").test(); // not Sized
 }"#,
         expect![[r#"
-            22..26 'self': &Self
+            22..26 'self': &'? Self
             79..194 '{     ...ized }': ()
             85..88 '1u8': u8
             85..95 '1u8.test()': bool
             101..116 '(*"foo").test()': {unknown}
             102..108 '*"foo"': str
-            103..108 '"foo"': &str
+            103..108 '"foo"': &'static str
             135..145 '(1u8, 1u8)': (u8, u8)
             135..152 '(1u8, ...test()': bool
             136..139 '1u8': u8
@@ -3042,7 +3043,7 @@ fn test() {
             158..178 '(1u8, ...test()': {unknown}
             159..162 '1u8': u8
             164..170 '*"foo"': str
-            165..170 '"foo"': &str
+            165..170 '"foo"': &'static str
         "#]],
     );
 }
@@ -3093,7 +3094,7 @@ fn foo() {
             93..94 'x': Option<i32>
             109..111 '{}': ()
             117..124 '(&f)(s)': ()
-            118..120 '&f': &impl Fn(Option<i32>)
+            118..120 '&f': &'? impl Fn(Option<i32>)
             119..120 'f': impl Fn(Option<i32>)
             122..123 's': Option<i32>
         "#]],
@@ -3170,25 +3171,25 @@ fn foo() {
     f(&s);
 }"#,
         expect![[r#"
-            154..158 'self': &Box<T>
-            166..205 '{     ...     }': &T
-            176..199 'unsafe...nner }': &T
-            185..197 '&*self.inner': &T
+            154..158 'self': &'? Box<T>
+            166..205 '{     ...     }': &'? T
+            176..199 'unsafe...nner }': &'? T
+            185..197 '&*self.inner': &'? T
             186..197 '*self.inner': T
-            187..191 'self': &Box<T>
+            187..191 'self': &'? Box<T>
             187..197 'self.inner': *mut T
             218..324 '{     ...&s); }': ()
             228..229 's': Option<i32>
             232..236 'None': Option<i32>
-            246..247 'f': Box<dyn FnOnce(&Option<i32>)>
-            281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
-            294..308 '&mut (|ps| {})': &mut impl FnOnce(&Option<i32>)
-            300..307 '|ps| {}': impl FnOnce(&Option<i32>)
-            301..303 'ps': &Option<i32>
+            246..247 'f': Box<dyn FnOnce(&'? Option<i32>)>
+            281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>)>
+            294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option<i32>)
+            300..307 '|ps| {}': impl FnOnce(&'? Option<i32>)
+            301..303 'ps': &'? Option<i32>
             305..307 '{}': ()
-            316..317 'f': Box<dyn FnOnce(&Option<i32>)>
+            316..317 'f': Box<dyn FnOnce(&'? Option<i32>)>
             316..321 'f(&s)': ()
-            318..320 '&s': &Option<i32>
+            318..320 '&s': &'? Option<i32>
             319..320 's': Option<i32>
         "#]],
     );
@@ -3320,7 +3321,7 @@ fn f() {
     }
 }"#,
         expect![[r#"
-            46..50 'self': &Self
+            46..50 'self': &'? Self
             58..63 '{ 0 }': u8
             60..61 '0': u8
             115..185 '{     ...   } }': ()
@@ -3595,7 +3596,7 @@ fn take_u32(_: u32) {}
 fn minimized() {
     let v = V::default();
     let p = v.get(&0);
-      //^ &u32
+      //^ &'? u32
     take_u32(42 + p);
 }
 "#,
@@ -3625,7 +3626,7 @@ fn take_u32(_: u32) {}
 fn minimized() {
     let v = V::default();
     let p = v.get();
-      //^ &{unknown}
+      //^ &'? {unknown}
     take_u32(42 + p);
 }
 "#,
@@ -3684,11 +3685,11 @@ fn main() {
 }
 "#,
         expect![[r#"
-            44..48 'self': &Self
-            133..137 'self': &[u8; 4]
+            44..48 'self': &'? Self
+            133..137 'self': &'? [u8; 4]
             155..172 '{     ...     }': usize
             165..166 '2': usize
-            236..240 'self': &[u8; 2]
+            236..240 'self': &'? [u8; 2]
             258..275 '{     ...     }': u8
             268..269 '2': u8
             289..392 '{     ...g(); }': ()
@@ -3732,11 +3733,11 @@ fn main() {
 }
 "#,
         expect![[r#"
-            44..48 'self': &Self
-            151..155 'self': &[u8; L]
+            44..48 'self': &'? Self
+            151..155 'self': &'? [u8; L]
             173..194 '{     ...     }': [u8; L]
             183..188 '*self': [u8; L]
-            184..188 'self': &[u8; L]
+            184..188 'self': &'? [u8; L]
             208..260 '{     ...g(); }': ()
             218..219 'v': [u8; 2]
             222..230 '[0u8; 2]': [u8; 2]
@@ -4056,13 +4057,13 @@ fn g(t: &(dyn Sync + T2 + T1 + Send)) {
 }
         "#,
         expect![[r#"
-            68..69 't': &{unknown}
+            68..69 't': &'? {unknown}
             101..103 '{}': ()
-            109..110 't': &{unknown}
+            109..110 't': &'? {unknown}
             142..155 '{     f(t); }': ()
-            148..149 'f': fn f(&{unknown})
+            148..149 'f': fn f(&'? {unknown})
             148..152 'f(t)': ()
-            150..151 't': &{unknown}
+            150..151 't': &'? {unknown}
         "#]],
     );
 
@@ -4105,7 +4106,7 @@ trait Trait {
 }
 
 fn f(t: &dyn Trait<T = (), T = ()>) {}
-   //^&{unknown}
+   //^&'? {unknown}
         "#,
     );
 }
@@ -4175,27 +4176,27 @@ trait Trait {
 
 fn f<T>(v: impl Trait) {
     let a = v.get::<i32>().deref();
-      //^ &i32
+      //^ &'? i32
     let a = v.get::<T>().deref();
-      //^ &T
+      //^ &'? T
 }
 fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
     let a = v.get::<T>();
-      //^ &T
+      //^ &'a T
     let a = v.get::<()>();
-      //^ Trait::Assoc<(), impl Trait<Assoc<T> = &T>>
+      //^ Trait::Assoc<(), impl Trait<Assoc<T> = &'a T>>
 }
 fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
     let a = v.get::<i32>();
-      //^ &i32
+      //^ &'a i32
     let a = v.get::<i64>();
-      //^ &i64
+      //^ &'a i64
 }
 fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
     let a = v.get::<i32>();
-      //^ &i32
+      //^ &'a i32
     let a = v.get::<i64>();
-      //^ &i64
+      //^ &'a i64
 }
     "#,
     );
@@ -4221,12 +4222,12 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
 }
     "#,
         expect![[r#"
-            90..94 'self': &Self
-            127..128 'v': &(dyn Trait<Assoc<i32> = &i32>)
+            90..94 'self': &'? Self
+            127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32>)
             164..195 '{     ...f(); }': ()
-            170..171 'v': &(dyn Trait<Assoc<i32> = &i32>)
-            170..184 'v.get::<i32>()': &i32
-            170..192 'v.get:...eref()': &i32
+            170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32>)
+            170..184 'v.get::<i32>()': &'? i32
+            170..192 'v.get:...eref()': &'? i32
         "#]],
     );
 }
@@ -4487,19 +4488,19 @@ fn derive_macro_bounds() {
             let x = (&Copy).clone();
               //^ Copy
             let x = (&NotCopy).clone();
-              //^ &NotCopy
+              //^ &'? NotCopy
             let x = (&Generic(Copy)).clone();
               //^ Generic<Copy>
             let x = (&Generic(NotCopy)).clone();
-              //^ &Generic<NotCopy>
+              //^ &'? Generic<NotCopy>
             let x: &AssocGeneric<Copy> = &AssocGeneric(NotCopy);
             let x = x.clone();
-              //^ &AssocGeneric<Copy>
+              //^ &'? AssocGeneric<Copy>
             // let x: &AssocGeneric2<Copy> = &AssocGeneric2(NotCopy);
             // let x = x.clone();
             let x: &AssocGeneric3<Copy> = &AssocGeneric3(Generic(NotCopy));
             let x = x.clone();
-              //^ &AssocGeneric3<Copy>
+              //^ &'? AssocGeneric3<Copy>
             let x = (&R1(Vec())).clone();
               //^ R1
             let x = (&R2(R1(Vec()))).clone();
@@ -4582,7 +4583,7 @@ impl B for u16 {
 fn ttt() {
     let inp = Y;
     x::<u16>(&inp);
-           //^^^^ expected &X, got &Y
+           //^^^^ expected &'? X, got &'? Y
 }
 "#,
     );
@@ -4629,7 +4630,7 @@ fn foo() {
     let mut map = SomeMap;
     map["a"] = ();
     map;
-  //^^^ SomeMap<&str>
+  //^^^ SomeMap<&'static str>
 }
 "#,
     );
@@ -4764,3 +4765,62 @@ fn test() {
         "#,
     );
 }
+
+#[test]
+fn associated_type_with_impl_trait_in_tuple() {
+    check_no_mismatches(
+        r#"
+pub trait Iterator {
+    type Item;
+}
+
+pub trait Value {}
+
+fn bar<I: Iterator<Item = (usize, impl Value)>>() {}
+
+fn foo() {
+    bar();
+}
+"#,
+    );
+}
+
+#[test]
+fn associated_type_with_impl_trait_in_nested_tuple() {
+    check_no_mismatches(
+        r#"
+pub trait Iterator {
+    type Item;
+}
+
+pub trait Value {}
+
+fn bar<I: Iterator<Item = ((impl Value, usize), u32)>>() {}
+
+fn foo() {
+    bar();
+}
+"#,
+    );
+}
+
+#[test]
+fn dyn_trait_with_lifetime_in_rpit() {
+    check_types(
+        r#"
+//- minicore: future
+pub struct Box<T> {}
+
+trait Trait {}
+
+pub async fn foo_async<'a>() -> Box<dyn Trait + 'a>  {
+    Box {}
+}
+
+fn foo() {
+    foo_async();
+  //^^^^^^^^^^^impl Future<Output = Box<dyn Trait>> + ?Sized
+}
+"#,
+    )
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 4518422d27e..72272934ab7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -9,9 +9,11 @@ use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDi
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
+pub use hir_def::VariantId;
 use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId};
 use hir_expand::{name::Name, HirFileId, InFile};
 use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
+use triomphe::Arc;
 
 use crate::{AssocItem, Field, Local, MacroKind, Trait, Type};
 
@@ -171,7 +173,7 @@ pub struct MacroError {
 pub struct MacroExpansionParseError {
     pub node: InFile<SyntaxNodePtr>,
     pub precise_location: Option<TextRange>,
-    pub errors: Box<[SyntaxError]>,
+    pub errors: Arc<[SyntaxError]>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -200,6 +202,7 @@ pub struct MalformedDerive {
 pub struct NoSuchField {
     pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
     pub private: bool,
+    pub variant: VariantId,
 }
 
 #[derive(Debug)]
@@ -525,7 +528,7 @@ impl AnyDiagnostic {
             source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
         };
         Some(match d {
-            &InferenceDiagnostic::NoSuchField { field: expr, private } => {
+            &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
                 let expr_or_pat = match expr {
                     ExprOrPatId::ExprId(expr) => {
                         source_map.field_syntax(expr).map(AstPtr::wrap_left)
@@ -534,7 +537,7 @@ impl AnyDiagnostic {
                         source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
                     }
                 };
-                NoSuchField { field: expr_or_pat, private }.into()
+                NoSuchField { field: expr_or_pat, private, variant }.into()
             }
             &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
                 MismatchedArgCount { call_expr: expr_syntax(call_expr)?, expected, found }.into()
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 84f03d111f2..c276e87786d 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -188,28 +188,7 @@ impl HirDisplay for Struct {
             StructKind::Record => {
                 let has_where_clause = write_where_clause(def_id, f)?;
                 if let Some(limit) = f.entity_limit {
-                    let fields = self.fields(f.db);
-                    let count = fields.len().min(limit);
-                    f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-                    if count == 0 {
-                        if fields.is_empty() {
-                            f.write_str("{}")?;
-                        } else {
-                            f.write_str("{ /* … */ }")?;
-                        }
-                    } else {
-                        f.write_str(" {\n")?;
-                        for field in &fields[..count] {
-                            f.write_str("    ")?;
-                            field.hir_fmt(f)?;
-                            f.write_str(",\n")?;
-                        }
-
-                        if fields.len() > count {
-                            f.write_str("    /* … */\n")?;
-                        }
-                        f.write_str("}")?;
-                    }
+                    display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
                 }
             }
             StructKind::Unit => _ = write_where_clause(def_id, f)?,
@@ -226,18 +205,10 @@ impl HirDisplay for Enum {
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
         write_generic_params(def_id, f)?;
-        let has_where_clause = write_where_clause(def_id, f)?;
 
-        let variants = self.variants(f.db);
-        if !variants.is_empty() {
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-            f.write_str("{\n")?;
-            for variant in variants {
-                f.write_str("    ")?;
-                variant.hir_fmt(f)?;
-                f.write_str(",\n")?;
-            }
-            f.write_str("}")?;
+        let has_where_clause = write_where_clause(def_id, f)?;
+        if let Some(limit) = f.entity_limit {
+            display_variants(&self.variants(f.db), has_where_clause, limit, f)?;
         }
 
         Ok(())
@@ -251,22 +222,102 @@ impl HirDisplay for Union {
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
         write_generic_params(def_id, f)?;
+
         let has_where_clause = write_where_clause(def_id, f)?;
+        if let Some(limit) = f.entity_limit {
+            display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
+        }
+        Ok(())
+    }
+}
+
+fn display_fields(
+    fields: &[Field],
+    has_where_clause: bool,
+    limit: usize,
+    in_line: bool,
+    f: &mut HirFormatter<'_>,
+) -> Result<(), HirDisplayError> {
+    let count = fields.len().min(limit);
+    let (indent, separator) = if in_line { ("", ' ') } else { ("    ", '\n') };
+    f.write_char(if !has_where_clause { ' ' } else { separator })?;
+    if count == 0 {
+        if fields.is_empty() {
+            f.write_str("{}")?;
+        } else {
+            f.write_str("{ /* … */ }")?;
+        }
+    } else {
+        f.write_char('{')?;
 
-        let fields = self.fields(f.db);
         if !fields.is_empty() {
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-            f.write_str("{\n")?;
-            for field in self.fields(f.db) {
-                f.write_str("    ")?;
+            f.write_char(separator)?;
+            for field in &fields[..count] {
+                f.write_str(indent)?;
                 field.hir_fmt(f)?;
-                f.write_str(",\n")?;
+                f.write_char(',')?;
+                f.write_char(separator)?;
+            }
+
+            if fields.len() > count {
+                f.write_str(indent)?;
+                f.write_str("/* … */")?;
+                f.write_char(separator)?;
             }
-            f.write_str("}")?;
         }
 
-        Ok(())
+        f.write_str("}")?;
+    }
+
+    Ok(())
+}
+
+fn display_variants(
+    variants: &[Variant],
+    has_where_clause: bool,
+    limit: usize,
+    f: &mut HirFormatter<'_>,
+) -> Result<(), HirDisplayError> {
+    let count = variants.len().min(limit);
+    f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
+    if count == 0 {
+        if variants.is_empty() {
+            f.write_str("{}")?;
+        } else {
+            f.write_str("{ /* … */ }")?;
+        }
+    } else {
+        f.write_str("{\n")?;
+        for variant in &variants[..count] {
+            f.write_str("    ")?;
+            write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?;
+            match variant.kind(f.db) {
+                StructKind::Tuple => {
+                    if variant.fields(f.db).is_empty() {
+                        f.write_str("()")?;
+                    } else {
+                        f.write_str("( /* … */ )")?;
+                    }
+                }
+                StructKind::Record => {
+                    if variant.fields(f.db).is_empty() {
+                        f.write_str(" {}")?;
+                    } else {
+                        f.write_str(" { /* … */ }")?;
+                    }
+                }
+                StructKind::Unit => {}
+            }
+            f.write_str(",\n")?;
+        }
+
+        if variants.len() > count {
+            f.write_str("    /* … */\n")?;
+        }
+        f.write_str("}")?;
     }
+
+    Ok(())
 }
 
 impl HirDisplay for Field {
@@ -304,21 +355,10 @@ impl HirDisplay for Variant {
                 }
                 f.write_char(')')?;
             }
-            VariantData::Record(fields) => {
-                f.write_str(" {")?;
-                let mut first = true;
-                for (_, field) in fields.iter() {
-                    if first {
-                        first = false;
-                        f.write_char(' ')?;
-                    } else {
-                        f.write_str(", ")?;
-                    }
-                    // Enum variant fields must be pub.
-                    write!(f, "{}: ", field.name.display(f.db.upcast()))?;
-                    field.type_ref.hir_fmt(f)?;
+            VariantData::Record(_) => {
+                if let Some(limit) = f.entity_limit {
+                    display_fields(&self.fields(f.db), false, limit, true, f)?;
                 }
-                f.write_str(" }")?;
             }
         }
         Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index bcd94a611a9..85f33a10fcb 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -59,7 +59,9 @@ use hir_def::{
     ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId,
     TypeParamId, UnionId,
 };
-use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind};
+use hir_expand::{
+    attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
+};
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
@@ -79,7 +81,7 @@ use hir_ty::{
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
-use span::Edition;
+use span::{Edition, MacroCallId};
 use stdx::{impl_from, never};
 use syntax::{
     ast::{self, HasAttrs as _, HasName},
@@ -559,6 +561,12 @@ impl Module {
             emit_def_diagnostic(db, acc, diag);
         }
 
+        if !self.id.is_block_module() {
+            // These are reported by the body of block modules
+            let scope = &def_map[self.id.local_id].scope;
+            scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc));
+        }
+
         for def in self.declarations(db) {
             match def {
                 ModuleDef::Module(m) => {
@@ -577,6 +585,10 @@ impl Module {
                         item.diagnostics(db, acc, style_lints);
                     }
 
+                    t.all_macro_calls(db)
+                        .iter()
+                        .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc));
+
                     acc.extend(def.diagnostics(db, style_lints))
                 }
                 ModuleDef::Adt(adt) => {
@@ -621,6 +633,11 @@ impl Module {
                 // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
                 continue;
             }
+            impl_def
+                .all_macro_calls(db)
+                .iter()
+                .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc));
+
             let ast_id_map = db.ast_id_map(file_id);
 
             for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
@@ -809,6 +826,37 @@ impl Module {
     }
 }
 
+fn macro_call_diagnostics(
+    db: &dyn HirDatabase,
+    macro_call_id: MacroCallId,
+    acc: &mut Vec<AnyDiagnostic>,
+) {
+    let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
+        return;
+    };
+    let ValueResult { value: parse_errors, err } = &*e;
+    if let Some(err) = err {
+        let loc = db.lookup_intern_macro_call(macro_call_id);
+        let (node, precise_location, macro_name, kind) = precise_macro_call_location(&loc.kind, db);
+        let diag = match err {
+            &hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
+                UnresolvedProcMacro { node, precise_location, macro_name, kind, krate }.into()
+            }
+            err => MacroError { node, precise_location, message: err.to_string() }.into(),
+        };
+        acc.push(diag);
+    }
+
+    if !parse_errors.is_empty() {
+        let loc = db.lookup_intern_macro_call(macro_call_id);
+        let (node, precise_location, _, _) = precise_macro_call_location(&loc.kind, db);
+        acc.push(
+            MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() }
+                .into(),
+        )
+    }
+}
+
 fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
     let id = db.macro_def(m.id);
     if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) {
@@ -888,16 +936,6 @@ fn emit_def_diagnostic_(
                 .into(),
             );
         }
-        DefDiagnosticKind::MacroError { ast, message } => {
-            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
-            acc.push(MacroError { node, precise_location, message: message.clone() }.into());
-        }
-        DefDiagnosticKind::MacroExpansionParseError { ast, errors } => {
-            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
-            acc.push(
-                MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(),
-            );
-        }
         DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
             let node = ast.to_node(db.upcast());
             // Must have a name, otherwise we wouldn't emit it.
@@ -1489,6 +1527,14 @@ impl Adt {
             .map(|arena| arena.1.clone())
     }
 
+    pub fn as_struct(&self) -> Option<Struct> {
+        if let Self::Struct(v) = self {
+            Some(*v)
+        } else {
+            None
+        }
+    }
+
     pub fn as_enum(&self) -> Option<Enum> {
         if let Self::Enum(v) = self {
             Some(*v)
@@ -1636,6 +1682,10 @@ impl DefWithBody {
             Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
         }
 
+        source_map
+            .macro_calls()
+            .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id.macro_call_id, acc));
+
         for diag in source_map.diagnostics() {
             acc.push(match diag {
                 BodyDiagnostic::InactiveCode { node, cfg, opts } => {
@@ -2437,6 +2487,14 @@ impl Trait {
             .filter(|(_, ty)| !count_required_only || !ty.has_default())
             .count()
     }
+
+    fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
+        db.trait_data(self.id)
+            .macro_calls
+            .as_ref()
+            .map(|it| it.as_ref().clone().into_boxed_slice())
+            .unwrap_or_default()
+    }
 }
 
 impl HasVisibility for Trait {
@@ -2506,6 +2564,15 @@ impl HasVisibility for TypeAlias {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct StaticLifetime;
+
+impl StaticLifetime {
+    pub fn name(self) -> Name {
+        known::STATIC_LIFETIME
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct BuiltinType {
     pub(crate) inner: hir_def::builtin_type::BuiltinType,
 }
@@ -2535,6 +2602,20 @@ impl BuiltinType {
         matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
     }
 
+    pub fn is_f32(&self) -> bool {
+        matches!(
+            self.inner,
+            hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F32)
+        )
+    }
+
+    pub fn is_f64(&self) -> bool {
+        matches!(
+            self.inner,
+            hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F64)
+        )
+    }
+
     pub fn is_char(&self) -> bool {
         matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
     }
@@ -3743,6 +3824,14 @@ impl Impl {
     pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool {
         check_orphan_rules(db, self.id)
     }
+
+    fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
+        db.impl_data(self.id)
+            .macro_calls
+            .as_ref()
+            .map(|it| it.as_ref().clone().into_boxed_slice())
+            .unwrap_or_default()
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -4495,7 +4584,8 @@ impl Type {
         name: Option<&Name>,
         mut callback: impl FnMut(Function) -> Option<T>,
     ) -> Option<T> {
-        let _p = tracing::span!(tracing::Level::INFO, "iterate_method_candidates").entered();
+        let _p =
+            tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered();
         let mut slot = None;
 
         self.iterate_method_candidates_dyn(
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index e792e159acf..6c70cc4baf0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -131,7 +131,7 @@ pub struct SemanticsImpl<'db> {
     pub db: &'db dyn HirDatabase,
     s2d_cache: RefCell<SourceToDefCache>,
     /// Rootnode to HirFileId cache
-    cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
+    root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
     // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens
     // So we might wanna move them out into something specific for semantic highlighting
     expansion_info_cache: RefCell<FxHashMap<MacroFileId, ExpansionInfo>>,
@@ -294,7 +294,7 @@ impl<'db> SemanticsImpl<'db> {
         SemanticsImpl {
             db,
             s2d_cache: Default::default(),
-            cache: Default::default(),
+            root_to_file_cache: Default::default(),
             expansion_info_cache: Default::default(),
             macro_call_cache: Default::default(),
         }
@@ -690,6 +690,7 @@ impl<'db> SemanticsImpl<'db> {
                 exp_info
             });
 
+            // FIXME: uncached parse
             // Create the source analyzer for the macro call scope
             let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file()))
             else {
@@ -722,7 +723,7 @@ impl<'db> SemanticsImpl<'db> {
         mut token: SyntaxToken,
         f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
     ) {
-        let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered();
         let (sa, span, file_id) =
             match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) {
                 Some(sa) => match sa.file_id.file_id() {
@@ -1025,6 +1026,7 @@ impl<'db> SemanticsImpl<'db> {
                 None => {
                     let call_node = file_id.macro_file()?.call_node(db);
                     // cache the node
+                    // FIXME: uncached parse
                     self.parse_or_expand(call_node.file_id);
                     Some(call_node)
                 }
@@ -1370,7 +1372,7 @@ impl<'db> SemanticsImpl<'db> {
         offset: Option<TextSize>,
         infer_body: bool,
     ) -> Option<SourceAnalyzer> {
-        let _p = tracing::span!(tracing::Level::INFO, "Semantics::analyze_impl").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "SemanticsImpl::analyze_impl").entered();
         let node = self.find_file(node);
 
         let container = self.with_ctx(|ctx| ctx.find_container(node))?;
@@ -1397,7 +1399,7 @@ impl<'db> SemanticsImpl<'db> {
 
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
         assert!(root_node.parent().is_none());
-        let mut cache = self.cache.borrow_mut();
+        let mut cache = self.root_to_file_cache.borrow_mut();
         let prev = cache.insert(root_node, file_id);
         assert!(prev.is_none() || prev == Some(file_id))
     }
@@ -1407,7 +1409,7 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
-        let cache = self.cache.borrow();
+        let cache = self.root_to_file_cache.borrow();
         cache.get(root_node).copied()
     }
 
@@ -1427,7 +1429,7 @@ impl<'db> SemanticsImpl<'db> {
                  known nodes: {}\n\n",
                 node,
                 root_node,
-                self.cache
+                self.root_to_file_cache
                     .borrow()
                     .keys()
                     .map(|it| format!("{it:?}"))
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 434e4b5a0cf..d2bd8b0e799 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -118,10 +118,10 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
 
 impl SourceToDefCtx<'_, '_> {
     pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
-        let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "SourceToDefCtx::file_to_def").entered();
         let mut mods = SmallVec::new();
         for &crate_id in self.db.relevant_crates(file).iter() {
-            // FIXME: inner items
+            // Note: `mod` declarations in block modules cannot be supported here
             let crate_def_map = self.db.crate_def_map(crate_id);
             mods.extend(
                 crate_def_map
@@ -129,6 +129,9 @@ impl SourceToDefCtx<'_, '_> {
                     .map(|local_id| crate_def_map.module_id(local_id)),
             )
         }
+        if mods.is_empty() {
+            // FIXME: detached file
+        }
         mods
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index dc96a1b03d0..057b03baef0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -28,7 +28,7 @@ use hir_expand::{
     mod_path::path,
     name,
     name::{AsName, Name},
-    HirFileId, InFile, MacroFileId, MacroFileIdExt,
+    HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt,
 };
 use hir_ty::{
     diagnostics::{
@@ -118,7 +118,7 @@ impl SourceAnalyzer {
     fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
         let src = match expr {
             ast::Expr::MacroExpr(expr) => {
-                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?
+                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
             }
             _ => InFile::new(self.file_id, expr.clone()),
         };
@@ -145,20 +145,20 @@ impl SourceAnalyzer {
         &self,
         db: &dyn HirDatabase,
         expr: InFile<ast::MacroCall>,
-    ) -> Option<InFile<ast::Expr>> {
+    ) -> Option<InMacroFile<ast::Expr>> {
         let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
-        let expanded = db.parse_or_expand(macro_file);
+        let expanded = db.parse_macro_expansion(macro_file).value.0.syntax_node();
         let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
             match stmts.expr()? {
                 ast::Expr::MacroExpr(mac) => {
-                    self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
+                    self.expand_expr(db, InFile::new(macro_file.into(), mac.macro_call()?))?
                 }
-                expr => InFile::new(macro_file, expr),
+                expr => InMacroFile::new(macro_file, expr),
             }
         } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
-            self.expand_expr(db, InFile::new(macro_file, call))?
+            self.expand_expr(db, InFile::new(macro_file.into(), call))?
         } else {
-            InFile::new(macro_file, ast::Expr::cast(expanded)?)
+            InMacroFile::new(macro_file, ast::Expr::cast(expanded)?)
         };
 
         Some(res)
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
index 93e73004911..5c5ddae19e2 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -127,6 +127,13 @@ impl LookupTable {
             self.types_wishlist.insert(ty.clone());
         }
 
+        // Collapse suggestions if there are many
+        if let Some(res) = &res {
+            if res.len() > self.many_threshold {
+                return Some(vec![Expr::Many(ty.clone())]);
+            }
+        }
+
         res
     }
 
@@ -158,6 +165,13 @@ impl LookupTable {
             self.types_wishlist.insert(ty.clone());
         }
 
+        // Collapse suggestions if there are many
+        if let Some(res) = &res {
+            if res.len() > self.many_threshold {
+                return Some(vec![Expr::Many(ty.clone())]);
+            }
+        }
+
         res
     }
 
@@ -255,13 +269,13 @@ pub struct TermSearchConfig {
     pub enable_borrowcheck: bool,
     /// Indicate when to squash multiple trees to `Many` as there are too many to keep track
     pub many_alternatives_threshold: usize,
-    /// Depth of the search eg. number of cycles to run
-    pub depth: usize,
+    /// Fuel for term search in "units of work"
+    pub fuel: u64,
 }
 
 impl Default for TermSearchConfig {
     fn default() -> Self {
-        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 }
+        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
     }
 }
 
@@ -280,8 +294,7 @@ impl Default for TermSearchConfig {
 ///    transformation tactics. For example functions take as from set of types (arguments) to some
 ///    type (return type). Other transformations include methods on type, type constructors and
 ///    projections to struct fields (field access).
-/// 3. Once we manage to find path to type we are interested in we continue for single round to see
-///    if we can find more paths that take us to the `goal` type.
+/// 3. If we run out of fuel (term search takes too long) we stop iterating.
 /// 4. Return all the paths (type trees) that take us to the `goal` type.
 ///
 /// Note that there are usually more ways we can get to the `goal` type but some are discarded to
@@ -297,21 +310,31 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
     });
 
     let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone());
+    let fuel = std::cell::Cell::new(ctx.config.fuel);
+
+    let should_continue = &|| {
+        let remaining = fuel.get();
+        fuel.set(remaining.saturating_sub(1));
+        if remaining == 0 {
+            tracing::debug!("fuel exhausted");
+        }
+        remaining > 0
+    };
 
     // Try trivial tactic first, also populates lookup table
     let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
     // Use well known types tactic before iterations as it does not depend on other tactics
     solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
 
-    for _ in 0..ctx.config.depth {
+    while should_continue() {
         lookup.new_round();
 
-        solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup));
+        solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
 
         // Discard not interesting `ScopeDef`s for speedup
         for def in lookup.exhausted_scopedefs() {
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
index 2d0c5630e10..9f56a1ee55d 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -211,13 +211,13 @@ impl Expr {
                 }
             }
             Expr::Method { func, target, params, .. } => {
-                if target.contains_many_in_illegal_pos() {
+                if self.contains_many_in_illegal_pos(db) {
                     return Ok(many_formatter(&target.ty(db)));
                 }
 
                 let func_name = func.name(db).display(db.upcast()).to_string();
                 let self_param = func.self_param(db).unwrap();
-                let target = target.gen_source_code(
+                let target_str = target.gen_source_code(
                     sema_scope,
                     many_formatter,
                     prefer_no_std,
@@ -236,9 +236,12 @@ impl Expr {
                     Some(trait_) => {
                         let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
                         let target = match self_param.access(db) {
-                            crate::Access::Shared => format!("&{target}"),
-                            crate::Access::Exclusive => format!("&mut {target}"),
-                            crate::Access::Owned => target,
+                            crate::Access::Shared if !target.is_many() => format!("&{target_str}"),
+                            crate::Access::Exclusive if !target.is_many() => {
+                                format!("&mut {target_str}")
+                            }
+                            crate::Access::Owned => target_str,
+                            _ => many_formatter(&target.ty(db)),
                         };
                         let res = match args.is_empty() {
                             true => format!("{trait_name}::{func_name}({target})",),
@@ -246,7 +249,7 @@ impl Expr {
                         };
                         Ok(res)
                     }
-                    None => Ok(format!("{target}.{func_name}({args})")),
+                    None => Ok(format!("{target_str}.{func_name}({args})")),
                 }
             }
             Expr::Variant { variant, generics, params } => {
@@ -381,7 +384,7 @@ impl Expr {
                 Ok(res)
             }
             Expr::Field { expr, field } => {
-                if expr.contains_many_in_illegal_pos() {
+                if expr.contains_many_in_illegal_pos(db) {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
@@ -395,7 +398,7 @@ impl Expr {
                 Ok(format!("{strukt}.{field}"))
             }
             Expr::Reference(expr) => {
-                if expr.contains_many_in_illegal_pos() {
+                if expr.contains_many_in_illegal_pos(db) {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
@@ -466,10 +469,15 @@ impl Expr {
     /// macro!().bar()
     /// &macro!()
     /// ```
-    fn contains_many_in_illegal_pos(&self) -> bool {
+    fn contains_many_in_illegal_pos(&self, db: &dyn HirDatabase) -> bool {
         match self {
-            Expr::Method { target, .. } => target.contains_many_in_illegal_pos(),
-            Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(),
+            Expr::Method { target, func, .. } => {
+                match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) {
+                    Some(_) => false,
+                    None => target.is_many(),
+                }
+            }
+            Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(db),
             Expr::Reference(target) => target.is_many(),
             Expr::Many(_) => true,
             _ => false,
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
index 63b2a2506f8..a26728272dc 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -4,6 +4,7 @@
 //! * `ctx` - Context for the term search
 //! * `defs` - Set of items in scope at term search target location
 //! * `lookup` - Lookup table for types
+//! * `should_continue` - Function that indicates when to stop iterating
 //! And they return iterator that yields type trees that unify with the `goal` type.
 
 use std::iter;
@@ -97,16 +98,19 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn type_constructor<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     fn variant_helper(
         db: &dyn HirDatabase,
         lookup: &mut LookupTable,
+        should_continue: &dyn std::ops::Fn() -> bool,
         parent_enum: Enum,
         variant: Variant,
         config: &TermSearchConfig,
@@ -152,6 +156,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
             .chain((non_default_type_params_len == 0).then_some(Vec::new()));
 
         generic_params
+            .filter(|_| should_continue())
             .filter_map(move |generics| {
                 // Insert default type params
                 let mut g = generics.into_iter();
@@ -194,8 +199,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
     defs.iter()
         .filter_map(move |def| match def {
             ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
-                let variant_exprs =
-                    variant_helper(db, lookup, it.parent_enum(db), *it, &ctx.config);
+                let variant_exprs = variant_helper(
+                    db,
+                    lookup,
+                    should_continue,
+                    it.parent_enum(db),
+                    *it,
+                    &ctx.config,
+                );
                 if variant_exprs.is_empty() {
                     return None;
                 }
@@ -213,7 +224,9 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
                 let exprs: Vec<(Type, Vec<Expr>)> = enum_
                     .variants(db)
                     .into_iter()
-                    .flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.config))
+                    .flat_map(|it| {
+                        variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
+                    })
                     .collect();
 
                 if exprs.is_empty() {
@@ -271,6 +284,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
                     .chain((non_default_type_params_len == 0).then_some(Vec::new()));
 
                 let exprs = generic_params
+                    .filter(|_| should_continue())
                     .filter_map(|generics| {
                         // Insert default type params
                         let mut g = generics.into_iter();
@@ -345,10 +359,12 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn free_function<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -390,6 +406,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
                     .permutations(non_default_type_params_len);
 
                 let exprs: Vec<_> = generic_params
+                    .filter(|_| should_continue())
                     .filter_map(|generics| {
                         // Insert default type params
                         let mut g = generics.into_iter();
@@ -474,10 +491,12 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn impl_method<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -554,6 +573,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
                 .permutations(non_default_fn_type_params_len);
 
             let exprs: Vec<_> = generic_params
+                .filter(|_| should_continue())
                 .filter_map(|generics| {
                     // Insert default type params
                     let mut g = generics.into_iter();
@@ -645,10 +665,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn struct_projection<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -656,6 +678,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
         .new_types(NewTypesKey::StructProjection)
         .into_iter()
         .map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup")))
+        .filter(|_| should_continue())
         .flat_map(move |(ty, targets)| {
             ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| {
                 if !field.is_visible_from(db, module) {
@@ -716,10 +739,12 @@ pub(super) fn famous_types<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn impl_static_method<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -728,6 +753,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
         .clone()
         .into_iter()
         .chain(iter::once(ctx.goal.clone()))
+        .filter(|_| should_continue())
         .flat_map(|ty| {
             Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
         })
@@ -801,6 +827,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
                 .permutations(non_default_fn_type_params_len);
 
             let exprs: Vec<_> = generic_params
+                .filter(|_| should_continue())
                 .filter_map(|generics| {
                     // Insert default type params
                     let mut g = generics.into_iter();
@@ -884,10 +911,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn make_tuple<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -896,6 +925,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
         .types_wishlist()
         .clone()
         .into_iter()
+        .filter(|_| should_continue())
         .filter(|ty| ty.is_tuple())
         .filter_map(move |ty| {
             // Double check to not contain unknown
@@ -915,6 +945,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
             let exprs: Vec<Expr> = param_exprs
                 .into_iter()
                 .multi_cartesian_product()
+                .filter(|_| should_continue())
                 .map(|params| {
                     let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
                     let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index fbe17dbfd77..5d76cb04323 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -16,4 +16,5 @@ pub struct AssistConfig {
     pub prefer_no_std: bool,
     pub prefer_prelude: bool,
     pub assist_emit_must_use: bool,
+    pub term_search_fuel: u64,
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 55e0d7f3b28..f178a7e0cec 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -8,8 +8,7 @@ use ide_db::{
 };
 use syntax::{
     ast::{self, make, AstNode, Expr::BinExpr, HasArgList},
-    ted::{self, Position},
-    SyntaxKind,
+    ted, SyntaxKind, T,
 };
 
 use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
@@ -62,7 +61,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     let demorganed = bin_expr.clone_subtree().clone_for_update();
 
     ted::replace(demorganed.op_token()?, ast::make::token(inv_token));
-    let mut exprs = VecDeque::from(vec![
+    let mut exprs = VecDeque::from([
         (bin_expr.lhs()?, demorganed.lhs()?),
         (bin_expr.rhs()?, demorganed.rhs()?),
     ]);
@@ -93,58 +92,38 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
         }
     }
 
-    let dm_lhs = demorganed.lhs()?;
-
     acc.add_group(
         &GroupLabel("Apply De Morgan's law".to_owned()),
         AssistId("apply_demorgan", AssistKind::RefactorRewrite),
         "Apply De Morgan's law",
         op_range,
         |edit| {
+            let demorganed = ast::Expr::BinExpr(demorganed);
             let paren_expr = bin_expr.syntax().parent().and_then(ast::ParenExpr::cast);
             let neg_expr = paren_expr
                 .clone()
                 .and_then(|paren_expr| paren_expr.syntax().parent())
                 .and_then(ast::PrefixExpr::cast)
-                .and_then(|prefix_expr| {
-                    if prefix_expr.op_kind()? == ast::UnaryOp::Not {
-                        Some(prefix_expr)
-                    } else {
-                        None
-                    }
-                });
+                .filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not)))
+                .map(ast::Expr::PrefixExpr);
 
             if let Some(paren_expr) = paren_expr {
                 if let Some(neg_expr) = neg_expr {
                     cov_mark::hit!(demorgan_double_negation);
-                    edit.replace_ast(ast::Expr::PrefixExpr(neg_expr), demorganed.into());
+                    let parent = neg_expr.syntax().parent();
+
+                    if parent.is_some_and(|parent| demorganed.needs_parens_in(parent)) {
+                        cov_mark::hit!(demorgan_keep_parens_for_op_precedence2);
+                        edit.replace_ast(neg_expr, make::expr_paren(demorganed));
+                    } else {
+                        edit.replace_ast(neg_expr, demorganed);
+                    };
                 } else {
                     cov_mark::hit!(demorgan_double_parens);
-                    ted::insert_all_raw(
-                        Position::before(dm_lhs.syntax()),
-                        vec![
-                            syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)),
-                            syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)),
-                        ],
-                    );
-
-                    ted::append_child_raw(
-                        demorganed.syntax(),
-                        syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::R_PAREN)),
-                    );
-
-                    edit.replace_ast(ast::Expr::ParenExpr(paren_expr), demorganed.into());
+                    edit.replace_ast(paren_expr.into(), add_bang_paren(demorganed));
                 }
             } else {
-                ted::insert_all_raw(
-                    Position::before(dm_lhs.syntax()),
-                    vec![
-                        syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)),
-                        syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)),
-                    ],
-                );
-                ted::append_child_raw(demorganed.syntax(), ast::make::token(SyntaxKind::R_PAREN));
-                edit.replace_ast(bin_expr, demorganed);
+                edit.replace_ast(bin_expr.into(), add_bang_paren(demorganed));
             }
         },
     )
@@ -271,6 +250,11 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) {
     }
 }
 
+/// Add bang and parentheses to the expression.
+fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
+    make::expr_prefix(T![!], make::expr_paren(expr))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -349,16 +333,14 @@ fn f() { !(S <= S || S < S) }
         check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
     }
 
-    // FIXME : This needs to go.
-    // // https://github.com/rust-lang/rust-analyzer/issues/10963
-    // #[test]
-    // fn demorgan_doesnt_hang() {
-    //     check_assist(
-    //         apply_demorgan,
-    //         "fn f() { 1 || 3 &&$0 4 || 5 }",
-    //         "fn f() { !(!1 || !3 || !4) || 5 }",
-    //     )
-    // }
+    #[test]
+    fn demorgan_doesnt_hang() {
+        check_assist(
+            apply_demorgan,
+            "fn f() { 1 || 3 &&$0 4 || 5 }",
+            "fn f() { 1 || !(!3 || !4) || 5 }",
+        )
+    }
 
     #[test]
     fn demorgan_keep_pars_for_op_precedence() {
@@ -376,6 +358,21 @@ fn f() { !(S <= S || S < S) }
     }
 
     #[test]
+    fn demorgan_keep_pars_for_op_precedence2() {
+        cov_mark::check!(demorgan_keep_parens_for_op_precedence2);
+        check_assist(
+            apply_demorgan,
+            "fn f() { (a && !(b &&$0 c); }",
+            "fn f() { (a && (!b || !c); }",
+        );
+    }
+
+    #[test]
+    fn demorgan_keep_pars_for_op_precedence3() {
+        check_assist(apply_demorgan, "fn f() { (a || !(b &&$0 c); }", "fn f() { (a || !b || !c; }");
+    }
+
+    #[test]
     fn demorgan_removes_pars_in_eq_precedence() {
         check_assist(
             apply_demorgan,
@@ -385,6 +382,11 @@ fn f() { !(S <= S || S < S) }
     }
 
     #[test]
+    fn demorgan_removes_pars_for_op_precedence2() {
+        check_assist(apply_demorgan, "fn f() { (a || !(b ||$0 c); }", "fn f() { (a || !b && !c; }");
+    }
+
+    #[test]
     fn demorgan_iterator_any_all_reverse() {
         check_assist(
             apply_demorgan_iterator,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 76f021ed912..43ff1158864 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -85,7 +85,7 @@ fn edit_struct_def(
     strukt: &Either<ast::Struct, ast::Variant>,
     record_fields: ast::RecordFieldList,
 ) {
-    // Note that we don't need to consider macro files in this function because this this is
+    // Note that we don't need to consider macro files in this function because this is
     // currently not triggered for struct definitions inside macro calls.
     let tuple_fields = record_fields
         .fields()
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 34326294d2e..2b8de3443b4 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
@@ -5623,7 +5623,7 @@ fn func<T: Debug>(i: Struct<'_, T>) {
     fun_name(i);
 }
 
-fn $0fun_name(i: Struct<'_, T>) {
+fn $0fun_name(i: Struct<T>) {
     foo(i);
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index db94a21a6d2..0fc122d623f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -1,6 +1,6 @@
 use hir::{
-    Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics, Type,
-    TypeInfo,
+    Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics,
+    StructKind, Type, TypeInfo,
 };
 use ide_db::{
     base_db::FileId,
@@ -15,8 +15,8 @@ use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::{
     ast::{
-        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, CallExpr, HasArgList,
-        HasGenericParams, HasModuleItem, HasTypeBounds,
+        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr,
+        HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds,
     },
     ted, SyntaxKind, SyntaxNode, TextRange, T,
 };
@@ -66,7 +66,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     }
 
     let fn_name = &*name_ref.text();
-    let TargetInfo { target_module, adt_name, target, file } =
+    let TargetInfo { target_module, adt_info, target, file } =
         fn_target_info(ctx, path, &call, fn_name)?;
 
     if let Some(m) = target_module {
@@ -75,15 +75,16 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
         }
     }
 
-    let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
+    let function_builder =
+        FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target, &adt_info)?;
     let text_range = call.syntax().text_range();
     let label = format!("Generate {} function", function_builder.fn_name);
-    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label)
+    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_info, label)
 }
 
 struct TargetInfo {
     target_module: Option<Module>,
-    adt_name: Option<hir::Name>,
+    adt_info: Option<AdtInfo>,
     target: GeneratedFunctionTarget,
     file: FileId,
 }
@@ -91,11 +92,11 @@ struct TargetInfo {
 impl TargetInfo {
     fn new(
         target_module: Option<Module>,
-        adt_name: Option<hir::Name>,
+        adt_info: Option<AdtInfo>,
         target: GeneratedFunctionTarget,
         file: FileId,
     ) -> Self {
-        Self { target_module, adt_name, target, file }
+        Self { target_module, adt_info, target, file }
     }
 }
 
@@ -157,9 +158,9 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
         target,
     )?;
     let text_range = call.syntax().text_range();
-    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
+    let adt_info = AdtInfo::new(adt, impl_.is_some());
     let label = format!("Generate {} method", function_builder.fn_name);
-    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label)
+    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, Some(adt_info), label)
 }
 
 fn add_func_to_accumulator(
@@ -168,7 +169,7 @@ fn add_func_to_accumulator(
     text_range: TextRange,
     function_builder: FunctionBuilder,
     file: FileId,
-    adt_name: Option<hir::Name>,
+    adt_info: Option<AdtInfo>,
     label: String,
 ) -> Option<()> {
     acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |edit| {
@@ -177,8 +178,14 @@ fn add_func_to_accumulator(
         let target = function_builder.target.clone();
         let func = function_builder.render(ctx.config.snippet_cap, edit);
 
-        if let Some(name) = adt_name {
-            let name = make::ty_path(make::ext::ident_path(&format!("{}", name.display(ctx.db()))));
+        if let Some(adt) =
+            adt_info
+                .and_then(|adt_info| if adt_info.impl_exists { None } else { Some(adt_info.adt) })
+        {
+            let name = make::ty_path(make::ext::ident_path(&format!(
+                "{}",
+                adt.name(ctx.db()).display(ctx.db())
+            )));
 
             // FIXME: adt may have generic params.
             let impl_ = make::impl_(None, None, name, None, None).clone_for_update();
@@ -210,6 +217,7 @@ struct FunctionBuilder {
     generic_param_list: Option<ast::GenericParamList>,
     where_clause: Option<ast::WhereClause>,
     params: ast::ParamList,
+    fn_body: BlockExpr,
     ret_type: Option<ast::RetType>,
     should_focus_return_type: bool,
     visibility: Visibility,
@@ -225,6 +233,7 @@ impl FunctionBuilder {
         fn_name: &str,
         target_module: Option<Module>,
         target: GeneratedFunctionTarget,
+        adt_info: &Option<AdtInfo>,
     ) -> Option<Self> {
         let target_module =
             target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
@@ -243,9 +252,27 @@ impl FunctionBuilder {
         let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
         let is_async = await_expr.is_some();
 
-        let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
-        let (ret_type, should_focus_return_type) =
-            make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params);
+        let ret_type;
+        let should_focus_return_type;
+        let fn_body;
+
+        // If generated function has the name "new" and is an associated function, we generate fn body
+        // as a constructor and assume a "Self" return type.
+        if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) {
+            ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self"))));
+            should_focus_return_type = false;
+            fn_body = body;
+        } else {
+            let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
+            (ret_type, should_focus_return_type) = make_return_type(
+                ctx,
+                &expr_for_ret_ty,
+                target_module,
+                &mut necessary_generic_params,
+            );
+            let placeholder_expr = make::ext::expr_todo();
+            fn_body = make::block_expr(vec![], Some(placeholder_expr));
+        };
 
         let (generic_param_list, where_clause) =
             fn_generic_params(ctx, necessary_generic_params, &target)?;
@@ -256,6 +283,7 @@ impl FunctionBuilder {
             generic_param_list,
             where_clause,
             params,
+            fn_body,
             ret_type,
             should_focus_return_type,
             visibility,
@@ -294,12 +322,16 @@ impl FunctionBuilder {
         let (generic_param_list, where_clause) =
             fn_generic_params(ctx, necessary_generic_params, &target)?;
 
+        let placeholder_expr = make::ext::expr_todo();
+        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
+
         Some(Self {
             target,
             fn_name,
             generic_param_list,
             where_clause,
             params,
+            fn_body,
             ret_type,
             should_focus_return_type,
             visibility,
@@ -308,8 +340,6 @@ impl FunctionBuilder {
     }
 
     fn render(self, cap: Option<SnippetCap>, edit: &mut SourceChangeBuilder) -> ast::Fn {
-        let placeholder_expr = make::ext::expr_todo();
-        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
         let visibility = match self.visibility {
             Visibility::None => None,
             Visibility::Crate => Some(make::visibility_pub_crate()),
@@ -321,7 +351,7 @@ impl FunctionBuilder {
             self.generic_param_list,
             self.where_clause,
             self.params,
-            fn_body,
+            self.fn_body,
             self.ret_type,
             self.is_async,
             false, // FIXME : const and unsafe are not handled yet.
@@ -391,6 +421,53 @@ fn make_return_type(
     (ret_type, should_focus_return_type)
 }
 
+fn make_fn_body_as_new_function(
+    ctx: &AssistContext<'_>,
+    fn_name: &str,
+    adt_info: &Option<AdtInfo>,
+) -> Option<ast::BlockExpr> {
+    if fn_name != "new" {
+        return None;
+    };
+    let adt_info = adt_info.as_ref()?;
+
+    let path_self = make::ext::ident_path("Self");
+    let placeholder_expr = make::ext::expr_todo();
+    let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() {
+        match strukt.kind(ctx.db()) {
+            StructKind::Record => {
+                let fields = strukt
+                    .fields(ctx.db())
+                    .iter()
+                    .map(|field| {
+                        make::record_expr_field(
+                            make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))),
+                            Some(placeholder_expr.clone()),
+                        )
+                    })
+                    .collect::<Vec<_>>();
+
+                make::record_expr(path_self, make::record_expr_field_list(fields)).into()
+            }
+            StructKind::Tuple => {
+                let args = strukt
+                    .fields(ctx.db())
+                    .iter()
+                    .map(|_| placeholder_expr.clone())
+                    .collect::<Vec<_>>();
+
+                make::expr_call(make::expr_path(path_self), make::arg_list(args))
+            }
+            StructKind::Unit => make::expr_path(path_self),
+        }
+    } else {
+        placeholder_expr
+    };
+
+    let fn_body = make::block_expr(vec![], Some(tail_expr));
+    Some(fn_body)
+}
+
 fn get_fn_target_info(
     ctx: &AssistContext<'_>,
     target_module: Option<Module>,
@@ -443,8 +520,8 @@ fn assoc_fn_target_info(
     }
     let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
     let target = get_method_target(ctx, &impl_, &adt)?;
-    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
-    Some(TargetInfo::new(target_module, adt_name, target, file))
+    let adt_info = AdtInfo::new(adt, impl_.is_some());
+    Some(TargetInfo::new(target_module, Some(adt_info), target, file))
 }
 
 #[derive(Clone)]
@@ -560,6 +637,17 @@ impl GeneratedFunctionTarget {
     }
 }
 
+struct AdtInfo {
+    adt: hir::Adt,
+    impl_exists: bool,
+}
+
+impl AdtInfo {
+    fn new(adt: Adt, impl_exists: bool) -> Self {
+        Self { adt, impl_exists }
+    }
+}
+
 /// Computes parameter list for the generated function.
 fn fn_args(
     ctx: &AssistContext<'_>,
@@ -2758,18 +2846,18 @@ fn main() {
             r"
 enum Foo {}
 fn main() {
-    Foo::new$0();
+    Foo::bar$0();
 }
 ",
             r"
 enum Foo {}
 impl Foo {
-    fn new() ${0:-> _} {
+    fn bar() ${0:-> _} {
         todo!()
     }
 }
 fn main() {
-    Foo::new();
+    Foo::bar();
 }
 ",
         )
@@ -2849,4 +2937,152 @@ fn main() {
 ",
         );
     }
+
+    #[test]
+    fn new_function_assume_self_type() {
+        check_assist(
+            generate_function,
+            r"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+impl Foo {
+    fn new() -> Self {
+        ${0:Self { field_1: todo!(), field_2: todo!() }}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_for_tuple_struct() {
+        check_assist(
+            generate_function,
+            r"
+pub struct Foo (usize, String);
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub struct Foo (usize, String);
+impl Foo {
+    fn new() -> Self {
+        ${0:Self(todo!(), todo!())}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_for_unit_struct() {
+        check_assist(
+            generate_function,
+            r"
+pub struct Foo;
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub struct Foo;
+impl Foo {
+    fn new() -> Self {
+        ${0:Self}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_for_enum() {
+        check_assist(
+            generate_function,
+            r"
+pub enum Foo {}
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub enum Foo {}
+impl Foo {
+    fn new() -> Self {
+        ${0:todo!()}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_with_args() {
+        check_assist(
+            generate_function,
+            r#"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+
+struct Baz;
+fn baz() -> Baz { Baz }
+
+fn main() {
+    let foo = Foo::new$0(baz(), baz(), "foo", "bar");
+}
+        "#,
+            r#"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+impl Foo {
+    fn new(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) -> Self {
+        ${0:Self { field_1: todo!(), field_2: todo!() }}
+    }
+}
+
+struct Baz;
+fn baz() -> Baz { Baz }
+
+fn main() {
+    let foo = Foo::new(baz(), baz(), "foo", "bar");
+}
+        "#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index 048906d9d9f..9af8411f4cb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use ast::edit::IndentLevel;
+use hir::HasAttrs;
 use ide_db::base_db::AnchoredPathBuf;
 use itertools::Itertools;
 use stdx::format_to;
@@ -50,9 +51,17 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         |builder| {
             let path = {
                 let mut buf = String::from("./");
-                match parent_module.name(ctx.db()) {
-                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
-                        format_to!(buf, "{}/", name.display(ctx.db()))
+                let db = ctx.db();
+                match parent_module.name(db) {
+                    Some(name)
+                        if !parent_module.is_mod_rs(db)
+                            && parent_module
+                                .attrs(db)
+                                .by_key("path")
+                                .string_value_unescape()
+                                .is_none() =>
+                    {
+                        format_to!(buf, "{}/", name.display(db))
                     }
                     _ => (),
                 }
@@ -108,6 +117,72 @@ mod tests {
     use super::*;
 
     #[test]
+    fn extract_with_specified_path_attr() {
+        check_assist(
+            move_module_to_file,
+            r#"
+//- /main.rs
+#[path="parser/__mod.rs"]
+mod parser;
+//- /parser/__mod.rs
+fn test() {}
+mod $0expr {
+    struct A {}
+}
+"#,
+            r#"
+//- /parser/__mod.rs
+fn test() {}
+mod expr;
+//- /parser/expr.rs
+struct A {}
+"#,
+        );
+
+        check_assist(
+            move_module_to_file,
+            r#"
+//- /main.rs
+#[path="parser/a/__mod.rs"]
+mod parser;
+//- /parser/a/__mod.rs
+fn test() {}
+mod $0expr {
+    struct A {}
+}
+"#,
+            r#"
+//- /parser/a/__mod.rs
+fn test() {}
+mod expr;
+//- /parser/a/expr.rs
+struct A {}
+"#,
+        );
+
+        check_assist(
+            move_module_to_file,
+            r#"
+//- /main.rs
+#[path="a.rs"]
+mod parser;
+//- /a.rs
+fn test() {}
+mod $0expr {
+    struct A {}
+}
+"#,
+            r#"
+//- /a.rs
+fn test() {}
+mod expr;
+//- /expr.rs
+struct A {}
+"#,
+        );
+    }
+
+    #[test]
     fn extract_from_root() {
         check_assist(
             move_module_to_file,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
index 63db6063361..5a197f23d0e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
@@ -25,7 +25,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
     if token.is_raw() {
         return None;
     }
-    let value = token.value()?;
+    let value = token.value().ok()?;
     let target = token.syntax().text_range();
     acc.add(
         AssistId("make_raw_string", AssistKind::RefactorRewrite),
@@ -64,7 +64,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     if !token.is_raw() {
         return None;
     }
-    let value = token.value()?;
+    let value = token.value().ok()?;
     let target = token.syntax().text_range();
     acc.add(
         AssistId("make_usual_string", AssistKind::RefactorRewrite),
@@ -398,12 +398,12 @@ string"###;
     }
 
     #[test]
-    fn remove_hash_doesnt_work() {
+    fn remove_hash_does_not_work() {
         check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#);
     }
 
     #[test]
-    fn remove_hash_no_hash_doesnt_work() {
+    fn remove_hash_no_hash_does_not_work() {
         check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index 66669662316..cf135f83e7b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -77,7 +77,7 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                 ast::AssocItem::MacroCall(_) => None,
             };
 
-            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
+            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX)
         })
         .collect();
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
index 6310981ccce..a48b20acbca 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
@@ -25,7 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 // ```
 pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
-    let value = token.value()?;
+    let value = token.value().ok()?;
     let target = token.syntax().text_range();
 
     if value.chars().take(2).count() != 1 {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 0f4a8e3aecb..d0c6ae21988 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -1,5 +1,5 @@
 //! Term search assist
-use hir::term_search::TermSearchCtx;
+use hir::term_search::{TermSearchConfig, TermSearchCtx};
 use ide_db::{
     assists::{AssistId, AssistKind, GroupLabel},
     famous_defs::FamousDefs,
@@ -34,7 +34,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         sema: &ctx.sema,
         scope: &scope,
         goal: target_ty,
-        config: Default::default(),
+        config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() },
     };
     let paths = hir::term_search::term_search(&term_search_ctx);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index 32d69841020..3b6c9512511 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -31,6 +31,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     prefer_no_std: false,
     prefer_prelude: true,
     assist_emit_must_use: false,
+    term_search_fuel: 400,
 };
 
 pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@@ -46,6 +47,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
     prefer_no_std: false,
     prefer_prelude: true,
     assist_emit_must_use: false,
+    term_search_fuel: 400,
 };
 
 pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@@ -61,6 +63,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
     prefer_no_std: false,
     prefer_prelude: true,
     assist_emit_must_use: false,
+    term_search_fuel: 400,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index 802e9bc3a80..1e31d65fddf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -353,7 +353,7 @@ pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>)
             config: hir::term_search::TermSearchConfig {
                 enable_borrowcheck: false,
                 many_alternatives_threshold: 1,
-                depth: 6,
+                fuel: 200,
             },
         };
         let exprs = hir::term_search::term_search(&term_search_ctx);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 3bc329ecd74..bf6747d71b7 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -296,7 +296,7 @@ fn import_on_the_fly_pat_(
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat", ?potential_import_name)
+    let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat_", ?potential_import_name)
         .entered();
 
     ImportScope::find_insert_use_container(&position, &ctx.sema)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 04563fb0f46..809c305ed82 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -15,6 +15,7 @@ pub struct CompletionConfig {
     pub enable_self_on_the_fly: bool,
     pub enable_private_editable: bool,
     pub enable_term_search: bool,
+    pub term_search_fuel: u64,
     pub full_function_signatures: bool,
     pub callable: Option<CallableSnippets>,
     pub snippet_cap: Option<SnippetCap>,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 8b435f419c7..db34beadc0f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -466,7 +466,7 @@ impl CompletionContext<'_> {
                 cov_mark::hit!(completes_if_lifetime_without_idents);
                 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
             }
-            IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(),
+            IDENT | LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
             _ if kind.is_keyword() => self.original_token.text_range(),
             _ => TextRange::empty(self.position.offset),
         }
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 ca0424809ed..7fa31e2757d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -368,7 +368,7 @@ fn render_resolution_pat(
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_pat").entered();
     use hir::ModuleDef::*;
 
     if let ScopeDef::ModuleDef(Macro(mac)) = resolution {
@@ -386,7 +386,7 @@ fn render_resolution_path(
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_path").entered();
     use hir::ModuleDef::*;
 
     match resolution {
@@ -494,7 +494,7 @@ fn render_resolution_simple_(
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_simple_").entered();
 
     let db = ctx.db();
     let ctx = ctx.import_to_add(import_to_add);
@@ -1731,6 +1731,51 @@ fn foo(a: A) { B { bar: a.$0 }; }
     }
 
     #[test]
+    fn tuple_field_detail() {
+        check(
+            r#"
+struct S(i32);
+
+fn f() -> i32 {
+    let s = S(0);
+    s.0$0
+}
+"#,
+            SymbolKind::Field,
+            expect![[r#"
+                [
+                    CompletionItem {
+                        label: "0",
+                        source_range: 56..57,
+                        delete: 56..57,
+                        insert: "0",
+                        kind: SymbolKind(
+                            Field,
+                        ),
+                        detail: "i32",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: Some(
+                                Exact,
+                            ),
+                            is_local: false,
+                            is_item_from_trait: false,
+                            is_item_from_notable_trait: false,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_op_method: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            is_definite: false,
+                            function: None,
+                        },
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn record_field_and_call_relevances() {
         check_relevance(
             r#"
@@ -1808,8 +1853,7 @@ fn f() { A { bar: b$0 }; }
                 fn baz() [type]
                 ex baz() [type]
                 ex bar() [type]
-                ex A { bar: baz() }.bar [type]
-                ex A { bar: bar() }.bar [type]
+                ex A { bar: ... }.bar [type]
                 st A []
                 fn f() []
             "#]],
@@ -1947,8 +1991,8 @@ fn main() {
 }
             "#,
             expect![[r#"
-                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
                 ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
+                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &t [type+local]
@@ -1997,8 +2041,8 @@ fn main() {
 }
             "#,
             expect![[r#"
-                ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
                 ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
+                ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &mut t [type+local]
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 f52a5f76255..9c5cb1e37d9 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
@@ -27,7 +27,7 @@ pub(crate) fn render_variant_lit(
     variant: hir::Variant,
     path: Option<hir::ModPath>,
 ) -> Option<Builder> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_enum_variant").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_variant_lit").entered();
     let db = ctx.db();
 
     let name = local_name.unwrap_or_else(|| variant.name(db));
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 540cfd03d60..8b81a95abbe 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
@@ -27,7 +27,7 @@ pub(crate) fn render_macro_pat(
     name: hir::Name,
     macro_: hir::Macro,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_macro_pat").entered();
     render(ctx, false, false, false, name, macro_)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 1f032c7df48..70e0aa4e9a9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -80,6 +80,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     },
     snippets: Vec::new(),
     limit: None,
+    term_search_fuel: 200,
 };
 
 pub(crate) fn completion_list(ra_fixture: &str) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
index 64a32dee3d7..62eb642b3bc 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
@@ -19,7 +19,7 @@ struct Foo<'lt, T, const C: usize> where $0 {}
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            st Foo<…>    Foo<'{error}, {unknown}, _>
+            st Foo<…>    Foo<{unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
@@ -92,7 +92,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            st Foo<…>    Foo<'{error}, {unknown}, _>
+            st Foo<…>    Foo<{unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index 66f1bff7c1c..ff38c161087 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -20,8 +20,8 @@ struct Foo<'lt, T, const C: usize> {
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            sp Self      Foo<'{error}, {unknown}, _>
-            st Foo<…>    Foo<'{error}, {unknown}, _>
+            sp Self      Foo<{unknown}, _>
+            st Foo<…>    Foo<{unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
@@ -45,8 +45,8 @@ struct Foo<'lt, T, const C: usize>(f$0);
             en Enum       Enum
             ma makro!(…)  macro_rules! makro
             md module
-            sp Self       Foo<'{error}, {unknown}, _>
-            st Foo<…>     Foo<'{error}, {unknown}, _>
+            sp Self       Foo<{unknown}, _>
+            st Foo<…>     Foo<{unknown}, _>
             st Record     Record
             st Tuple      Tuple
             st Unit       Unit
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index c0f0faba35c..634277e8698 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -11,8 +11,8 @@ use hir::{
     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
     Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
     Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module,
-    ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField,
-    TypeAlias, Variant, VariantDef, Visibility,
+    ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
+    TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
 };
 use stdx::{format_to, impl_from};
 use syntax::{
@@ -39,12 +39,13 @@ pub enum Definition {
     Trait(Trait),
     TraitAlias(TraitAlias),
     TypeAlias(TypeAlias),
-    BuiltinType(BuiltinType),
     SelfType(Impl),
     GenericParam(GenericParam),
     Local(Local),
     Label(Label),
     DeriveHelper(DeriveHelper),
+    BuiltinType(BuiltinType),
+    BuiltinLifetime(StaticLifetime),
     BuiltinAttr(BuiltinAttr),
     ToolModule(ToolModule),
     ExternCrateDecl(ExternCrateDecl),
@@ -83,6 +84,7 @@ impl Definition {
             Definition::DeriveHelper(it) => it.derive().module(db),
             Definition::BuiltinAttr(_)
             | Definition::BuiltinType(_)
+            | Definition::BuiltinLifetime(_)
             | Definition::TupleField(_)
             | Definition::ToolModule(_) => return None,
         };
@@ -112,6 +114,7 @@ impl Definition {
             Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
             Definition::Macro(_) => return None,
             Definition::BuiltinAttr(_)
+            | Definition::BuiltinLifetime(_)
             | Definition::ToolModule(_)
             | Definition::SelfType(_)
             | Definition::Local(_)
@@ -141,6 +144,7 @@ impl Definition {
             Definition::Local(it) => it.name(db),
             Definition::GenericParam(it) => it.name(db),
             Definition::Label(it) => it.name(db),
+            Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME,
             Definition::BuiltinAttr(_) => return None, // FIXME
             Definition::ToolModule(_) => return None,  // FIXME
             Definition::DeriveHelper(it) => it.name(db),
@@ -174,6 +178,7 @@ impl Definition {
                     doc_owner.docs(fd.0.db)
                 })
             }
+            Definition::BuiltinLifetime(StaticLifetime) => None,
             Definition::Local(_) => None,
             Definition::SelfType(impl_def) => {
                 impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
@@ -228,6 +233,7 @@ impl Definition {
             Definition::TraitAlias(it) => it.display(db).to_string(),
             Definition::TypeAlias(it) => it.display(db).to_string(),
             Definition::BuiltinType(it) => it.name().display(db).to_string(),
+            Definition::BuiltinLifetime(it) => it.name().display(db).to_string(),
             Definition::Local(it) => {
                 let ty = it.ty(db);
                 let ty_display = ty.display_truncated(db, None);
@@ -693,6 +699,9 @@ impl NameRefClass {
     ) -> Option<NameRefClass> {
         let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime)
             .entered();
+        if lifetime.text() == "'static" {
+            return Some(NameRefClass::Definition(Definition::BuiltinLifetime(StaticLifetime)));
+        }
         let parent = lifetime.syntax().parent()?;
         match parent.kind() {
             SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index c597555a3bf..766bfcf4d09 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -209,8 +209,7 @@ impl ImportAssets {
         prefer_no_std: bool,
         prefer_prelude: bool,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "import_assets::search_for_imports").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_imports").entered();
         self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude)
     }
 
@@ -221,7 +220,7 @@ impl ImportAssets {
         prefer_no_std: bool,
         prefer_prelude: bool,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for_relative_paths")
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_relative_paths")
             .entered();
         self.search_for(sema, None, prefer_no_std, prefer_prelude)
     }
@@ -263,7 +262,7 @@ impl ImportAssets {
         prefer_no_std: bool,
         prefer_prelude: bool,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for").entered();
 
         let scope = match sema.scope(&self.candidate_node) {
             Some(it) => it,
@@ -308,7 +307,7 @@ impl ImportAssets {
     }
 
     fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet<ScopeDef> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_assets::scope_definitions").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::scope_definitions").entered();
         let mut scope_definitions = FxHashSet::default();
         if let Some(scope) = sema.scope(&self.candidate_node) {
             scope.process_all_names(&mut |_, scope_def| {
@@ -327,7 +326,7 @@ fn path_applicable_imports(
     scope_filter: impl Fn(ItemInNs) -> bool + Copy,
 ) -> FxHashSet<LocatedImport> {
     let _p =
-        tracing::span!(tracing::Level::INFO, "import_assets::path_applicable_imports").entered();
+        tracing::span!(tracing::Level::INFO, "ImportAssets::path_applicable_imports").entered();
 
     match &path_candidate.qualifier {
         None => {
@@ -374,7 +373,7 @@ fn import_for_item(
     original_item: ItemInNs,
     scope_filter: impl Fn(ItemInNs) -> bool,
 ) -> Option<LocatedImport> {
-    let _p = tracing::span!(tracing::Level::INFO, "import_assets::import_for_item").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::import_for_item").entered();
     let [first_segment, ..] = unresolved_qualifier else { return None };
 
     let item_as_assoc = item_as_assoc(db, original_item);
@@ -508,8 +507,7 @@ fn trait_applicable_items(
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
     scope_filter: impl Fn(hir::Trait) -> bool,
 ) -> FxHashSet<LocatedImport> {
-    let _p =
-        tracing::span!(tracing::Level::INFO, "import_assets::trait_applicable_items").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::trait_applicable_items").entered();
 
     let db = sema.db;
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index e97f1b86143..026d4e36f97 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -194,7 +194,7 @@ fn insert_use_with_alias_option(
     cfg: &InsertUseConfig,
     alias: Option<ast::Rename>,
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "insert_use").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "insert_use_with_alias_option").entered();
     let mut mb = match cfg.granularity {
         ImportGranularity::Crate => Some(MergeBehavior::Crate),
         ImportGranularity::Module => Some(MergeBehavior::Module),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index 024e8f6ae39..58077f636b6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -1,6 +1,6 @@
 //! rust-analyzer is lazy and doesn't compute anything unless asked. This
 //! sometimes is counter productive when, for example, the first goto definition
-//! request takes longer to compute. This modules implemented prepopulation of
+//! request takes longer to compute. This module implements prepopulation of
 //! various caches, it's not really advanced at the moment.
 mod topologic_sort;
 
@@ -32,7 +32,7 @@ pub fn parallel_prime_caches(
     num_worker_threads: u8,
     cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync),
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "prime_caches").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "parallel_prime_caches").entered();
 
     let graph = db.crate_graph();
     let mut crates_to_prime = {
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 6a7042988a9..288d56b534e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -196,11 +196,12 @@ impl Definition {
                         .and_then(syn_ctx_is_root)
                 }
             }
-            Definition::BuiltinType(_) => return None,
-            Definition::SelfType(_) => return None,
-            Definition::BuiltinAttr(_) => return None,
-            Definition::ToolModule(_) => return None,
-            Definition::TupleField(_) => return None,
+            Definition::BuiltinType(_)
+            | Definition::BuiltinLifetime(_)
+            | Definition::BuiltinAttr(_)
+            | Definition::SelfType(_)
+            | Definition::ToolModule(_)
+            | Definition::TupleField(_) => return None,
             // FIXME: This should be doable in theory
             Definition::DeriveHelper(_) => return None,
         };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index cb103313c9e..8f633065f3c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -1,7 +1,7 @@
 //! Implementation of find-usages functionality.
 //!
 //! It is based on the standard ide trick: first, we run a fast text search to
-//! get a super-set of matches. Then, we we confirm each match using precise
+//! get a super-set of matches. Then, we confirm each match using precise
 //! name resolution.
 
 use std::mem;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index c65467a4324..12085f9ebd2 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -301,8 +301,8 @@ impl SymbolIndex {
     }
 
     fn range_to_map_value(start: usize, end: usize) -> u64 {
-        debug_assert![start <= (std::u32::MAX as usize)];
-        debug_assert![end <= (std::u32::MAX as usize)];
+        debug_assert![start <= (u32::MAX as usize)];
+        debug_assert![end <= (u32::MAX as usize)];
 
         ((start as u64) << 32) | end as u64
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index 241fddbb906..b3dde977b1c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -7,7 +7,7 @@ use ide_db::{
     helpers::mod_path_to_ast,
     imports::insert_use::{insert_use, ImportScope},
     source_change::SourceChangeBuilder,
-    RootDatabase,
+    FxHashMap, RootDatabase,
 };
 use itertools::Itertools;
 use stdx::{format_to, never};
@@ -22,15 +22,22 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity};
 #[derive(Default)]
 struct State {
     result: String,
-    struct_counts: usize,
     has_serialize: bool,
     has_deserialize: bool,
+    names: FxHashMap<String, usize>,
 }
 
 impl State {
-    fn generate_new_name(&mut self) -> ast::Name {
-        self.struct_counts += 1;
-        make::name(&format!("Struct{}", self.struct_counts))
+    fn generate_new_name(&mut self, name: &str) -> ast::Name {
+        let name = stdx::to_camel_case(name);
+        let count = if let Some(count) = self.names.get_mut(&name) {
+            *count += 1;
+            *count
+        } else {
+            self.names.insert(name.clone(), 1);
+            1
+        };
+        make::name(&format!("{}{}", name, count))
     }
 
     fn serde_derive(&self) -> String {
@@ -52,15 +59,21 @@ impl State {
         }
     }
 
-    fn build_struct(&mut self, value: &serde_json::Map<String, serde_json::Value>) -> ast::Type {
-        let name = self.generate_new_name();
+    fn build_struct(
+        &mut self,
+        name: &str,
+        value: &serde_json::Map<String, serde_json::Value>,
+    ) -> ast::Type {
+        let name = self.generate_new_name(name);
         let ty = make::ty(&name.to_string());
         let strukt = make::struct_(
             None,
             name,
             None,
             make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map(
-                |(name, value)| make::record_field(None, make::name(name), self.type_of(value)),
+                |(name, value)| {
+                    make::record_field(None, make::name(name), self.type_of(name, value))
+                },
             ))
             .into(),
         );
@@ -68,7 +81,7 @@ impl State {
         ty
     }
 
-    fn type_of(&mut self, value: &serde_json::Value) -> ast::Type {
+    fn type_of(&mut self, name: &str, value: &serde_json::Value) -> ast::Type {
         match value {
             serde_json::Value::Null => make::ty_unit(),
             serde_json::Value::Bool(_) => make::ty("bool"),
@@ -76,12 +89,12 @@ impl State {
             serde_json::Value::String(_) => make::ty("String"),
             serde_json::Value::Array(it) => {
                 let ty = match it.iter().next() {
-                    Some(x) => self.type_of(x),
+                    Some(x) => self.type_of(name, x),
                     None => make::ty_placeholder(),
                 };
                 make::ty(&format!("Vec<{ty}>"))
             }
-            serde_json::Value::Object(x) => self.build_struct(x),
+            serde_json::Value::Object(x) => self.build_struct(name, x),
         }
     }
 }
@@ -113,7 +126,7 @@ pub(crate) fn json_in_items(
                 let serialize_resolved = scope_resolve("::serde::Serialize");
                 state.has_deserialize = deserialize_resolved.is_some();
                 state.has_serialize = serialize_resolved.is_some();
-                state.build_struct(&it);
+                state.build_struct("Root", &it);
                 edit.insert(range.start(), state.result);
                 acc.push(
                     Diagnostic::new(
@@ -218,7 +231,7 @@ mod tests {
             }
 
             #[derive(Serialize)]
-            struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
+            struct Root1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
 
             "#,
         );
@@ -237,9 +250,44 @@ mod tests {
             }
             "#,
             r#"
-            struct Struct3{  }
-            struct Struct2{ kind: String, value: Struct3 }
-            struct Struct1{ bar: Struct2, foo: String }
+            struct Value1{  }
+            struct Bar1{ kind: String, value: Value1 }
+            struct Root1{ bar: Bar1, foo: String }
+
+            "#,
+        );
+    }
+
+    #[test]
+    fn naming() {
+        check_fix(
+            r#"
+            {$0
+                "user": {
+                    "address": {
+                        "street": "Main St",
+                        "house": 3
+                    },
+                    "email": "example@example.com"
+                },
+                "another_user": {
+                    "user": {
+                        "address": {
+                            "street": "Main St",
+                            "house": 3
+                        },
+                        "email": "example@example.com"
+                    }
+                }
+            }
+            "#,
+            r#"
+            struct Address1{ house: i64, street: String }
+            struct User1{ address: Address1, email: String }
+            struct AnotherUser1{ user: User1 }
+            struct Address2{ house: i64, street: String }
+            struct User2{ address: Address2, email: String }
+            struct Root1{ another_user: AnotherUser1, user: User2 }
 
             "#,
         );
@@ -276,9 +324,9 @@ mod tests {
             use serde::Deserialize;
 
             #[derive(Serialize, Deserialize)]
-            struct Struct2{ x: i64, y: i64 }
+            struct OfObject1{ x: i64, y: i64 }
             #[derive(Serialize, Deserialize)]
-            struct Struct1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<Struct2>, of_string: Vec<String> }
+            struct Root1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<OfObject1>, of_string: Vec<String> }
 
             "#,
         );
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 8d77e566edc..5a3206445c5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics};
+use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId};
 use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase};
 use syntax::{
     ast::{self, edit::IndentLevel, make},
@@ -25,7 +25,10 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
     } else {
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
-            DiagnosticCode::RustcHardError("E0559"),
+            match d.variant {
+                VariantId::EnumVariantId(_) => DiagnosticCode::RustcHardError("E0559"),
+                _ => DiagnosticCode::RustcHardError("E0560"),
+            },
             "no such field",
             node,
         )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 56c8181e84c..656d79dc732 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -1,6 +1,6 @@
 use hir::{
     db::ExpandDatabase,
-    term_search::{term_search, TermSearchCtx},
+    term_search::{term_search, TermSearchConfig, TermSearchCtx},
     ClosureStyle, HirDisplay,
 };
 use ide_db::{
@@ -47,7 +47,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
         sema: &ctx.sema,
         scope: &scope,
         goal: d.expected.clone(),
-        config: Default::default(),
+        config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() },
     };
     let paths = term_search(&term_search_ctx);
 
@@ -274,7 +274,7 @@ impl Foo for Baz {
 }
 fn asd() -> Bar {
     let a = Baz;
-    Foo::foo(a)
+    Foo::foo(_)
 }
 ",
         );
@@ -363,7 +363,7 @@ impl Foo for A {
 }
 fn main() {
     let a = A;
-    let c: Bar = Foo::foo(&a);
+    let c: Bar = Foo::foo(_);
 }"#,
         );
     }
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 c3ced36a696..15543a5d655 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -232,6 +232,7 @@ pub struct DiagnosticsConfig {
     pub insert_use: InsertUseConfig,
     pub prefer_no_std: bool,
     pub prefer_prelude: bool,
+    pub term_search_fuel: u64,
 }
 
 impl DiagnosticsConfig {
@@ -256,6 +257,7 @@ impl DiagnosticsConfig {
             },
             prefer_no_std: false,
             prefer_prelude: true,
+            term_search_fuel: 400,
         }
     }
 }
@@ -297,11 +299,10 @@ pub fn diagnostics(
 ) -> Vec<Diagnostic> {
     let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered();
     let sema = Semantics::new(db);
-    let parse = db.parse(file_id);
     let mut res = Vec::new();
 
     // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
-    res.extend(parse.errors().into_iter().take(128).map(|err| {
+    res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| {
         Diagnostic::new(
             DiagnosticCode::RustcHardError("syntax-error"),
             format!("Syntax Error: {err}"),
@@ -340,7 +341,8 @@ pub fn diagnostics(
             AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d),
             AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
             AnyDiagnostic::MacroExpansionParseError(d) => {
-                res.extend(d.errors.iter().take(32).map(|err| {
+                // FIXME: Point to the correct error span here, not just the macro-call name
+                res.extend(d.errors.iter().take(16).map(|err| {
                     {
                         Diagnostic::new(
                             DiagnosticCode::RustcHardError("syntax-error"),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index bb5c2b79139..cd5e95cc1e3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -293,6 +293,7 @@ fn minicore_smoke_test() {
         // This should be ignored since we conditionally remove code which creates single item use with braces
         config.disabled.insert("unused_braces".to_owned());
         config.disabled.insert("unused_variables".to_owned());
+        config.disabled.insert("remove-unnecessary-else".to_owned());
         check_diagnostics_with_config(config, &source);
     }
 
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 64b4ccc5bd8..8d765dfc91b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -214,8 +214,9 @@ pub(crate) fn resolve_doc_path_for_def(
         Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
         Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
         Definition::BuiltinAttr(_)
-        | Definition::ToolModule(_)
         | Definition::BuiltinType(_)
+        | Definition::BuiltinLifetime(_)
+        | Definition::ToolModule(_)
         | Definition::TupleField(_)
         | Definition::Local(_)
         | Definition::GenericParam(_)
@@ -648,6 +649,7 @@ fn filename_and_frag_for_def(
         | Definition::TupleField(_)
         | Definition::Label(_)
         | Definition::BuiltinAttr(_)
+        | Definition::BuiltinLifetime(_)
         | Definition::ToolModule(_)
         | Definition::DeriveHelper(_) => return None,
     };
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index e2d629a02fc..1ead045788f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -76,8 +76,6 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
         return derive;
     }
 
-    // FIXME: Intermix attribute and bang! expansions
-    // currently we only recursively expand one of the two types
     let mut anc = tok.parent_ancestors();
     let (name, expanded, kind) = loop {
         let node = anc.next()?;
@@ -86,7 +84,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
             if let Some(def) = sema.resolve_attr_macro_call(&item) {
                 break (
                     def.name(db).display(db).to_string(),
-                    expand_attr_macro_recur(&sema, &item)?,
+                    expand_macro_recur(&sema, &item)?,
                     SyntaxKind::MACRO_ITEMS,
                 );
             }
@@ -94,11 +92,9 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
         if let Some(mac) = ast::MacroCall::cast(node) {
             let mut name = mac.path()?.segment()?.name_ref()?.to_string();
             name.push('!');
-            break (
-                name,
-                expand_macro_recur(&sema, &mac)?,
-                mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS),
-            );
+            let syntax_kind =
+                mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS);
+            break (name, expand_macro_recur(&sema, &ast::Item::MacroCall(mac))?, syntax_kind);
         }
     };
 
@@ -112,31 +108,23 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
 
 fn expand_macro_recur(
     sema: &Semantics<'_, RootDatabase>,
-    macro_call: &ast::MacroCall,
-) -> Option<SyntaxNode> {
-    let expanded = sema.expand(macro_call)?.clone_for_update();
-    expand(sema, expanded, ast::MacroCall::cast, expand_macro_recur)
-}
-
-fn expand_attr_macro_recur(
-    sema: &Semantics<'_, RootDatabase>,
-    item: &ast::Item,
+    macro_call: &ast::Item,
 ) -> Option<SyntaxNode> {
-    let expanded = sema.expand_attr_macro(item)?.clone_for_update();
-    expand(sema, expanded, ast::Item::cast, expand_attr_macro_recur)
+    let expanded = match macro_call {
+        item @ ast::Item::MacroCall(macro_call) => {
+            sema.expand_attr_macro(item).or_else(|| sema.expand(macro_call))?.clone_for_update()
+        }
+        item => sema.expand_attr_macro(item)?.clone_for_update(),
+    };
+    expand(sema, expanded)
 }
 
-fn expand<T: AstNode>(
-    sema: &Semantics<'_, RootDatabase>,
-    expanded: SyntaxNode,
-    f: impl FnMut(SyntaxNode) -> Option<T>,
-    exp: impl Fn(&Semantics<'_, RootDatabase>, &T) -> Option<SyntaxNode>,
-) -> Option<SyntaxNode> {
-    let children = expanded.descendants().filter_map(f);
+fn expand(sema: &Semantics<'_, RootDatabase>, expanded: SyntaxNode) -> Option<SyntaxNode> {
+    let children = expanded.descendants().filter_map(ast::Item::cast);
     let mut replacements = Vec::new();
 
     for child in children {
-        if let Some(new_node) = exp(sema, &child) {
+        if let Some(new_node) = expand_macro_recur(sema, &child) {
             // check if the whole original syntax is replaced
             if expanded == *child.syntax() {
                 return Some(new_node);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index ddeeca5f7b3..76b80fcefa4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -123,7 +123,7 @@ fn try_lookup_include_path(
     {
         return None;
     }
-    let path = token.value()?;
+    let path = token.value().ok()?;
 
     let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
     let size = sema.db.file_text(file_id).len().try_into().ok()?;
@@ -179,11 +179,11 @@ fn try_filter_trait_item_definition(
         AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
             let trait_ = assoc.implemented_trait(db)?;
             let name = def.name(db)?;
-            let discri_value = discriminant(&assoc);
+            let discriminant_value = discriminant(&assoc);
             trait_
                 .items(db)
                 .iter()
-                .filter(|itm| discriminant(*itm) == discri_value)
+                .filter(|itm| discriminant(*itm) == discriminant_value)
                 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
                 .map(|it| it.collect())
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 95de3c88c8a..bdb56081c33 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -15,7 +15,7 @@ use ide_db::{
     FxIndexSet, RootDatabase,
 };
 use itertools::{multizip, Itertools};
-use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
+use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};
 
 use crate::{
     doc_links::token_as_doc_comment,
@@ -33,7 +33,8 @@ pub struct HoverConfig {
     pub keywords: bool,
     pub format: HoverDocFormat,
     pub max_trait_assoc_items_count: Option<usize>,
-    pub max_struct_field_count: Option<usize>,
+    pub max_fields_count: Option<usize>,
+    pub max_enum_variants_count: Option<usize>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -297,61 +298,8 @@ fn hover_simple(
         })
         // tokens
         .or_else(|| {
-            let mut res = HoverResult::default();
-            match_ast! {
-                match original_token {
-                    ast::String(string) => {
-                        res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?));
-                    },
-                    ast::ByteString(string) => {
-                        res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?));
-                    },
-                    ast::CString(string) => {
-                        let val = string.value()?;
-                        res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?));
-                    },
-                    ast::Char(char) => {
-                        let mut res = HoverResult::default();
-                        res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?));
-                    },
-                    ast::Byte(byte) => {
-                        res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?));
-                    },
-                    ast::FloatNumber(num) => {
-                        res.markup = if num.suffix() == Some("f32") {
-                            match num.value_f32() {
-                                Ok(num) => {
-                                    Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
-                                },
-                                Err(e) => {
-                                    Markup::fenced_block_text(format_args!("{e}"))
-                                },
-                            }
-                        } else {
-                            match num.value() {
-                                Ok(num) => {
-                                    Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
-                                },
-                                Err(e) => {
-                                    Markup::fenced_block_text(format_args!("{e}"))
-                                },
-                            }
-                        };
-                    },
-                    ast::IntNumber(num) => {
-                        res.markup = match num.value() {
-                            Ok(num) => {
-                                Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0b{num:b})"))
-                            },
-                            Err(e) => {
-                                Markup::fenced_block_text(format_args!("{e}"))
-                            },
-                        };
-                    },
-                    _ => return None
-                }
-            }
-            Some(res)
+            render::literal(sema, original_token.clone())
+                .map(|markup| HoverResult { markup, actions: vec![] })
         });
 
     result.map(|mut res: HoverResult| {
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 3f0fc851344..3bc17f95e70 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -17,11 +17,7 @@ use ide_db::{
 };
 use itertools::Itertools;
 use stdx::format_to;
-use syntax::{
-    algo,
-    ast::{self, RecordPat},
-    match_ast, AstNode, Direction, SyntaxToken, T,
-};
+use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T};
 
 use crate::{
     doc_links::{remove_links, rewrite_links},
@@ -276,7 +272,7 @@ pub(super) fn keyword(
 pub(super) fn struct_rest_pat(
     sema: &Semantics<'_, RootDatabase>,
     _config: &HoverConfig,
-    pattern: &RecordPat,
+    pattern: &ast::RecordPat,
 ) -> HoverResult {
     let missing_fields = sema.record_pattern_missing_fields(pattern);
 
@@ -411,8 +407,21 @@ pub(super) fn definition(
         Definition::Trait(trait_) => {
             trait_.display_limited(db, config.max_trait_assoc_items_count).to_string()
         }
-        Definition::Adt(Adt::Struct(struct_)) => {
-            struct_.display_limited(db, config.max_struct_field_count).to_string()
+        Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => {
+            adt.display_limited(db, config.max_fields_count).to_string()
+        }
+        Definition::Variant(variant) => {
+            variant.display_limited(db, config.max_fields_count).to_string()
+        }
+        Definition::Adt(adt @ Adt::Enum(_)) => {
+            adt.display_limited(db, config.max_enum_variants_count).to_string()
+        }
+        Definition::SelfType(impl_def) => {
+            let self_ty = &impl_def.self_ty(db);
+            match self_ty.as_adt() {
+                Some(adt) => adt.display_limited(db, config.max_fields_count).to_string(),
+                None => self_ty.display(db).to_string(),
+            }
         }
         Definition::Macro(it) => {
             let mut label = it.display(db).to_string();
@@ -513,6 +522,60 @@ pub(super) fn definition(
     markup(docs.map(Into::into), desc, mod_path)
 }
 
+pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Markup> {
+    let lit = token.parent().and_then(ast::Literal::cast)?;
+    let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) {
+        sema.type_of_pat(&p)?
+    } else {
+        sema.type_of_expr(&ast::Expr::Literal(lit))?
+    }
+    .original;
+
+    let value = match_ast! {
+        match token {
+            ast::String(string)     => string.value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
+            ast::ByteString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("{it:?}")),
+            ast::CString(string)    => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| std::str::from_utf8(it).map_or_else(|e| format!("{e:?}"), ToOwned::to_owned)),
+            ast::Char(char)         => char  .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
+            ast::Byte(byte)         => byte  .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")),
+            ast::FloatNumber(num) => {
+                let (text, _) = num.split_into_parts();
+                let text = text.replace('_', "");
+                if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) {
+                    match text.parse::<f32>() {
+                        Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
+                        Err(e) => Err(e.to_string()),
+                    }
+                } else {
+                    match text.parse::<f64>() {
+                        Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
+                        Err(e) => Err(e.to_string()),
+                    }
+                }
+            },
+            ast::IntNumber(num) => match num.value() {
+                Ok(num) => Ok(format!("{num} (0x{num:X}|0b{num:b})")),
+                Err(e) => Err(e.to_string()),
+            },
+            _ => return None
+        }
+    };
+    let ty = ty.display(sema.db);
+
+    let mut s = format!("```rust\n{ty}\n```\n___\n\n");
+    match value {
+        Ok(value) => {
+            if let Some(newline) = value.find('\n') {
+                format_to!(s, "value of literal (truncated up to newline): {}", &value[..newline])
+            } else {
+                format_to!(s, "value of literal: {value}")
+            }
+        }
+        Err(error) => format_to!(s, "invalid literal: {error}"),
+    }
+    Some(s.into())
+}
+
 fn render_notable_trait_comment(
     db: &RootDatabase,
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
@@ -693,15 +756,7 @@ fn closure_ty(
 }
 
 fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
-    if matches!(
-        def,
-        Definition::GenericParam(_)
-            | Definition::BuiltinType(_)
-            | Definition::Local(_)
-            | Definition::Label(_)
-            | Definition::BuiltinAttr(_)
-            | Definition::ToolModule(_)
-    ) {
+    if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) {
         return None;
     }
     def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
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 6bbc8b380d6..20d07bf9919 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -18,7 +18,8 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
     format: HoverDocFormat::Markdown,
     keywords: true,
     max_trait_assoc_items_count: None,
-    max_struct_field_count: None,
+    max_fields_count: Some(5),
+    max_enum_variants_count: Some(5),
 };
 
 fn check_hover_no_result(ra_fixture: &str) {
@@ -51,13 +52,43 @@ fn check(ra_fixture: &str, expect: Expect) {
 }
 
 #[track_caller]
-fn check_hover_struct_limit(count: usize, ra_fixture: &str, expect: Expect) {
+fn check_hover_fields_limit(
+    fields_count: impl Into<Option<usize>>,
+    ra_fixture: &str,
+    expect: Expect,
+) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
             &HoverConfig {
                 links_in_hover: true,
-                max_struct_field_count: Some(count),
+                max_fields_count: fields_count.into(),
+                ..HOVER_BASE_CONFIG
+            },
+            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
+        )
+        .unwrap()
+        .unwrap();
+
+    let content = analysis.db.file_text(position.file_id);
+    let hovered_element = &content[hover.range];
+
+    let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
+    expect.assert_eq(&actual)
+}
+
+#[track_caller]
+fn check_hover_enum_variants_limit(
+    variants_count: impl Into<Option<usize>>,
+    ra_fixture: &str,
+    expect: Expect,
+) {
+    let (analysis, position) = fixture::position(ra_fixture);
+    let hover = analysis
+        .hover(
+            &HoverConfig {
+                links_in_hover: true,
+                max_enum_variants_count: variants_count.into(),
                 ..HOVER_BASE_CONFIG
             },
             FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
@@ -876,7 +907,9 @@ struct Foo$0 { field: u32 }
 
             ```rust
             // size = 4, align = 4
-            struct Foo
+            struct Foo {
+                field: u32,
+            }
             ```
         "#]],
     );
@@ -896,6 +929,9 @@ struct Foo$0 where u32: Copy { field: u32 }
             struct Foo
             where
                 u32: Copy,
+            {
+                field: u32,
+            }
             ```
         "#]],
     );
@@ -903,7 +939,7 @@ struct Foo$0 where u32: Copy { field: u32 }
 
 #[test]
 fn hover_record_struct_limit() {
-    check_hover_struct_limit(
+    check_hover_fields_limit(
         3,
         r#"
     struct Foo$0 { a: u32, b: i32, c: i32 }
@@ -917,7 +953,7 @@ fn hover_record_struct_limit() {
 
             ```rust
             // size = 12 (0xC), align = 4
-            struct Foo  {
+            struct Foo {
                 a: u32,
                 b: i32,
                 c: i32,
@@ -925,7 +961,7 @@ fn hover_record_struct_limit() {
             ```
         "#]],
     );
-    check_hover_struct_limit(
+    check_hover_fields_limit(
         3,
         r#"
     struct Foo$0 { a: u32 }
@@ -939,13 +975,13 @@ fn hover_record_struct_limit() {
 
             ```rust
             // size = 4, align = 4
-            struct Foo  {
+            struct Foo {
                 a: u32,
             }
             ```
         "#]],
     );
-    check_hover_struct_limit(
+    check_hover_fields_limit(
         3,
         r#"
     struct Foo$0 { a: u32, b: i32, c: i32, d: u32 }
@@ -959,7 +995,7 @@ fn hover_record_struct_limit() {
 
             ```rust
             // size = 16 (0x10), align = 4
-            struct Foo  {
+            struct Foo {
                 a: u32,
                 b: i32,
                 c: i32,
@@ -968,6 +1004,338 @@ fn hover_record_struct_limit() {
             ```
         "#]],
     );
+    check_hover_fields_limit(
+        None,
+        r#"
+    struct Foo$0 { a: u32, b: i32, c: i32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            struct Foo
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        0,
+        r#"
+    struct Foo$0 { a: u32, b: i32, c: i32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            struct Foo { /* … */ }
+            ```
+        "#]],
+    );
+
+    // No extra spaces within `{}` when there are no fields
+    check_hover_fields_limit(
+        5,
+        r#"
+    struct Foo$0 {}
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            struct Foo {}
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_record_variant_limit() {
+    check_hover_fields_limit(
+        3,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            A { a: u32, b: i32, c: i32, }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        3,
+        r#"
+    enum Foo { A$0 { a: u32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            A { a: u32, }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        3,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32, d: u32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 16 (0x10), align = 4
+            A { a: u32, b: i32, c: i32, /* … */ }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        None,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            A
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        0,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            A { /* … */ }
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_enum_limit() {
+    check_hover_enum_variants_limit(
+        5,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo {
+                A,
+                B,
+            }
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        1,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo {
+                A,
+                /* … */
+            }
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        0,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo { /* … */ }
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        None,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        7,
+        r#"enum Enum$0 {
+               Variant {},
+               Variant2 { field: i32 },
+               Variant3 { field: i32, field2: i32 },
+               Variant4(),
+               Variant5(i32),
+               Variant6(i32, i32),
+               Variant7,
+               Variant8,
+           }"#,
+        expect![[r#"
+            *Enum*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4, niches = 4294967288
+            enum Enum {
+                Variant {},
+                Variant2 { /* … */ },
+                Variant3 { /* … */ },
+                Variant4(),
+                Variant5( /* … */ ),
+                Variant6( /* … */ ),
+                Variant7,
+                /* … */
+            }
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_union_limit() {
+    check_hover_fields_limit(
+        5,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo {
+                a: u32,
+                b: i32,
+            }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        1,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo {
+                a: u32,
+                /* … */
+            }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        0,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo { /* … */ }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        None,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo
+            ```
+        "#]],
+    );
 }
 
 #[test]
@@ -1431,11 +1799,14 @@ impl Thing {
                 ```
 
                 ```rust
-                struct Thing
+                struct Thing {
+                    x: u32,
+                }
                 ```
             "#]],
     );
-    check(
+    check_hover_fields_limit(
+        None,
         r#"
 struct Thing { x: u32 }
 impl Thing {
@@ -1456,9 +1827,9 @@ impl Thing {
     );
     check(
         r#"
-enum Thing { A }
+struct Thing { x: u32 }
 impl Thing {
-    pub fn new() -> Self$0 { Thing::A }
+    fn new() -> Self$0 { Self { x: 0 } }
 }
 "#,
         expect![[r#"
@@ -1469,8 +1840,8 @@ impl Thing {
                 ```
 
                 ```rust
-                enum Thing {
-                    A,
+                struct Thing {
+                    x: u32,
                 }
                 ```
             "#]],
@@ -1479,22 +1850,43 @@ impl Thing {
         r#"
 enum Thing { A }
 impl Thing {
+    pub fn new() -> Self$0 { Thing::A }
+}
+"#,
+        expect![[r#"
+            *Self*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            enum Thing {
+                A,
+            }
+            ```
+        "#]],
+    );
+    check(
+        r#"
+enum Thing { A }
+impl Thing {
     pub fn thing(a: Self$0) {}
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            test
+            ```
 
-                ```rust
-                enum Thing {
-                    A,
-                }
-                ```
-            "#]],
+            ```rust
+            enum Thing {
+                A,
+            }
+            ```
+        "#]],
     );
     check(
         r#"
@@ -2382,8 +2774,8 @@ fn test_hover_layout_of_enum() {
             ```rust
             // size = 16 (0x10), align = 8, niches = 254
             enum Foo {
-                Variant1(u8, u16),
-                Variant2(i32, u8, i64),
+                Variant1( /* … */ ),
+                Variant2( /* … */ ),
             }
             ```
         "#]],
@@ -4049,7 +4441,7 @@ fn foo() {
             ```rust
             'label
             ```
-            "#]],
+        "#]],
     );
 }
 
@@ -4063,7 +4455,17 @@ fn hover_lifetime() {
             ```rust
             'lifetime
             ```
-            "#]],
+        "#]],
+    );
+    check(
+        r#"fn foo(_: &'static$0 ()) {}"#,
+        expect![[r#"
+            *'static*
+
+            ```rust
+            'static
+            ```
+        "#]],
     );
 }
 
@@ -6554,7 +6956,7 @@ enum Enum {
 
             ```rust
             // size = 4, align = 4
-            RecordV { field: u32 }
+            RecordV { field: u32, }
             ```
         "#]],
     );
@@ -7398,9 +7800,12 @@ fn main() {
 "#,
         expect![[r#"
             *"🦀\u{1f980}\\\x41"*
-            ```text
-            🦀🦀\A
+            ```rust
+            &str
             ```
+            ___
+
+            value of literal: 🦀🦀\A
         "#]],
     );
     check(
@@ -7411,9 +7816,34 @@ fn main() {
 "#,
         expect![[r#"
             *r"🦀\u{1f980}\\\x41"*
-            ```text
-            🦀\u{1f980}\\\x41
+            ```rust
+            &str
             ```
+            ___
+
+            value of literal: 🦀\u{1f980}\\\x41
+        "#]],
+    );
+    check(
+        r#"
+fn main() {
+    $0r"🦀\u{1f980}\\\x41
+
+
+fsdghs";
+}
+"#,
+        expect![[r#"
+            *r"🦀\u{1f980}\\\x41
+
+
+            fsdghs"*
+            ```rust
+            &str
+            ```
+            ___
+
+            value of literal (truncated up to newline): 🦀\u{1f980}\\\x41
         "#]],
     );
 }
@@ -7428,9 +7858,12 @@ fn main() {
 "#,
         expect![[r#"
             *c"🦀\u{1f980}\\\x41"*
-            ```text
-            🦀🦀\A
+            ```rust
+            &{unknown}
             ```
+            ___
+
+            value of literal: 🦀🦀\A
         "#]],
     );
 }
@@ -7445,9 +7878,12 @@ fn main() {
 "#,
         expect![[r#"
             *b"\xF0\x9F\xA6\x80\\"*
-            ```text
-            [240, 159, 166, 128, 92]
+            ```rust
+            &[u8; 5]
             ```
+            ___
+
+            value of literal: [240, 159, 166, 128, 92]
         "#]],
     );
     check(
@@ -7458,9 +7894,12 @@ fn main() {
 "#,
         expect![[r#"
             *br"\xF0\x9F\xA6\x80\\"*
-            ```text
-            [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92]
+            ```rust
+            &[u8; 18]
             ```
+            ___
+
+            value of literal: [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92]
         "#]],
     );
 }
@@ -7475,9 +7914,12 @@ fn main() {
 "#,
         expect![[r#"
             *b'\xF0'*
-            ```text
-            0xF0
+            ```rust
+            u8
             ```
+            ___
+
+            value of literal: 0xF0
         "#]],
     );
     check(
@@ -7488,9 +7930,12 @@ fn main() {
 "#,
         expect![[r#"
             *b'\\'*
-            ```text
-            0x5C
+            ```rust
+            u8
             ```
+            ___
+
+            value of literal: 0x5C
         "#]],
     );
 }
@@ -7505,7 +7950,12 @@ fn main() {
 "#,
         expect![[r#"
             *'\x41'*
+            ```rust
+            char
+            ```
+            ___
 
+            value of literal: A
         "#]],
     );
     check(
@@ -7516,7 +7966,12 @@ fn main() {
 "#,
         expect![[r#"
             *'\\'*
+            ```rust
+            char
+            ```
+            ___
 
+            value of literal: \
         "#]],
     );
     check(
@@ -7527,7 +7982,12 @@ fn main() {
 "#,
         expect![[r#"
             *'\u{1f980}'*
+            ```rust
+            char
+            ```
+            ___
 
+            value of literal: 🦀
         "#]],
     );
 }
@@ -7542,9 +8002,12 @@ fn main() {
 "#,
         expect![[r#"
             *1.0*
-            ```text
-            1 (bits: 0x3FF0000000000000)
+            ```rust
+            f64
             ```
+            ___
+
+            value of literal: 1 (bits: 0x3FF0000000000000)
         "#]],
     );
     check(
@@ -7555,9 +8018,12 @@ fn main() {
 "#,
         expect![[r#"
             *1.0f32*
-            ```text
-            1 (bits: 0x3F800000)
+            ```rust
+            f32
             ```
+            ___
+
+            value of literal: 1 (bits: 0x3F800000)
         "#]],
     );
     check(
@@ -7568,9 +8034,12 @@ fn main() {
 "#,
         expect![[r#"
             *134e12*
-            ```text
-            134000000000000 (bits: 0x42DE77D399980000)
+            ```rust
+            f64
             ```
+            ___
+
+            value of literal: 134000000000000 (bits: 0x42DE77D399980000)
         "#]],
     );
     check(
@@ -7581,9 +8050,12 @@ fn main() {
 "#,
         expect![[r#"
             *1523527134274733643531312.0*
-            ```text
-            1523527134274733600000000 (bits: 0x44F429E9249F629B)
+            ```rust
+            f64
             ```
+            ___
+
+            value of literal: 1523527134274733600000000 (bits: 0x44F429E9249F629B)
         "#]],
     );
     check(
@@ -7594,9 +8066,12 @@ fn main() {
 "#,
         expect![[r#"
             *0.1ea123*
-            ```text
-            invalid float literal
+            ```rust
+            f64
             ```
+            ___
+
+            invalid literal: invalid float literal
         "#]],
     );
 }
@@ -7611,9 +8086,12 @@ fn main() {
 "#,
         expect![[r#"
             *34325236457856836345234*
-            ```text
-            34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010)
         "#]],
     );
     check(
@@ -7624,9 +8102,12 @@ fn main() {
 "#,
         expect![[r#"
             *134_123424_21*
-            ```text
-            13412342421 (0x31F701A95|0b1100011111011100000001101010010101)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 13412342421 (0x31F701A95|0b1100011111011100000001101010010101)
         "#]],
     );
     check(
@@ -7637,9 +8118,12 @@ fn main() {
 "#,
         expect![[r#"
             *0x12423423*
-            ```text
-            306328611 (0x12423423|0b10010010000100011010000100011)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 306328611 (0x12423423|0b10010010000100011010000100011)
         "#]],
     );
     check(
@@ -7650,9 +8134,12 @@ fn main() {
 "#,
         expect![[r#"
             *0b1111_1111*
-            ```text
-            255 (0xFF|0b11111111)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 255 (0xFF|0b11111111)
         "#]],
     );
     check(
@@ -7663,9 +8150,12 @@ fn main() {
 "#,
         expect![[r#"
             *0o12345*
-            ```text
-            5349 (0x14E5|0b1010011100101)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 5349 (0x14E5|0b1010011100101)
         "#]],
     );
     check(
@@ -7676,9 +8166,12 @@ fn main() {
 "#,
         expect![[r#"
             *0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F*
-            ```text
-            number too large to fit in target type
+            ```rust
+            i32
             ```
+            ___
+
+            invalid literal: number too large to fit in target type
         "#]],
     );
 }
@@ -7864,8 +8357,8 @@ impl Iterator for S {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 6290..6498,
-                                focus_range: 6355..6361,
+                                full_range: 7791..7999,
+                                focus_range: 7856..7862,
                                 name: "Future",
                                 kind: Trait,
                                 container_name: "future",
@@ -7878,8 +8371,8 @@ impl Iterator for S {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 7128..7594,
-                                focus_range: 7172..7180,
+                                full_range: 8629..9095,
+                                focus_range: 8673..8681,
                                 name: "Iterator",
                                 kind: Trait,
                                 container_name: "iterator",
@@ -7936,7 +8429,9 @@ struct Pedro$0<'a> {
 
             ```rust
             // size = 16 (0x10), align = 8, niches = 1
-            struct Pedro<'a>
+            struct Pedro<'a> {
+                hola: &str,
+            }
             ```
         "#]],
     )
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 15eecd1b54a..dda5a005a72 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -496,7 +496,7 @@ pub(crate) fn inlay_hints_resolve(
     config: &InlayHintsConfig,
     hasher: impl Fn(&InlayHint) -> u64,
 ) -> Option<InlayHint> {
-    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints_resolve").entered();
     let sema = Semantics::new(db);
     let file = sema.parse(file_id);
     let file = file.syntax();
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..0cb8c485b2f 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
@@ -332,6 +332,25 @@ fn main(a: SliceIter<'_, Container>) {
     }
 
     #[test]
+    fn lt_hints() {
+        check_types(
+            r#"
+struct S<'lt>;
+
+fn f<'a>() {
+    let x = S::<'static>;
+      //^ S<'static>
+    let y = S::<'_>;
+      //^ S
+    let z = S::<'a>;
+      //^ S<'a>
+
+}
+"#,
+        );
+    }
+
+    #[test]
     fn fn_hints() {
         check_types(
             r#"
@@ -341,7 +360,7 @@ fn foo1() -> impl Fn(f64) { loop {} }
 fn foo2() -> impl Fn(f64, f64) { loop {} }
 fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
 fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
-fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
+fn foo5() -> &'static for<'a> dyn Fn(&'a dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
 fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
 fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 08760c0d88c..68854c33cef 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -211,6 +211,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati
             }
         }
         Definition::BuiltinType(..) => Type,
+        Definition::BuiltinLifetime(_) => TypeParameter,
         Definition::SelfType(..) => TypeAlias,
         Definition::GenericParam(..) => TypeParameter,
         Definition::Local(it) => {
@@ -316,6 +317,7 @@ pub(crate) fn def_to_moniker(
         Definition::GenericParam(_)
         | Definition::Label(_)
         | Definition::DeriveHelper(_)
+        | Definition::BuiltinLifetime(_)
         | Definition::BuiltinAttr(_)
         | Definition::ToolModule(_) => return None,
 
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 2123c98605d..fc836d55409 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -235,9 +235,11 @@ impl TryToNav for Definition {
             Definition::TraitAlias(it) => it.try_to_nav(db),
             Definition::TypeAlias(it) => it.try_to_nav(db),
             Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?),
-            Definition::BuiltinType(_) | Definition::TupleField(_) => None,
-            Definition::ToolModule(_) => None,
-            Definition::BuiltinAttr(_) => None,
+            Definition::BuiltinLifetime(_)
+            | Definition::BuiltinType(_)
+            | Definition::TupleField(_)
+            | Definition::ToolModule(_)
+            | Definition::BuiltinAttr(_) => None,
             // FIXME: The focus range should be set to the helper declaration
             Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index b6c6753755c..64ffa591017 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -15,6 +15,7 @@ use ide_db::{
     FxHashMap, FxHashSet, RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
+use span::TextSize;
 use stdx::{always, format_to};
 use syntax::{
     ast::{self, AstNode},
@@ -48,16 +49,15 @@ impl fmt::Display for TestId {
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum RunnableKind {
-    Test { test_id: TestId, attr: TestAttr },
     TestMod { path: String },
+    Test { test_id: TestId, attr: TestAttr },
     Bench { test_id: TestId },
     DocTest { test_id: TestId },
     Bin,
 }
 
-#[cfg(test)]
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-enum RunnableTestKind {
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+enum RunnableDiscKind {
     Test,
     TestMod,
     DocTest,
@@ -65,6 +65,18 @@ enum RunnableTestKind {
     Bin,
 }
 
+impl RunnableKind {
+    fn disc(&self) -> RunnableDiscKind {
+        match self {
+            RunnableKind::TestMod { .. } => RunnableDiscKind::TestMod,
+            RunnableKind::Test { .. } => RunnableDiscKind::Test,
+            RunnableKind::DocTest { .. } => RunnableDiscKind::DocTest,
+            RunnableKind::Bench { .. } => RunnableDiscKind::Bench,
+            RunnableKind::Bin => RunnableDiscKind::Bin,
+        }
+    }
+}
+
 impl Runnable {
     // test package::module::testname
     pub fn label(&self, target: Option<String>) -> String {
@@ -97,17 +109,6 @@ impl Runnable {
         s.push_str(suffix);
         s
     }
-
-    #[cfg(test)]
-    fn test_kind(&self) -> RunnableTestKind {
-        match &self.kind {
-            RunnableKind::TestMod { .. } => RunnableTestKind::TestMod,
-            RunnableKind::Test { .. } => RunnableTestKind::Test,
-            RunnableKind::DocTest { .. } => RunnableTestKind::DocTest,
-            RunnableKind::Bench { .. } => RunnableTestKind::Bench,
-            RunnableKind::Bin => RunnableTestKind::Bin,
-        }
-    }
 }
 
 // Feature: Run
@@ -193,6 +194,20 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
             r
         })
     }));
+    res.sort_by(|Runnable { nav, kind, .. }, Runnable { nav: nav_b, kind: kind_b, .. }| {
+        // full_range.start < focus_range.start < name, should give us a decent unique ordering
+        nav.full_range
+            .start()
+            .cmp(&nav_b.full_range.start())
+            .then_with(|| {
+                let t_0 = || TextSize::from(0);
+                nav.focus_range
+                    .map_or_else(t_0, |it| it.start())
+                    .cmp(&nav_b.focus_range.map_or_else(t_0, |it| it.start()))
+            })
+            .then_with(|| kind.disc().cmp(&kind_b.disc()))
+            .then_with(|| nav.name.cmp(&nav_b.name))
+    });
     res
 }
 
@@ -571,13 +586,12 @@ mod tests {
 
     fn check(ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let mut runnables = analysis.runnables(position.file_id).unwrap();
-        runnables.sort_by_key(|it| (it.nav.full_range.start(), it.nav.name.clone()));
-
-        let result = runnables
+        let result = analysis
+            .runnables(position.file_id)
+            .unwrap()
             .into_iter()
             .map(|runnable| {
-                let mut a = format!("({:?}, {:?}", runnable.test_kind(), runnable.nav);
+                let mut a = format!("({:?}, {:?}", runnable.kind.disc(), runnable.nav);
                 if runnable.use_name_in_title {
                     a.push_str(", true");
                 }
@@ -609,6 +623,9 @@ fn main() {}
 #[export_name = "main"]
 fn __cortex_m_rt_main_trampoline() {}
 
+#[unsafe(export_name = "main")]
+fn __cortex_m_rt_main_trampoline_unsafe() {}
+
 #[test]
 fn test_foo() {}
 
@@ -628,13 +645,14 @@ mod not_a_root {
 "#,
             expect![[r#"
                 [
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..253, name: \"\", kind: Module })",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"\", kind: Module })",
                     "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })",
                     "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 78..102, focus_range: 89..97, name: \"test_foo\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 104..155, focus_range: 136..150, name: \"test_full_path\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 157..191, focus_range: 178..186, name: \"test_foo\", kind: Function })",
-                    "(Bench, NavigationTarget { file_id: FileId(0), full_range: 193..215, focus_range: 205..210, name: \"bench\", kind: Function })",
+                    "(Bin, NavigationTarget { file_id: FileId(0), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 156..180, focus_range: 167..175, name: \"test_foo\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 182..233, focus_range: 214..228, name: \"test_full_path\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..269, focus_range: 256..264, name: \"test_foo\", kind: Function })",
+                    "(Bench, NavigationTarget { file_id: FileId(0), full_range: 271..293, focus_range: 283..288, name: \"bench\", kind: Function })",
                 ]
             "#]],
         );
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 ca013da7099..0d2311b6e98 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -167,7 +167,8 @@ impl StaticIndex<'_> {
             keywords: true,
             format: crate::HoverDocFormat::Markdown,
             max_trait_assoc_items_count: None,
-            max_struct_field_count: None,
+            max_fields_count: Some(5),
+            max_enum_variants_count: Some(5),
         };
         let tokens = tokens.filter(|token| {
             matches!(
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
index 5913ca5e454..0439e509d21 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
@@ -25,7 +25,7 @@ pub(super) fn highlight_escape_string<T: IsString>(
 }
 
 pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
-    if char.value().is_none() {
+    if char.value().is_err() {
         // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
         // state and this token contains junks, since `'` is not a reliable delimiter (consider
         // lifetimes). Nonetheless, parser errors should already be emitted.
@@ -48,7 +48,7 @@ pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start:
 }
 
 pub(super) fn highlight_escape_byte(stack: &mut Highlights, byte: &Byte, start: TextSize) {
-    if byte.value().is_none() {
+    if byte.value().is_err() {
         // See `highlight_escape_char` for why no error highlighting here.
         return;
     }
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 a72f505eb85..3b784ebec3b 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
@@ -484,6 +484,7 @@ pub(super) fn highlight_def(
             h
         }
         Definition::BuiltinType(_) => Highlight::new(HlTag::BuiltinType),
+        Definition::BuiltinLifetime(_) => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)),
         Definition::Static(s) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
 
@@ -542,13 +543,14 @@ pub(super) fn highlight_def(
     let def_crate = def.krate(db);
     let is_from_other_crate = def_crate != Some(krate);
     let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db));
-    let is_builtin_type = matches!(def, Definition::BuiltinType(_));
-    let is_public = def.visibility(db) == Some(hir::Visibility::Public);
-
-    match (is_from_other_crate, is_builtin_type, is_public) {
-        (true, false, _) => h |= HlMod::Library,
-        (false, _, true) => h |= HlMod::Public,
-        _ => {}
+    let is_builtin = matches!(
+        def,
+        Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_)
+    );
+    match is_from_other_crate {
+        true if !is_builtin => h |= HlMod::Library,
+        false if def.visibility(db) == Some(hir::Visibility::Public) => h |= HlMod::Public,
+        _ => (),
     }
 
     if is_from_builtin_crate {
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 6bf13ffd06f..f9b8a22a3c0 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
@@ -30,7 +30,7 @@ pub(super) fn ra_fixture(
     if !active_parameter.ident().map_or(false, |name| name.text().starts_with("ra_fixture")) {
         return None;
     }
-    let value = literal.value()?;
+    let value = literal.value().ok()?;
 
     if let Some(range) = literal.open_quote_text_range() {
         hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
@@ -299,6 +299,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag {
         Definition::Trait(_) => SymbolKind::Trait,
         Definition::TraitAlias(_) => SymbolKind::TraitAlias,
         Definition::TypeAlias(_) => SymbolKind::TypeAlias,
+        Definition::BuiltinLifetime(_) => SymbolKind::LifetimeParam,
         Definition::BuiltinType(_) => return HlTag::BuiltinType,
         Definition::Macro(_) => SymbolKind::Macro,
         Definition::Field(_) | Definition::TupleField(_) => SymbolKind::Field,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index de902b5137d..cad5a8b593f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -45,7 +45,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">identity</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Default</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index 366895ce7ec..893e3c06751 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -49,5 +49,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="enum_variant default_library library">Some</span><span class="parenthesis">(</span><span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method consuming default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</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/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index b2ca6e1ca4b..35650bbe87f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -79,7 +79,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">/// # Examples</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected library">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="keyword">pub</span> <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration public static">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
@@ -162,12 +162,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="comment documentation">///</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</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">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</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">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="module injected">alloc</span><span class="operator injected">::</span><span class="macro injected">vec</span><span class="macro_bang injected">!</span><span class="bracket injected macro">[</span><span class="numeric_literal injected macro">1</span><span class="comma injected macro">,</span><span class="none injected"> </span><span class="numeric_literal injected macro">2</span><span class="comma injected macro">,</span><span class="none injected"> </span><span class="numeric_literal injected macro">3</span><span class="bracket injected macro">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration public">mix_and_match</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 5234d362c26..413edb6d65f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -49,13 +49,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</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">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnMut</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnOnce</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</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">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">Fn</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnMut</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
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 7a07d17b271..22706dea1fa 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
@@ -158,9 +158,9 @@ 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">"</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 default_library library">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 default_library library">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 default_library library">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 default_library library">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 default_library library">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 default_library library">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">"{}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>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 15d6be6334c..be6176894b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -69,7 +69,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</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">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
     <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
 <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 31b0c8cdec5..76940ab57ab 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -17,6 +17,7 @@ use itertools::Itertools;
 use proc_macro_api::{MacroDylib, ProcMacroServer};
 use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
 use span::Span;
+use tracing::{instrument, Level};
 use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath};
 
 pub struct LoadCargoConfig {
@@ -50,6 +51,7 @@ pub fn load_workspace_at(
     load_workspace(workspace, &cargo_config.extra_env, load_config)
 }
 
+#[instrument(skip_all)]
 pub fn load_workspace(
     ws: ProjectWorkspace,
     extra_env: &FxHashMap<String, String>,
@@ -66,9 +68,9 @@ pub fn load_workspace(
     let proc_macro_server = match &load_config.with_proc_macro_server {
         ProcMacroServerChoice::Sysroot => ws
             .find_sysroot_proc_macro_srv()
-            .and_then(|it| ProcMacroServer::spawn(it, extra_env).map_err(Into::into)),
+            .and_then(|it| ProcMacroServer::spawn(&it, extra_env).map_err(Into::into)),
         ProcMacroServerChoice::Explicit(path) => {
-            ProcMacroServer::spawn(path.clone(), extra_env).map_err(Into::into)
+            ProcMacroServer::spawn(path, extra_env).map_err(Into::into)
         }
         ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")),
     };
@@ -333,9 +335,7 @@ fn load_crate_graph(
     vfs: &mut vfs::Vfs,
     receiver: &Receiver<vfs::loader::Message>,
 ) -> RootDatabase {
-    let (ProjectWorkspace::Cargo { toolchain, target_layout, .. }
-    | ProjectWorkspace::Json { toolchain, target_layout, .. }
-    | ProjectWorkspace::DetachedFile { toolchain, target_layout, .. }) = ws;
+    let ProjectWorkspace { toolchain, target_layout, .. } = ws;
 
     let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
     let mut db = RootDatabase::new(lru_cap);
@@ -352,6 +352,8 @@ fn load_crate_graph(
                 }
             }
             vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => {
+                let _p = tracing::span!(Level::INFO, "load_cargo::load_crate_craph/LoadedChanged")
+                    .entered();
                 for (path, contents) in files {
                     vfs.set_file_contents(path.into(), contents);
                 }
@@ -359,8 +361,8 @@ fn load_crate_graph(
         }
     }
     let changes = vfs.take_changes();
-    for file in changes {
-        if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
+    for (_, file) in changes {
+        if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
             if let Ok(text) = String::from_utf8(v) {
                 analysis_change.change_file(file.file_id, Some(text))
             }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index f4bbaef7af3..f73e188c797 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -10,7 +10,7 @@ use test_utils::{bench, bench_fixture, skip_slow_tests};
 
 use crate::{
     parser::{MetaVarKind, Op, RepeatKind, Separator},
-    syntax_node_to_token_tree, DeclarativeMacro, DummyTestSpanMap, DUMMY,
+    syntax_node_to_token_tree, DeclarativeMacro, DocCommentDesugarMode, DummyTestSpanMap, DUMMY,
 };
 
 #[test]
@@ -78,6 +78,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree<Span>> {
                 rule.token_tree().unwrap().syntax(),
                 DummyTestSpanMap,
                 DUMMY,
+                DocCommentDesugarMode::Mbe,
             );
             (id, def_tt)
         })
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index d5de56312a3..6920832dd2e 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -34,7 +34,7 @@ pub use tt::{Delimiter, DelimiterKind, Punct};
 pub use crate::syntax_bridge::{
     parse_exprs_with_sep, parse_to_token_tree, parse_to_token_tree_static_span,
     syntax_node_to_token_tree, syntax_node_to_token_tree_modified, token_tree_to_syntax_node,
-    SpanMapper,
+    DocCommentDesugarMode, SpanMapper,
 };
 
 pub use crate::syntax_bridge::dummy_test_span_utils::*;
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index 3230eeb5bd8..412e4921768 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -69,18 +69,28 @@ pub(crate) mod dummy_test_span_utils {
     }
 }
 
+/// Doc comment desugaring differs between mbe and proc-macros.
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum DocCommentDesugarMode {
+    /// Desugars doc comments as quoted raw strings
+    Mbe,
+    /// Desugars doc comments as quoted strings
+    ProcMacro,
+}
+
 /// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the
 /// subtree's spans.
 pub fn syntax_node_to_token_tree<Ctx, SpanMap>(
     node: &SyntaxNode,
     map: SpanMap,
     span: SpanData<Ctx>,
+    mode: DocCommentDesugarMode,
 ) -> tt::Subtree<SpanData<Ctx>>
 where
     SpanData<Ctx>: Copy + fmt::Debug,
     SpanMap: SpanMapper<SpanData<Ctx>>,
 {
-    let mut c = Converter::new(node, map, Default::default(), Default::default(), span);
+    let mut c = Converter::new(node, map, Default::default(), Default::default(), span, mode);
     convert_tokens(&mut c)
 }
 
@@ -93,12 +103,13 @@ pub fn syntax_node_to_token_tree_modified<Ctx, SpanMap>(
     append: FxHashMap<SyntaxElement, Vec<tt::Leaf<SpanData<Ctx>>>>,
     remove: FxHashSet<SyntaxElement>,
     call_site: SpanData<Ctx>,
+    mode: DocCommentDesugarMode,
 ) -> tt::Subtree<SpanData<Ctx>>
 where
     SpanMap: SpanMapper<SpanData<Ctx>>,
     SpanData<Ctx>: Copy + fmt::Debug,
 {
-    let mut c = Converter::new(node, map, append, remove, call_site);
+    let mut c = Converter::new(node, map, append, remove, call_site, mode);
     convert_tokens(&mut c)
 }
 
@@ -165,7 +176,8 @@ where
     if lexed.errors().next().is_some() {
         return None;
     }
-    let mut conv = RawConverter { lexed, anchor, pos: 0, ctx };
+    let mut conv =
+        RawConverter { lexed, anchor, pos: 0, ctx, mode: DocCommentDesugarMode::ProcMacro };
     Some(convert_tokens(&mut conv))
 }
 
@@ -178,7 +190,8 @@ where
     if lexed.errors().next().is_some() {
         return None;
     }
-    let mut conv = StaticRawConverter { lexed, pos: 0, span };
+    let mut conv =
+        StaticRawConverter { lexed, pos: 0, span, mode: DocCommentDesugarMode::ProcMacro };
     Some(convert_tokens(&mut conv))
 }
 
@@ -405,7 +418,7 @@ fn is_single_token_op(kind: SyntaxKind) -> bool {
 /// That is, strips leading `///` (or `/**`, etc)
 /// and strips the ending `*/`
 /// And then quote the string, which is needed to convert to `tt::Literal`
-fn doc_comment_text(comment: &ast::Comment) -> SmolStr {
+fn doc_comment_text(comment: &ast::Comment, mode: DocCommentDesugarMode) -> SmolStr {
     let prefix_len = comment.prefix().len();
     let mut text = &comment.text()[prefix_len..];
 
@@ -414,26 +427,34 @@ fn doc_comment_text(comment: &ast::Comment) -> SmolStr {
         text = &text[0..text.len() - 2];
     }
 
-    let mut num_of_hashes = 0;
-    let mut count = 0;
-    for ch in text.chars() {
-        count = match ch {
-            '"' => 1,
-            '#' if count > 0 => count + 1,
-            _ => 0,
-        };
-        num_of_hashes = num_of_hashes.max(count);
-    }
+    let text = match mode {
+        DocCommentDesugarMode::Mbe => {
+            let mut num_of_hashes = 0;
+            let mut count = 0;
+            for ch in text.chars() {
+                count = match ch {
+                    '"' => 1,
+                    '#' if count > 0 => count + 1,
+                    _ => 0,
+                };
+                num_of_hashes = num_of_hashes.max(count);
+            }
 
-    // Quote raw string with delimiters
-    // Note that `tt::Literal` expect an escaped string
-    let text = format!("r{delim}\"{text}\"{delim}", delim = "#".repeat(num_of_hashes));
+            // Quote raw string with delimiters
+            // Note that `tt::Literal` expect an escaped string
+            format!(r#"r{delim}"{text}"{delim}"#, delim = "#".repeat(num_of_hashes))
+        }
+        // Quote string with delimiters
+        // Note that `tt::Literal` expect an escaped string
+        DocCommentDesugarMode::ProcMacro => format!(r#""{}""#, text.escape_debug()),
+    };
     text.into()
 }
 
 fn convert_doc_comment<S: Copy>(
     token: &syntax::SyntaxToken,
     span: S,
+    mode: DocCommentDesugarMode,
 ) -> Option<Vec<tt::TokenTree<S>>> {
     cov_mark::hit!(test_meta_doc_comments);
     let comment = ast::Comment::cast(token.clone())?;
@@ -451,7 +472,7 @@ fn convert_doc_comment<S: Copy>(
     };
 
     let mk_doc_literal = |comment: &ast::Comment| {
-        let lit = tt::Literal { text: doc_comment_text(comment), span };
+        let lit = tt::Literal { text: doc_comment_text(comment, mode), span };
 
         tt::TokenTree::from(tt::Leaf::from(lit))
     };
@@ -479,12 +500,14 @@ struct RawConverter<'a, Ctx> {
     pos: usize,
     anchor: SpanAnchor,
     ctx: Ctx,
+    mode: DocCommentDesugarMode,
 }
 /// A raw token (straight from lexer) converter that gives every token the same span.
 struct StaticRawConverter<'a, S> {
     lexed: parser::LexedStr<'a>,
     pos: usize,
     span: S,
+    mode: DocCommentDesugarMode,
 }
 
 trait SrcToken<Ctx, S> {
@@ -553,7 +576,7 @@ where
         span: SpanData<Ctx>,
     ) -> Option<Vec<tt::TokenTree<SpanData<Ctx>>>> {
         let text = self.lexed.text(token);
-        convert_doc_comment(&doc_comment(text), span)
+        convert_doc_comment(&doc_comment(text), span, self.mode)
     }
 
     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
@@ -592,7 +615,7 @@ where
 
     fn convert_doc_comment(&self, &token: &usize, span: S) -> Option<Vec<tt::TokenTree<S>>> {
         let text = self.lexed.text(token);
-        convert_doc_comment(&doc_comment(text), span)
+        convert_doc_comment(&doc_comment(text), span, self.mode)
     }
 
     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
@@ -634,6 +657,7 @@ struct Converter<SpanMap, S> {
     append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
     remove: FxHashSet<SyntaxElement>,
     call_site: S,
+    mode: DocCommentDesugarMode,
 }
 
 impl<SpanMap, S> Converter<SpanMap, S> {
@@ -643,6 +667,7 @@ impl<SpanMap, S> Converter<SpanMap, S> {
         append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
         remove: FxHashSet<SyntaxElement>,
         call_site: S,
+        mode: DocCommentDesugarMode,
     ) -> Self {
         let mut this = Converter {
             current: None,
@@ -654,6 +679,7 @@ impl<SpanMap, S> Converter<SpanMap, S> {
             remove,
             call_site,
             current_leaves: vec![],
+            mode,
         };
         let first = this.next_token();
         this.current = first;
@@ -755,7 +781,7 @@ where
 {
     type Token = SynToken<S>;
     fn convert_doc_comment(&self, token: &Self::Token, span: S) -> Option<Vec<tt::TokenTree<S>>> {
-        convert_doc_comment(token.token(), span)
+        convert_doc_comment(token.token(), span, self.mode)
     }
 
     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
index bbfe378200d..2988fb3cf15 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
@@ -7,11 +7,16 @@ use tt::{
     Leaf, Punct, Spacing,
 };
 
-use crate::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+use crate::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
 
 fn check_punct_spacing(fixture: &str) {
     let source_file = ast::SourceFile::parse(fixture, span::Edition::CURRENT).ok().unwrap();
-    let subtree = syntax_node_to_token_tree(source_file.syntax(), DummyTestSpanMap, DUMMY);
+    let subtree = syntax_node_to_token_tree(
+        source_file.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::Mbe,
+    );
     let mut annotations: FxHashMap<_, _> = extract_annotations(fixture)
         .into_iter()
         .map(|(range, annotation)| {
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
index c13a1943792..82e4d661488 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
@@ -36,8 +36,33 @@ fn attr(p: &mut Parser<'_>, inner: bool) {
     attr.complete(p, ATTR);
 }
 
+// test metas
+// #![simple_ident]
+// #![simple::path]
+// #![simple_ident_expr = ""]
+// #![simple::path::Expr = ""]
+// #![simple_ident_tt(a b c)]
+// #![simple_ident_tt[a b c]]
+// #![simple_ident_tt{a b c}]
+// #![simple::path::tt(a b c)]
+// #![simple::path::tt[a b c]]
+// #![simple::path::tt{a b c}]
+// #![unsafe(simple_ident)]
+// #![unsafe(simple::path)]
+// #![unsafe(simple_ident_expr = "")]
+// #![unsafe(simple::path::Expr = "")]
+// #![unsafe(simple_ident_tt(a b c))]
+// #![unsafe(simple_ident_tt[a b c])]
+// #![unsafe(simple_ident_tt{a b c})]
+// #![unsafe(simple::path::tt(a b c))]
+// #![unsafe(simple::path::tt[a b c])]
+// #![unsafe(simple::path::tt{a b c})]
 pub(super) fn meta(p: &mut Parser<'_>) {
     let meta = p.start();
+    let is_unsafe = p.eat(T![unsafe]);
+    if is_unsafe {
+        p.expect(T!['(']);
+    }
     paths::use_path(p);
 
     match p.current() {
@@ -50,6 +75,9 @@ pub(super) fn meta(p: &mut Parser<'_>) {
         T!['('] | T!['['] | T!['{'] => items::token_tree(p),
         _ => {}
     }
+    if is_unsafe {
+        p.expect(T![')']);
+    }
 
     meta.complete(p, META);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast
new file mode 100644
index 00000000000..b1ac60b530e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast
@@ -0,0 +1,457 @@
+SOURCE_FILE
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "simple"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "path"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "Expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "simple"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "path"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "Expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs
new file mode 100644
index 00000000000..57b7bb7170d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs
@@ -0,0 +1,20 @@
+#![simple_ident]
+#![simple::path]
+#![simple_ident_expr = ""]
+#![simple::path::Expr = ""]
+#![simple_ident_tt(a b c)]
+#![simple_ident_tt[a b c]]
+#![simple_ident_tt{a b c}]
+#![simple::path::tt(a b c)]
+#![simple::path::tt[a b c]]
+#![simple::path::tt{a b c}]
+#![unsafe(simple_ident)]
+#![unsafe(simple::path)]
+#![unsafe(simple_ident_expr = "")]
+#![unsafe(simple::path::Expr = "")]
+#![unsafe(simple_ident_tt(a b c))]
+#![unsafe(simple_ident_tt[a b c])]
+#![unsafe(simple_ident_tt{a b c})]
+#![unsafe(simple::path::tt(a b c))]
+#![unsafe(simple::path::tt[a b c])]
+#![unsafe(simple::path::tt{a b c})]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 0ab16c38c87..87494172907 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -13,7 +13,7 @@ mod version;
 
 use base_db::Env;
 use indexmap::IndexSet;
-use paths::AbsPathBuf;
+use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
 use span::Span;
 use std::{
@@ -54,6 +54,7 @@ pub struct ProcMacroServer {
     ///
     /// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here.
     process: Arc<Mutex<ProcMacroProcessSrv>>,
+    path: AbsPathBuf,
 }
 
 pub struct MacroDylib {
@@ -113,15 +114,22 @@ pub struct MacroPanic {
 impl ProcMacroServer {
     /// Spawns an external process as the proc macro server and returns a client connected to it.
     pub fn spawn(
-        process_path: AbsPathBuf,
+        process_path: &AbsPath,
         env: &FxHashMap<String, String>,
     ) -> io::Result<ProcMacroServer> {
         let process = ProcMacroProcessSrv::run(process_path, env)?;
-        Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
+        Ok(ProcMacroServer {
+            process: Arc::new(Mutex::new(process)),
+            path: process_path.to_owned(),
+        })
+    }
+
+    pub fn path(&self) -> &AbsPath {
+        &self.path
     }
 
     pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
-        let _p = tracing::span!(tracing::Level::INFO, "ProcMacroClient::load_dylib").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ProcMacroServer::load_dylib").entered();
         let macros =
             self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?;
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index 35d48a15543..dce086d4299 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -6,7 +6,7 @@ use std::{
     sync::Arc,
 };
 
-use paths::{AbsPath, AbsPathBuf};
+use paths::AbsPath;
 use rustc_hash::FxHashMap;
 use stdx::JodChild;
 
@@ -28,11 +28,11 @@ pub(crate) struct ProcMacroProcessSrv {
 
 impl ProcMacroProcessSrv {
     pub(crate) fn run(
-        process_path: AbsPathBuf,
+        process_path: &AbsPath,
         env: &FxHashMap<String, String>,
     ) -> io::Result<ProcMacroProcessSrv> {
         let create_srv = |null_stderr| {
-            let mut process = Process::run(process_path.clone(), env, null_stderr)?;
+            let mut process = Process::run(process_path, env, null_stderr)?;
             let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
 
             io::Result::Ok(ProcMacroProcessSrv {
@@ -153,11 +153,11 @@ struct Process {
 
 impl Process {
     fn run(
-        path: AbsPathBuf,
+        path: &AbsPath,
         env: &FxHashMap<String, String>,
         null_stderr: bool,
     ) -> io::Result<Process> {
-        let child = JodChild(mk_child(&path, env, null_stderr)?);
+        let child = JodChild(mk_child(path, env, null_stderr)?);
         Ok(Process { child })
     }
 
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index a87b67f5c69..11a8e7af56a 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -24,7 +24,7 @@ jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = tr
 perf-event = "=0.4.7"
 
 [target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] }
+windows-sys = { version = "0.52", features = ["Win32_System_Threading", "Win32_System_ProcessStatus"] }
 
 [features]
 cpu_profiler = []
diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs
index a3fdb72a6d1..2ccb1cd06ae 100644
--- a/src/tools/rust-analyzer/crates/profile/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/lib.rs
@@ -26,7 +26,7 @@ thread_local!(static IN_SCOPE: RefCell<bool> = const { RefCell::new(false) });
 /// A wrapper around google_cpu_profiler.
 ///
 /// Usage:
-/// 1. Install gpref_tools (<https://github.com/gperftools/gperftools>), probably packaged with your Linux distro.
+/// 1. Install gperf_tools (<https://github.com/gperftools/gperftools>), probably packaged with your Linux distro.
 /// 2. Build with `cpu_profiler` feature.
 /// 3. Run the code, the *raw* output would be in the `./out.profile` file.
 /// 4. Install pprof for visualization (<https://github.com/google/pprof>).
diff --git a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
index f089c78e0c1..660afff3dca 100644
--- a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
@@ -37,8 +37,7 @@ impl MemoryUsage {
                 // There doesn't seem to be an API for determining heap usage, so we try to
                 // approximate that by using the Commit Charge value.
 
-                use winapi::um::processthreadsapi::*;
-                use winapi::um::psapi::*;
+                use windows_sys::Win32::System::{Threading::*, ProcessStatus::*};
                 use std::mem::{MaybeUninit, size_of};
 
                 let proc = unsafe { GetCurrentProcess() };
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index fbd423c9eac..8e1f7fdcded 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -24,7 +24,7 @@ use toolchain::Tool;
 
 use crate::{
     cfg::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
-    InvocationStrategy, Package, Sysroot, TargetKind,
+    InvocationStrategy, ManifestPath, Package, Sysroot, TargetKind,
 };
 
 /// Output of the build script and proc-macro building steps for a workspace.
@@ -63,9 +63,11 @@ impl WorkspaceBuildScripts {
     fn build_command(
         config: &CargoConfig,
         allowed_features: &FxHashSet<String>,
-        workspace_root: &AbsPathBuf,
+        manifest_path: &ManifestPath,
+        toolchain: Option<&Version>,
         sysroot: Option<&Sysroot>,
     ) -> io::Result<Command> {
+        const RUST_1_75: Version = Version::new(1, 75, 0);
         let mut cmd = match config.run_build_script_command.as_deref() {
             Some([program, args @ ..]) => {
                 let mut cmd = Command::new(program);
@@ -79,7 +81,7 @@ impl WorkspaceBuildScripts {
                 cmd.args(&config.extra_args);
 
                 cmd.arg("--manifest-path");
-                cmd.arg(workspace_root.join("Cargo.toml"));
+                cmd.arg(manifest_path.as_ref());
 
                 if let Some(target_dir) = &config.target_dir {
                     cmd.arg("--target-dir").arg(target_dir);
@@ -116,6 +118,14 @@ impl WorkspaceBuildScripts {
                     }
                 }
 
+                if manifest_path.is_rust_manifest() {
+                    cmd.arg("-Zscript");
+                }
+
+                if toolchain.map_or(false, |it| *it >= RUST_1_75) {
+                    cmd.arg("--keep-going");
+                }
+
                 cmd
             }
         };
@@ -138,11 +148,9 @@ impl WorkspaceBuildScripts {
         config: &CargoConfig,
         workspace: &CargoWorkspace,
         progress: &dyn Fn(String),
-        toolchain: &Option<Version>,
+        toolchain: Option<&Version>,
         sysroot: Option<&Sysroot>,
     ) -> io::Result<WorkspaceBuildScripts> {
-        const RUST_1_75: Version = Version::new(1, 75, 0);
-
         let current_dir = match &config.invocation_location {
             InvocationLocation::Root(root) if config.run_build_script_command.is_some() => {
                 root.as_path()
@@ -152,37 +160,14 @@ impl WorkspaceBuildScripts {
         .as_ref();
 
         let allowed_features = workspace.workspace_features();
-
-        match Self::run_per_ws(
-            Self::build_command(
-                config,
-                &allowed_features,
-                &workspace.workspace_root().to_path_buf(),
-                sysroot,
-            )?,
-            workspace,
-            current_dir,
-            progress,
-        ) {
-            Ok(WorkspaceBuildScripts { error: Some(error), .. })
-                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_75) =>
-            {
-                // building build scripts failed, attempt to build with --keep-going so
-                // that we potentially get more build data
-                let mut cmd = Self::build_command(
-                    config,
-                    &allowed_features,
-                    &workspace.workspace_root().to_path_buf(),
-                    sysroot,
-                )?;
-
-                cmd.args(["--keep-going"]);
-                let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
-                res.error = Some(error);
-                Ok(res)
-            }
-            res => res,
-        }
+        let cmd = Self::build_command(
+            config,
+            &allowed_features,
+            workspace.manifest_path(),
+            toolchain,
+            sysroot,
+        )?;
+        Self::run_per_ws(cmd, workspace, current_dir, progress)
     }
 
     /// Runs the build scripts by invoking the configured command *once*.
@@ -204,7 +189,14 @@ impl WorkspaceBuildScripts {
                 ))
             }
         };
-        let cmd = Self::build_command(config, &Default::default(), workspace_root, None)?;
+        let cmd = Self::build_command(
+            config,
+            &Default::default(),
+            // This is not gonna be used anyways, so just construct a dummy here
+            &ManifestPath::try_from(workspace_root.clone()).unwrap(),
+            None,
+            None,
+        )?;
         // NB: Cargo.toml could have been modified between `cargo metadata` and
         // `cargo check`. We shouldn't assume that package ids we see here are
         // exactly those from `config`.
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index ff7cf144aa8..9955f2687c9 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -32,6 +32,7 @@ pub struct CargoWorkspace {
     targets: Arena<TargetData>,
     workspace_root: AbsPathBuf,
     target_directory: AbsPathBuf,
+    manifest_path: ManifestPath,
 }
 
 impl ops::Index<Package> for CargoWorkspace {
@@ -306,7 +307,7 @@ impl CargoWorkspace {
             );
         }
         // The manifest is a rust file, so this means its a script manifest
-        if cargo_toml.extension().is_some_and(|ext| ext == "rs") {
+        if cargo_toml.is_rust_manifest() {
             // Deliberately don't set up RUSTC_BOOTSTRAP or a nightly override here, the user should
             // opt into it themselves.
             other_options.push("-Zscript".to_owned());
@@ -334,7 +335,7 @@ impl CargoWorkspace {
         .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
     }
 
-    pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace {
+    pub fn new(mut meta: cargo_metadata::Metadata, manifest_path: ManifestPath) -> CargoWorkspace {
         let mut pkg_by_id = FxHashMap::default();
         let mut packages = Arena::default();
         let mut targets = Arena::default();
@@ -448,7 +449,7 @@ impl CargoWorkspace {
 
         let target_directory = AbsPathBuf::assert(meta.target_directory);
 
-        CargoWorkspace { packages, targets, workspace_root, target_directory }
+        CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path }
     }
 
     pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
@@ -466,6 +467,10 @@ impl CargoWorkspace {
         &self.workspace_root
     }
 
+    pub fn manifest_path(&self) -> &ManifestPath {
+        &self.manifest_path
+    }
+
     pub fn target_directory(&self) -> &AbsPath {
         &self.target_directory
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index 762e01c9177..5520cdaff6b 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -60,16 +60,19 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe
 }
 
 pub(crate) fn cargo_config_env(
-    cargo_toml: &ManifestPath,
+    manifest: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
     sysroot: Option<&Sysroot>,
 ) -> FxHashMap<String, String> {
     let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo);
     cargo_config.envs(extra_env);
     cargo_config
-        .current_dir(cargo_toml.parent())
+        .current_dir(manifest.parent())
         .args(["-Z", "unstable-options", "config", "get", "env"])
         .env("RUSTC_BOOTSTRAP", "1");
+    if manifest.is_rust_manifest() {
+        cargo_config.arg("-Zscript");
+    }
     // if successful we receive `env.key.value = "value" per entry
     tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
     utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default()
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 7f3e35ca5db..181c07f46b2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -52,13 +52,15 @@ pub use crate::{
     manifest_path::ManifestPath,
     project_json::{ProjectJson, ProjectJsonData},
     sysroot::Sysroot,
-    workspace::{FileLoader, PackageRoot, ProjectWorkspace},
+    workspace::{FileLoader, PackageRoot, ProjectWorkspace, ProjectWorkspaceKind},
 };
+pub use cargo_metadata::Metadata;
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub enum ProjectManifest {
     ProjectJson(ManifestPath),
     CargoToml(ManifestPath),
+    CargoScript(ManifestPath),
 }
 
 impl ProjectManifest {
@@ -71,7 +73,10 @@ impl ProjectManifest {
         if path.file_name().unwrap_or_default() == "Cargo.toml" {
             return Ok(ProjectManifest::CargoToml(path));
         }
-        bail!("project root must point to Cargo.toml or rust-project.json: {path}");
+        if path.extension().unwrap_or_default() == "rs" {
+            return Ok(ProjectManifest::CargoScript(path));
+        }
+        bail!("project root must point to a Cargo.toml, rust-project.json or <script>.rs file: {path}");
     }
 
     pub fn discover_single(path: &AbsPath) -> anyhow::Result<ProjectManifest> {
@@ -146,15 +151,19 @@ impl ProjectManifest {
         res.sort();
         res
     }
+
+    pub fn manifest_path(&self) -> &ManifestPath {
+        match self {
+            ProjectManifest::ProjectJson(it)
+            | ProjectManifest::CargoToml(it)
+            | ProjectManifest::CargoScript(it) => it,
+        }
+    }
 }
 
 impl fmt::Display for ProjectManifest {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            ProjectManifest::ProjectJson(it) | ProjectManifest::CargoToml(it) => {
-                fmt::Display::fmt(&it, f)
-            }
-        }
+        fmt::Display::fmt(self.manifest_path(), f)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
index d86e81e7e1a..2331c0c36c3 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
@@ -1,5 +1,5 @@
 //! See [`ManifestPath`].
-use std::{fmt, ops, path::Path};
+use std::{borrow::Borrow, fmt, ops};
 
 use paths::{AbsPath, AbsPathBuf};
 
@@ -38,6 +38,10 @@ impl ManifestPath {
     pub fn canonicalize(&self) -> ! {
         (**self).canonicalize()
     }
+
+    pub fn is_rust_manifest(&self) -> bool {
+        self.file.extension().map_or(false, |ext| ext == "rs")
+    }
 }
 
 impl fmt::Display for ManifestPath {
@@ -54,8 +58,14 @@ impl ops::Deref for ManifestPath {
     }
 }
 
-impl AsRef<Path> for ManifestPath {
-    fn as_ref(&self) -> &Path {
+impl AsRef<AbsPath> for ManifestPath {
+    fn as_ref(&self) -> &AbsPath {
         self.file.as_ref()
     }
 }
+
+impl Borrow<AbsPath> for ManifestPath {
+    fn borrow(&self) -> &AbsPath {
+        self.file.borrow()
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index fac6eb8ad3e..5bee446f619 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -56,6 +56,7 @@ use serde::{de, Deserialize, Serialize};
 use span::Edition;
 
 use crate::cfg::CfgFlag;
+use crate::ManifestPath;
 
 /// Roots and crates that compose this Rust project.
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -65,6 +66,7 @@ pub struct ProjectJson {
     /// e.g. `path/to/sysroot/lib/rustlib/src/rust`
     pub(crate) sysroot_src: Option<AbsPathBuf>,
     project_root: AbsPathBuf,
+    manifest: Option<ManifestPath>,
     crates: Vec<Crate>,
 }
 
@@ -96,12 +98,17 @@ impl ProjectJson {
     /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
     /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
     ///            configuration.
-    pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
+    pub fn new(
+        manifest: Option<ManifestPath>,
+        base: &AbsPath,
+        data: ProjectJsonData,
+    ) -> ProjectJson {
         let absolutize_on_base = |p| base.absolutize(p);
         ProjectJson {
             sysroot: data.sysroot.map(absolutize_on_base),
             sysroot_src: data.sysroot_src.map(absolutize_on_base),
             project_root: base.to_path_buf(),
+            manifest,
             crates: data
                 .crates
                 .into_iter()
@@ -159,6 +166,11 @@ impl ProjectJson {
     pub fn path(&self) -> &AbsPath {
         &self.project_root
     }
+
+    /// Returns the path to the project's manifest or root folder, if no manifest exists.
+    pub fn manifest_or_root(&self) -> &AbsPath {
+        self.manifest.as_ref().map_or(&self.project_root, |manifest| manifest.as_ref())
+    }
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
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 1142d6243d2..e6bbe6ede8a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -4,7 +4,7 @@
 //! but we can't process `.rlib` and need source code instead. The source code
 //! is typically installed with `rustup component add rust-src` command.
 
-use std::{env, fs, iter, ops, process::Command, sync::Arc};
+use std::{env, fs, ops, process::Command, sync::Arc};
 
 use anyhow::{format_err, Result};
 use base_db::CrateName;
@@ -58,13 +58,11 @@ impl Stitched {
     pub(crate) fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
         // core is added as a dependency before std in order to
         // mimic rustcs dependency order
-        ["core", "alloc", "std"]
-            .into_iter()
-            .zip(iter::repeat(true))
-            .chain(iter::once(("test", false)))
-            .filter_map(move |(name, prelude)| {
+        [("core", true), ("alloc", false), ("std", true), ("test", false)].into_iter().filter_map(
+            move |(name, prelude)| {
                 Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
-            })
+            },
+        )
     }
 
     pub(crate) fn proc_macro(&self) -> Option<SysrootCrate> {
@@ -133,6 +131,24 @@ impl Sysroot {
         }
     }
 
+    pub fn check_has_core(&self) -> Result<(), String> {
+        let Some(Ok(src_root)) = &self.src_root else { return Ok(()) };
+        let has_core = match &self.mode {
+            SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+            SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
+        };
+        if !has_core {
+            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
+                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
+            } else {
+                " try running `rustup component add rust-src` to possible fix this"
+            };
+            Err(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
+        } else {
+            Ok(())
+        }
+    }
+
     pub fn num_packages(&self) -> usize {
         match &self.mode {
             SysrootMode::Workspace(ws) => ws.packages().count(),
@@ -349,7 +365,7 @@ impl Sysroot {
                     .filter(|&package| RELEVANT_SYSROOT_CRATES.contains(&&*package.name))
                     .map(|package| package.id.clone())
                     .collect();
-                let cargo_workspace = CargoWorkspace::new(res);
+                let cargo_workspace = CargoWorkspace::new(res, sysroot_cargo_toml);
                 Some(Sysroot {
                     root: sysroot_dir.clone(),
                     src_root: Some(Ok(sysroot_src_dir.clone())),
@@ -368,7 +384,7 @@ impl Sysroot {
                 .into_iter()
                 .map(|it| sysroot_src_dir.join(it))
                 .filter_map(|it| ManifestPath::try_from(it).ok())
-                .find(|it| fs::metadata(it).is_ok());
+                .find(|it| fs::metadata(it.as_ref()).is_ok());
 
             if let Some(root) = root {
                 stitched.crates.alloc(SysrootCrateData {
@@ -468,7 +484,7 @@ fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
     let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
     let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
     tracing::debug!("checking for rustc source code: {rustc_src}");
-    if fs::metadata(&rustc_src).is_ok() {
+    if fs::metadata(rustc_src.as_ref()).is_ok() {
         Some(rustc_src)
     } else {
         None
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index fd09dff503f..3d5a934fc92 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -1,6 +1,7 @@
 use std::ops::Deref;
 
 use base_db::{CrateGraph, FileId, ProcMacroPaths};
+use cargo_metadata::Metadata;
 use cfg::{CfgAtom, CfgDiff};
 use expect_test::{expect_file, ExpectFile};
 use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
@@ -9,8 +10,8 @@ use serde::de::DeserializeOwned;
 use triomphe::Arc;
 
 use crate::{
-    CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
-    WorkspaceBuildScripts,
+    workspace::ProjectWorkspaceKind, CargoWorkspace, CfgOverrides, ManifestPath, ProjectJson,
+    ProjectJsonData, ProjectWorkspace, Sysroot, WorkspaceBuildScripts,
 };
 
 fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) {
@@ -21,18 +22,22 @@ fn load_cargo_with_overrides(
     file: &str,
     cfg_overrides: CfgOverrides,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let meta = get_test_json_file(file);
-    let cargo_workspace = CargoWorkspace::new(meta);
-    let project_workspace = ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let meta: Metadata = get_test_json_file(file);
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
+        cfg_overrides,
         sysroot: Err(None),
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
-        cfg_overrides,
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     };
     to_crate_graph(project_workspace)
 }
@@ -41,18 +46,22 @@ fn load_cargo_with_fake_sysroot(
     file_map: &mut FxHashMap<AbsPathBuf, FileId>,
     file: &str,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let meta = get_test_json_file(file);
-    let cargo_workspace = CargoWorkspace::new(meta);
-    let project_workspace = ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let meta: Metadata = get_test_json_file(file);
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         sysroot: Ok(get_fake_sysroot()),
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
@@ -69,8 +78,8 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) {
     let data = get_test_json_file(file);
     let project = rooted_project_json(data);
     let sysroot = Ok(get_fake_sysroot());
-    let project_workspace = ProjectWorkspace::Json {
-        project,
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Json(project),
         sysroot,
         rustc_cfg: Vec::new(),
         toolchain: None,
@@ -143,7 +152,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
     replace_root(&mut root, true);
     let path = Utf8Path::new(&root);
     let base = AbsPath::assert(path);
-    ProjectJson::new(base, data)
+    ProjectJson::new(None, base, data)
 }
 
 fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacroPaths) {
@@ -268,9 +277,10 @@ fn smoke_test_real_sysroot_cargo() {
         return;
     }
     let file_map = &mut FxHashMap::<AbsPathBuf, FileId>::default();
-    let meta = get_test_json_file("hello-world-metadata.json");
-
-    let cargo_workspace = CargoWorkspace::new(meta);
+    let meta: Metadata = get_test_json_file("hello-world-metadata.json");
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
     let sysroot = Ok(Sysroot::discover(
         AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
@@ -278,16 +288,18 @@ fn smoke_test_real_sysroot_cargo() {
     )
     .unwrap());
 
-    let project_workspace = ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         sysroot,
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
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 98c5a02dcdc..85621444e33 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -4,7 +4,7 @@
 
 use std::{collections::VecDeque, fmt, fs, iter, sync};
 
-use anyhow::{format_err, Context};
+use anyhow::Context;
 use base_db::{
     CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileId,
     LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
@@ -14,8 +14,8 @@ use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::Edition;
-use stdx::always;
 use toolchain::Tool;
+use tracing::instrument;
 use triomphe::Arc;
 
 use crate::{
@@ -45,50 +45,39 @@ pub struct PackageRoot {
 }
 
 #[derive(Clone)]
-pub enum ProjectWorkspace {
+pub struct ProjectWorkspace {
+    pub kind: ProjectWorkspaceKind,
+    /// The sysroot loaded for this workspace.
+    pub sysroot: Result<Sysroot, Option<String>>,
+    /// Holds cfg flags for the current target. We get those by running
+    /// `rustc --print cfg`.
+    // FIXME: make this a per-crate map, as, eg, build.rs might have a
+    // different target.
+    pub rustc_cfg: Vec<CfgFlag>,
+    /// The toolchain version used by this workspace.
+    pub toolchain: Option<Version>,
+    /// The target data layout queried for workspace.
+    pub target_layout: TargetLayoutLoadResult,
+    /// A set of cfg overrides for this workspace.
+    pub cfg_overrides: CfgOverrides,
+}
+
+#[derive(Clone)]
+pub enum ProjectWorkspaceKind {
     /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
     Cargo {
         /// The workspace as returned by `cargo metadata`.
         cargo: CargoWorkspace,
         /// The build script results for the workspace.
         build_scripts: WorkspaceBuildScripts,
-        /// The sysroot loaded for this workspace.
-        sysroot: Result<Sysroot, Option<String>>,
         /// The rustc workspace loaded for this workspace. An `Err(None)` means loading has been
         /// disabled or was otherwise not requested.
         rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>,
-        /// Holds cfg flags for the current target. We get those by running
-        /// `rustc --print cfg`.
-        // FIXME: make this a per-crate map, as, eg, build.rs might have a
-        // different target.
-        rustc_cfg: Vec<CfgFlag>,
-        /// A set of cfg overrides for this workspace.
-        cfg_overrides: CfgOverrides,
-        /// The toolchain version used by this workspace.
-        toolchain: Option<Version>,
-        /// The target data layout queried for workspace.
-        target_layout: TargetLayoutLoadResult,
         /// Environment variables set in the `.cargo/config` file.
         cargo_config_extra_env: FxHashMap<String, String>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
-    Json {
-        /// The loaded project json file.
-        project: ProjectJson,
-        /// The sysroot loaded for this workspace.
-        sysroot: Result<Sysroot, Option<String>>,
-        /// Holds cfg flags for the current target. We get those by running
-        /// `rustc --print cfg`.
-        // FIXME: make this a per-crate map, as, eg, build.rs might have a
-        // different target.
-        rustc_cfg: Vec<CfgFlag>,
-        /// The toolchain version used by this workspace.
-        toolchain: Option<Version>,
-        /// The target data layout queried for workspace.
-        target_layout: TargetLayoutLoadResult,
-        /// A set of cfg overrides for this workspace.
-        cfg_overrides: CfgOverrides,
-    },
+    Json(ProjectJson),
     // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
     // That's not the end user experience we should strive for.
     // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
@@ -101,38 +90,23 @@ pub enum ProjectWorkspace {
     /// Backed by basic sysroot crates for basic completion and highlighting.
     DetachedFile {
         /// The file in question.
-        file: AbsPathBuf,
-        /// The sysroot loaded for this workspace.
-        sysroot: Result<Sysroot, Option<String>>,
-        /// Holds cfg flags for the current target. We get those by running
-        /// `rustc --print cfg`.
-        // FIXME: make this a per-crate map, as, eg, build.rs might have a
-        // different target.
-        rustc_cfg: Vec<CfgFlag>,
-        /// The toolchain version used by this workspace.
-        toolchain: Option<Version>,
-        /// The target data layout queried for workspace.
-        target_layout: TargetLayoutLoadResult,
-        /// A set of cfg overrides for the files.
-        cfg_overrides: CfgOverrides,
+        file: ManifestPath,
         /// Is this file a cargo script file?
-        cargo_script: Option<CargoWorkspace>,
+        cargo: Option<(CargoWorkspace, WorkspaceBuildScripts)>,
+        /// Environment variables set in the `.cargo/config` file.
+        cargo_config_extra_env: FxHashMap<String, String>,
     },
 }
 
 impl fmt::Debug for ProjectWorkspace {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Make sure this isn't too verbose.
-        match self {
-            ProjectWorkspace::Cargo {
+        let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self;
+        match kind {
+            ProjectWorkspaceKind::Cargo {
                 cargo,
                 build_scripts: _,
-                sysroot,
                 rustc,
-                rustc_cfg,
-                cfg_overrides,
-                toolchain,
-                target_layout,
                 cargo_config_extra_env,
             } => f
                 .debug_struct("Cargo")
@@ -149,14 +123,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("data_layout", &target_layout)
                 .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .finish(),
-            ProjectWorkspace::Json {
-                project,
-                sysroot,
-                rustc_cfg,
-                toolchain,
-                target_layout: data_layout,
-                cfg_overrides,
-            } => {
+            ProjectWorkspaceKind::Json(project) => {
                 let mut debug_struct = f.debug_struct("Json");
                 debug_struct.field("n_crates", &project.n_crates());
                 if let Ok(sysroot) = sysroot {
@@ -165,18 +132,14 @@ impl fmt::Debug for ProjectWorkspace {
                 debug_struct
                     .field("n_rustc_cfg", &rustc_cfg.len())
                     .field("toolchain", &toolchain)
-                    .field("data_layout", &data_layout)
+                    .field("data_layout", &target_layout)
                     .field("n_cfg_overrides", &cfg_overrides.len());
                 debug_struct.finish()
             }
-            ProjectWorkspace::DetachedFile {
+            ProjectWorkspaceKind::DetachedFile {
                 file,
-                sysroot,
-                rustc_cfg,
-                toolchain,
-                target_layout,
-                cfg_overrides,
-                cargo_script,
+                cargo: cargo_script,
+                cargo_config_extra_env,
             } => f
                 .debug_struct("DetachedFiles")
                 .field("file", &file)
@@ -187,6 +150,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("toolchain", &toolchain)
                 .field("data_layout", &target_layout)
                 .field("n_cfg_overrides", &cfg_overrides.len())
+                .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .finish(),
         }
     }
@@ -230,12 +194,13 @@ impl ProjectWorkspace {
     ) -> anyhow::Result<ProjectWorkspace> {
         let res = match manifest {
             ProjectManifest::ProjectJson(project_json) => {
-                let file = fs::read_to_string(project_json)
+                let file = fs::read_to_string(project_json.as_ref())
                     .with_context(|| format!("Failed to read json file {project_json}"))?;
                 let data = serde_json::from_str(&file)
                     .with_context(|| format!("Failed to deserialize json file {project_json}"))?;
                 let project_location = project_json.parent().to_path_buf();
-                let project_json: ProjectJson = ProjectJson::new(&project_location, data);
+                let project_json: ProjectJson =
+                    ProjectJson::new(Some(project_json.clone()), &project_location, data);
                 ProjectWorkspace::load_inline(
                     project_json,
                     config.target.as_deref(),
@@ -243,6 +208,9 @@ impl ProjectWorkspace {
                     &config.cfg_overrides,
                 )
             }
+            ProjectManifest::CargoScript(rust_file) => {
+                ProjectWorkspace::load_detached_file(rust_file, config)?
+            }
             ProjectManifest::CargoToml(cargo_toml) => {
                 let sysroot = match (&config.sysroot, &config.sysroot_src) {
                     (Some(RustLibSource::Path(path)), None) => {
@@ -299,7 +267,7 @@ impl ProjectWorkspace {
                         progress,
                     ) {
                         Ok(meta) => {
-                            let workspace = CargoWorkspace::new(meta);
+                            let workspace = CargoWorkspace::new(meta, cargo_toml.clone());
                             let buildscripts = WorkspaceBuildScripts::rustc_crates(
                                 &workspace,
                                 cargo_toml.parent(),
@@ -355,22 +323,24 @@ impl ProjectWorkspace {
                         "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
                     )
                 })?;
-                let cargo = CargoWorkspace::new(meta);
+                let cargo = CargoWorkspace::new(meta, cargo_toml.clone());
 
                 let cargo_config_extra_env =
                     cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref);
-                ProjectWorkspace::Cargo {
-                    cargo,
-                    build_scripts: WorkspaceBuildScripts::default(),
+                ProjectWorkspace {
+                    kind: ProjectWorkspaceKind::Cargo {
+                        cargo,
+                        build_scripts: WorkspaceBuildScripts::default(),
+                        rustc,
+                        cargo_config_extra_env,
+                    },
                     sysroot,
-                    rustc,
                     rustc_cfg,
                     cfg_overrides,
                     toolchain,
                     target_layout: data_layout
                         .map(Arc::from)
                         .map_err(|it| Arc::from(it.to_string())),
-                    cargo_config_extra_env,
                 }
             }
         };
@@ -423,8 +393,8 @@ impl ProjectWorkspace {
 
         let rustc_cfg = rustc_cfg::get(target, extra_env, cfg_config);
         let data_layout = target_data_layout::get(data_layout_config, target, extra_env);
-        ProjectWorkspace::Json {
-            project: project_json,
+        ProjectWorkspace {
+            kind: ProjectWorkspaceKind::Json(project_json),
             sysroot,
             rustc_cfg,
             toolchain,
@@ -433,82 +403,76 @@ impl ProjectWorkspace {
         }
     }
 
-    pub fn load_detached_files(
-        detached_files: Vec<AbsPathBuf>,
+    pub fn load_detached_file(
+        detached_file: &ManifestPath,
         config: &CargoConfig,
-    ) -> Vec<anyhow::Result<ProjectWorkspace>> {
-        detached_files
-            .into_iter()
-            .map(|detached_file| {
-                let dir = detached_file
-                    .parent()
-                    .ok_or_else(|| format_err!("detached file has no parent"))?;
-                let sysroot = match &config.sysroot {
-                    Some(RustLibSource::Path(path)) => {
-                        Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
-                            .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
-                    }
-                    Some(RustLibSource::Discover) => {
-                        Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata)
-                            .map_err(|e| {
-                                Some(format!(
-                                    "Failed to find sysroot for {dir}. Is rust-src installed? {e}"
-                                ))
-                            })
-                    }
-                    None => Err(None),
-                };
+    ) -> anyhow::Result<ProjectWorkspace> {
+        let dir = detached_file.parent();
+        let sysroot = match &config.sysroot {
+            Some(RustLibSource::Path(path)) => {
+                Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
+                    .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
+            }
+            Some(RustLibSource::Discover) => Sysroot::discover(
+                dir,
+                &config.extra_env,
+                config.sysroot_query_metadata,
+            )
+            .map_err(|e| {
+                Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}"))
+            }),
+            None => Err(None),
+        };
 
-                let sysroot_ref = sysroot.as_ref().ok();
-                let toolchain = match get_toolchain_version(
-                    dir,
-                    sysroot_ref,
-                    Tool::Rustc,
-                    &config.extra_env,
-                    "rustc ",
-                ) {
-                    Ok(it) => it,
-                    Err(e) => {
-                        tracing::error!("{e}");
-                        None
-                    }
-                };
+        let sysroot_ref = sysroot.as_ref().ok();
+        let toolchain =
+            match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ")
+            {
+                Ok(it) => it,
+                Err(e) => {
+                    tracing::error!("{e}");
+                    None
+                }
+            };
 
-                let rustc_cfg =
-                    rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref));
-                let data_layout = target_data_layout::get(
-                    RustcDataLayoutConfig::Rustc(sysroot_ref),
-                    None,
-                    &config.extra_env,
-                );
+        let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref));
+        let data_layout = target_data_layout::get(
+            RustcDataLayoutConfig::Rustc(sysroot_ref),
+            None,
+            &config.extra_env,
+        );
 
-                let cargo_script = ManifestPath::try_from(detached_file.clone())
-                    .ok()
-                    .and_then(|file| {
-                        CargoWorkspace::fetch_metadata(
-                            &file,
-                            file.parent(),
-                            config,
-                            sysroot_ref,
-                            &|_| (),
-                        )
-                        .ok()
-                    })
-                    .map(CargoWorkspace::new);
+        let cargo_script =
+            CargoWorkspace::fetch_metadata(detached_file, dir, config, sysroot_ref, &|_| ())
+                .ok()
+                .map(|ws| {
+                    (
+                        CargoWorkspace::new(ws, detached_file.clone()),
+                        WorkspaceBuildScripts::default(),
+                    )
+                });
 
-                Ok(ProjectWorkspace::DetachedFile {
-                    file: detached_file,
-                    sysroot,
-                    rustc_cfg,
-                    toolchain,
-                    target_layout: data_layout
-                        .map(Arc::from)
-                        .map_err(|it| Arc::from(it.to_string())),
-                    cfg_overrides: config.cfg_overrides.clone(),
-                    cargo_script,
-                })
-            })
-            .collect()
+        let cargo_config_extra_env =
+            cargo_config_env(detached_file, &config.extra_env, sysroot_ref);
+        Ok(ProjectWorkspace {
+            kind: ProjectWorkspaceKind::DetachedFile {
+                file: detached_file.to_owned(),
+                cargo: cargo_script,
+                cargo_config_extra_env,
+            },
+            sysroot,
+            rustc_cfg,
+            toolchain,
+            target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+            cfg_overrides: config.cfg_overrides.clone(),
+        })
+    }
+
+    pub fn load_detached_files(
+        detached_files: Vec<ManifestPath>,
+        config: &CargoConfig,
+    ) -> Vec<anyhow::Result<ProjectWorkspace>> {
+        detached_files.into_iter().map(|file| Self::load_detached_file(&file, config)).collect()
     }
 
     /// Runs the build scripts for this [`ProjectWorkspace`].
@@ -517,27 +481,22 @@ impl ProjectWorkspace {
         config: &CargoConfig,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<WorkspaceBuildScripts> {
-        match self {
-            ProjectWorkspace::DetachedFile {
-                cargo_script: Some(cargo),
-                toolchain,
-                sysroot,
-                ..
-            }
-            | ProjectWorkspace::Cargo { cargo, toolchain, sysroot, .. } => {
+        match &self.kind {
+            ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
+            | ProjectWorkspaceKind::Cargo { cargo, .. } => {
                 WorkspaceBuildScripts::run_for_workspace(
                     config,
                     cargo,
                     progress,
-                    toolchain,
-                    sysroot.as_ref().ok(),
+                    self.toolchain.as_ref(),
+                    self.sysroot.as_ref().ok(),
                 )
                 .with_context(|| {
                     format!("Failed to run build scripts for {}", cargo.workspace_root())
                 })
             }
-            ProjectWorkspace::DetachedFile { cargo_script: None, .. }
-            | ProjectWorkspace::Json { .. } => Ok(WorkspaceBuildScripts::default()),
+            ProjectWorkspaceKind::DetachedFile { cargo: None, .. }
+            | ProjectWorkspaceKind::Json { .. } => Ok(WorkspaceBuildScripts::default()),
         }
     }
 
@@ -557,8 +516,8 @@ impl ProjectWorkspace {
 
         let cargo_ws: Vec<_> = workspaces
             .iter()
-            .filter_map(|it| match it {
-                ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
+            .filter_map(|it| match &it.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. } => Some(cargo),
                 _ => None,
             })
             .collect();
@@ -572,8 +531,8 @@ impl ProjectWorkspace {
 
         workspaces
             .iter()
-            .map(|it| match it {
-                ProjectWorkspace::Cargo { cargo, .. } => match outputs {
+            .map(|it| match &it.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. } => match outputs {
                     Ok(outputs) => Ok(outputs.next().unwrap()),
                     Err(e) => Err(e.clone()).with_context(|| {
                         format!("Failed to run build scripts for {}", cargo.workspace_root())
@@ -585,39 +544,33 @@ impl ProjectWorkspace {
     }
 
     pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
-        match self {
-            ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,
-            _ => {
-                always!(bs == WorkspaceBuildScripts::default());
+        match &mut self.kind {
+            ProjectWorkspaceKind::Cargo { build_scripts, .. }
+            | ProjectWorkspaceKind::DetachedFile { cargo: Some((_, build_scripts)), .. } => {
+                *build_scripts = bs
             }
+            _ => assert_eq!(bs, WorkspaceBuildScripts::default()),
         }
     }
 
-    pub fn workspace_definition_path(&self) -> &AbsPath {
-        match self {
-            ProjectWorkspace::Cargo { cargo, .. } => cargo.workspace_root(),
-            ProjectWorkspace::Json { project, .. } => project.path(),
-            ProjectWorkspace::DetachedFile { file, .. } => file,
+    pub fn manifest_or_root(&self) -> &AbsPath {
+        match &self.kind {
+            ProjectWorkspaceKind::Cargo { cargo, .. } => cargo.manifest_path(),
+            ProjectWorkspaceKind::Json(project) => project.manifest_or_root(),
+            ProjectWorkspaceKind::DetachedFile { file, .. } => file,
         }
     }
 
     pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
-        match self {
-            ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
-            | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
-            | ProjectWorkspace::DetachedFile { sysroot: Ok(sysroot), .. } => {
-                sysroot.discover_proc_macro_srv()
-            }
-            ProjectWorkspace::DetachedFile { .. } => {
-                Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
-            }
-            ProjectWorkspace::Cargo { cargo, .. } => Err(anyhow::format_err!(
-                "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot",
-                cargo.workspace_root()
+        match &self.sysroot {
+            Ok(sysroot) => sysroot.discover_proc_macro_srv(),
+            Err(None) => Err(anyhow::format_err!(
+                "cannot find proc-macro server, the workspace `{}` is missing a sysroot",
+                self.manifest_or_root()
             )),
-            ProjectWorkspace::Json { project, .. } => Err(anyhow::format_err!(
-                "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot",
-                project.path()
+            Err(Some(e)) => Err(anyhow::format_err!(
+                "cannot find proc-macro server, the workspace `{}` is missing a sysroot: {e}",
+                self.manifest_or_root()
             )),
         }
     }
@@ -626,8 +579,8 @@ impl ProjectWorkspace {
     /// The return type contains the path and whether or not
     /// the root is a member of the current workspace
     pub fn to_roots(&self) -> Vec<PackageRoot> {
-        let mk_sysroot = |sysroot: Result<_, _>| {
-            sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
+        let mk_sysroot = || {
+            self.sysroot.as_ref().into_iter().flat_map(move |sysroot: &Sysroot| {
                 let mut r = match sysroot.mode() {
                     SysrootMode::Workspace(ws) => ws
                         .packages()
@@ -661,15 +614,8 @@ impl ProjectWorkspace {
                 r
             })
         };
-        match self {
-            ProjectWorkspace::Json {
-                project,
-                sysroot,
-                rustc_cfg: _,
-                toolchain: _,
-                target_layout: _,
-                cfg_overrides: _,
-            } => project
+        match &self.kind {
+            ProjectWorkspaceKind::Json(project) => project
                 .crates()
                 .map(|(_, krate)| PackageRoot {
                     is_local: krate.is_workspace_member,
@@ -678,17 +624,12 @@ impl ProjectWorkspace {
                 })
                 .collect::<FxHashSet<_>>()
                 .into_iter()
-                .chain(mk_sysroot(sysroot.as_ref()))
+                .chain(mk_sysroot())
                 .collect::<Vec<_>>(),
-            ProjectWorkspace::Cargo {
+            ProjectWorkspaceKind::Cargo {
                 cargo,
-                sysroot,
                 rustc,
-                rustc_cfg: _,
-                cfg_overrides: _,
                 build_scripts,
-                toolchain: _,
-                target_layout: _,
                 cargo_config_extra_env: _,
             } => {
                 cargo
@@ -729,7 +670,7 @@ impl ProjectWorkspace {
                         }
                         PackageRoot { is_local, include, exclude }
                     })
-                    .chain(mk_sysroot(sysroot.as_ref()))
+                    .chain(mk_sysroot())
                     .chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| {
                         rustc.packages().map(move |krate| PackageRoot {
                             is_local: false,
@@ -739,18 +680,21 @@ impl ProjectWorkspace {
                     }))
                     .collect()
             }
-            ProjectWorkspace::DetachedFile { file, cargo_script, sysroot, .. } => {
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => {
                 iter::once(PackageRoot {
                     is_local: true,
-                    include: vec![file.clone()],
+                    include: vec![file.as_ref().to_owned()],
                     exclude: Vec::new(),
                 })
-                .chain(cargo_script.iter().flat_map(|cargo| {
+                .chain(cargo_script.iter().flat_map(|(cargo, build_scripts)| {
                     cargo.packages().map(|pkg| {
                         let is_local = cargo[pkg].is_local;
                         let pkg_root = cargo[pkg].manifest.parent().to_path_buf();
 
                         let mut include = vec![pkg_root.clone()];
+                        let out_dir =
+                            build_scripts.get_output(pkg).and_then(|it| it.out_dir.clone());
+                        include.extend(out_dir);
 
                         // In case target's path is manually set in Cargo.toml to be
                         // outside the package root, add its parent as an extra include.
@@ -780,28 +724,28 @@ impl ProjectWorkspace {
                         PackageRoot { is_local, include, exclude }
                     })
                 }))
-                .chain(mk_sysroot(sysroot.as_ref()))
+                .chain(mk_sysroot())
                 .collect()
             }
         }
     }
 
     pub fn n_packages(&self) -> usize {
-        match self {
-            ProjectWorkspace::Json { project, sysroot, .. } => {
-                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+        match &self.kind {
+            ProjectWorkspaceKind::Json(project) => {
+                let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
                 sysroot_package_len + project.n_crates()
             }
-            ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
+            ProjectWorkspaceKind::Cargo { cargo, rustc, .. } => {
                 let rustc_package_len =
                     rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(it, _)| it.packages().len());
-                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+                let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
                 cargo.packages().len() + sysroot_package_len + rustc_package_len
             }
-            ProjectWorkspace::DetachedFile { sysroot, cargo_script, .. } => {
-                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+            ProjectWorkspaceKind::DetachedFile { cargo: cargo_script, .. } => {
+                let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
                 sysroot_package_len
-                    + cargo_script.as_ref().map_or(1, |cargo| cargo.packages().len())
+                    + cargo_script.as_ref().map_or(1, |(cargo, _)| cargo.packages().len())
             }
         }
     }
@@ -813,15 +757,9 @@ impl ProjectWorkspace {
     ) -> (CrateGraph, ProcMacroPaths) {
         let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
 
-        let ((mut crate_graph, proc_macros), sysroot) = match self {
-            ProjectWorkspace::Json {
-                project,
-                sysroot,
-                rustc_cfg,
-                toolchain: _,
-                target_layout: _,
-                cfg_overrides,
-            } => (
+        let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
+        let ((mut crate_graph, proc_macros), sysroot) = match kind {
+            ProjectWorkspaceKind::Json(project) => (
                 project_json_to_crate_graph(
                     rustc_cfg.clone(),
                     load,
@@ -832,15 +770,10 @@ impl ProjectWorkspace {
                 ),
                 sysroot,
             ),
-            ProjectWorkspace::Cargo {
+            ProjectWorkspaceKind::Cargo {
                 cargo,
-                sysroot,
                 rustc,
-                rustc_cfg,
-                cfg_overrides,
                 build_scripts,
-                toolchain: _,
-                target_layout: _,
                 cargo_config_extra_env: _,
             } => (
                 cargo_to_crate_graph(
@@ -854,16 +787,8 @@ impl ProjectWorkspace {
                 ),
                 sysroot,
             ),
-            ProjectWorkspace::DetachedFile {
-                file,
-                sysroot,
-                rustc_cfg,
-                toolchain: _,
-                target_layout: _,
-                cfg_overrides,
-                cargo_script,
-            } => (
-                if let Some(cargo) = cargo_script {
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => (
+                if let Some((cargo, build_scripts)) = cargo_script {
                     cargo_to_crate_graph(
                         &mut |path| load(path),
                         None,
@@ -871,7 +796,7 @@ impl ProjectWorkspace {
                         sysroot.as_ref().ok(),
                         rustc_cfg.clone(),
                         cfg_overrides,
-                        &WorkspaceBuildScripts::default(),
+                        build_scripts,
                     )
                 } else {
                     detached_file_to_crate_graph(
@@ -897,93 +822,60 @@ impl ProjectWorkspace {
     }
 
     pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
-        match (self, other) {
+        let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides, .. } = self;
+        let Self {
+            kind: o_kind,
+            sysroot: o_sysroot,
+            rustc_cfg: o_rustc_cfg,
+            toolchain: o_toolchain,
+            target_layout: o_target_layout,
+            cfg_overrides: o_cfg_overrides,
+            ..
+        } = other;
+        (match (kind, o_kind) {
             (
-                Self::Cargo {
+                ProjectWorkspaceKind::Cargo {
                     cargo,
-                    sysroot,
                     rustc,
-                    rustc_cfg,
-                    cfg_overrides,
-                    toolchain,
                     cargo_config_extra_env,
                     build_scripts: _,
-                    target_layout: _,
                 },
-                Self::Cargo {
+                ProjectWorkspaceKind::Cargo {
                     cargo: o_cargo,
-                    sysroot: o_sysroot,
                     rustc: o_rustc,
-                    rustc_cfg: o_rustc_cfg,
-                    cfg_overrides: o_cfg_overrides,
-                    toolchain: o_toolchain,
                     cargo_config_extra_env: o_cargo_config_extra_env,
                     build_scripts: _,
-                    target_layout: _,
                 },
             ) => {
                 cargo == o_cargo
                     && rustc == o_rustc
-                    && rustc_cfg == o_rustc_cfg
-                    && cfg_overrides == o_cfg_overrides
-                    && toolchain == o_toolchain
-                    && sysroot == o_sysroot
                     && cargo_config_extra_env == o_cargo_config_extra_env
             }
-            (
-                Self::Json {
-                    project,
-                    sysroot,
-                    rustc_cfg,
-                    toolchain,
-                    target_layout: _,
-                    cfg_overrides,
-                },
-                Self::Json {
-                    project: o_project,
-                    sysroot: o_sysroot,
-                    rustc_cfg: o_rustc_cfg,
-                    toolchain: o_toolchain,
-                    target_layout: _,
-                    cfg_overrides: o_cfg_overrides,
-                },
-            ) => {
+            (ProjectWorkspaceKind::Json(project), ProjectWorkspaceKind::Json(o_project)) => {
                 project == o_project
-                    && rustc_cfg == o_rustc_cfg
-                    && sysroot == o_sysroot
-                    && toolchain == o_toolchain
-                    && cfg_overrides == o_cfg_overrides
             }
             (
-                Self::DetachedFile {
+                ProjectWorkspaceKind::DetachedFile {
                     file,
-                    sysroot,
-                    rustc_cfg,
-                    cargo_script,
-                    toolchain,
-                    target_layout,
-                    cfg_overrides,
+                    cargo: Some((cargo_script, _)),
+                    cargo_config_extra_env,
                 },
-                Self::DetachedFile {
+                ProjectWorkspaceKind::DetachedFile {
                     file: o_file,
-                    sysroot: o_sysroot,
-                    rustc_cfg: o_rustc_cfg,
-                    cargo_script: o_cargo_script,
-                    toolchain: o_toolchain,
-                    target_layout: o_target_layout,
-                    cfg_overrides: o_cfg_overrides,
+                    cargo: Some((o_cargo_script, _)),
+                    cargo_config_extra_env: o_cargo_config_extra_env,
                 },
             ) => {
                 file == o_file
-                    && sysroot == o_sysroot
-                    && rustc_cfg == o_rustc_cfg
-                    && toolchain == o_toolchain
-                    && target_layout == o_target_layout
-                    && cfg_overrides == o_cfg_overrides
                     && cargo_script == o_cargo_script
+                    && cargo_config_extra_env == o_cargo_config_extra_env
             }
-            _ => false,
-        }
+            _ => return false,
+        }) && sysroot == o_sysroot
+            && rustc_cfg == o_rustc_cfg
+            && toolchain == o_toolchain
+            && target_layout == o_target_layout
+            && cfg_overrides == o_cfg_overrides
     }
 
     /// Returns `true` if the project workspace is [`Json`].
@@ -991,10 +883,11 @@ impl ProjectWorkspace {
     /// [`Json`]: ProjectWorkspace::Json
     #[must_use]
     pub fn is_json(&self) -> bool {
-        matches!(self, Self::Json { .. })
+        matches!(self.kind, ProjectWorkspaceKind::Json { .. })
     }
 }
 
+#[instrument(skip_all)]
 fn project_json_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     load: FileLoader<'_>,
@@ -1294,11 +1187,11 @@ fn cargo_to_crate_graph(
 fn detached_file_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     load: FileLoader<'_>,
-    detached_file: &AbsPathBuf,
+    detached_file: &ManifestPath,
     sysroot: Option<&Sysroot>,
     override_cfg: &CfgOverrides,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let _p = tracing::span!(tracing::Level::INFO, "detached_files_to_crate_graph").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered();
     let mut crate_graph = CrateGraph::default();
     let (public_deps, _libproc_macro) = match sysroot {
         Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
@@ -1520,7 +1413,7 @@ impl SysrootPublicDeps {
     /// Makes `from` depend on the public sysroot crates.
     fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) {
         for (name, krate, prelude) in &self.deps {
-            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
+            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude, true);
         }
     }
 }
@@ -1573,7 +1466,7 @@ fn sysroot_to_crate_graph(
                         | LangCrateOrigin::Std => pub_deps.push((
                             CrateName::normalize_dashes(&lang_crate.to_string()),
                             cid,
-                            !matches!(lang_crate, LangCrateOrigin::Test),
+                            !matches!(lang_crate, LangCrateOrigin::Test | LangCrateOrigin::Alloc),
                         )),
                         LangCrateOrigin::ProcMacro => libproc_macro = Some(cid),
                         LangCrateOrigin::Other => (),
@@ -1674,12 +1567,20 @@ fn add_dep_with_prelude(
     name: CrateName,
     to: CrateId,
     prelude: bool,
+    sysroot: bool,
 ) {
-    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
+    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, sysroot))
 }
 
 fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) {
-    add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude);
+    add_dep_with_prelude(
+        crate_graph,
+        from,
+        CrateName::new("proc_macro").unwrap(),
+        to,
+        prelude,
+        true,
+    );
 }
 
 fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
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 c2a2d6ed911..3401d7f7e47 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
@@ -50,6 +50,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -111,6 +112,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -118,6 +120,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -179,6 +182,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -186,6 +190,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -247,6 +252,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -254,6 +260,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
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 c2a2d6ed911..3401d7f7e47 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
@@ -50,6 +50,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -111,6 +112,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -118,6 +120,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -179,6 +182,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -186,6 +190,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -247,6 +252,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -254,6 +260,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
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 c291ffcca7b..491568d4b75 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
@@ -49,6 +49,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -109,6 +110,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -116,6 +118,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -176,6 +179,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -183,6 +187,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -243,6 +248,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -250,6 +256,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
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 80c91365894..c123df80a6a 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
@@ -30,6 +30,7 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Lang(
@@ -158,6 +159,7 @@
                     "std",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(1),
@@ -165,6 +167,7 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Lang(
@@ -233,6 +236,7 @@
                     "alloc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(3),
@@ -240,6 +244,7 @@
                     "panic_unwind",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(2),
@@ -247,6 +252,7 @@
                     "panic_abort",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(1),
@@ -254,6 +260,7 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(5),
@@ -261,6 +268,7 @@
                     "profiler_builtins",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(9),
@@ -268,6 +276,7 @@
                     "unwind",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(7),
@@ -275,6 +284,7 @@
                     "std_detect",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(8),
@@ -282,6 +292,7 @@
                     "test",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Lang(
@@ -409,13 +420,15 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(0),
                 name: CrateName(
                     "alloc",
                 ),
-                prelude: true,
+                prelude: false,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(6),
@@ -423,6 +436,7 @@
                     "std",
                 ),
                 prelude: true,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(8),
@@ -430,6 +444,7 @@
                     "test",
                 ),
                 prelude: false,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -437,6 +452,7 @@
                     "proc_macro",
                 ),
                 prelude: false,
+                sysroot: true,
             },
         ],
         origin: Local {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index cd3349899e9..34b3e493140 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "rust-analyzer"
 version = "0.0.0"
-homepage = "https://github.com/rust-analyzer/rust-analyzer"
+homepage = "https://rust-analyzer.github.io/"
+repository = "https://github.com/rust-analyzer/rust-analyzer"
 description = "A language server for the Rust programming language"
 documentation = "https://rust-analyzer.github.io/manual.html"
 autobins = false
@@ -69,7 +70,7 @@ vfs.workspace = true
 paths.workspace = true
 
 [target.'cfg(windows)'.dependencies]
-winapi = "0.3.9"
+windows-sys = { version = "0.52", features = ["Win32_System_Threading"] }
 
 [target.'cfg(not(target_env = "msvc"))'.dependencies]
 jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = true }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/build.rs b/src/tools/rust-analyzer/crates/rust-analyzer/build.rs
index 15935e2da8d..72b741de00e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/build.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/build.rs
@@ -5,6 +5,7 @@ use std::{env, path::PathBuf, process::Command};
 fn main() {
     set_rerun();
     set_commit_info();
+    println!("cargo::rustc-check-cfg=cfg(rust_analyzer)");
     if option_env!("CFG_RELEASE").is_none() {
         println!("cargo:rustc-env=POKE_RA_DEVS=1");
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index 78920f3abac..9daae914d79 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -259,9 +259,15 @@ fn run_server() -> anyhow::Result<()> {
         config.rediscover_workspaces();
     }
 
-    rust_analyzer::main_loop(config, connection)?;
+    // If the io_threads have an error, there's usually an error on the main
+    // loop too because the channels are closed. Ensure we report both errors.
+    match (rust_analyzer::main_loop(config, connection), io_threads.join()) {
+        (Err(loop_e), Err(join_e)) => anyhow::bail!("{loop_e}\n{join_e}"),
+        (Ok(_), Err(join_e)) => anyhow::bail!("{join_e}"),
+        (Err(loop_e), Ok(_)) => anyhow::bail!("{loop_e}"),
+        (Ok(_), Ok(_)) => {}
+    }
 
-    io_threads.join()?;
     tracing::info!("server did shut down");
     Ok(())
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
index 6a5f7b02624..693a35b91e6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -211,7 +211,7 @@ mod tests {
     use super::*;
 
     use ide::Edition;
-    use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+    use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
     use syntax::{
         ast::{self, AstNode},
         SmolStr,
@@ -221,7 +221,12 @@ mod tests {
         let cfg_expr = {
             let source_file = ast::SourceFile::parse(cfg, Edition::CURRENT).ok().unwrap();
             let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-            let tt = syntax_node_to_token_tree(tt.syntax(), &DummyTestSpanMap, DUMMY);
+            let tt = syntax_node_to_token_tree(
+                tt.syntax(),
+                &DummyTestSpanMap,
+                DUMMY,
+                DocCommentDesugarMode::Mbe,
+            );
             CfgExpr::parse(&tt)
         };
 
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 a1eea8839eb..5208aa9bf08 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
@@ -986,6 +986,7 @@ impl flags::AnalysisStats {
                     prefer_no_std: false,
                     prefer_prelude: true,
                     style_lints: false,
+                    term_search_fuel: 400,
                 },
                 ide::AssistResolveStrategy::All,
                 file_id,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index 79d6226debf..d5eac49ad3a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -13,6 +13,17 @@ use crate::cli::flags;
 
 impl flags::Diagnostics {
     pub fn run(self) -> anyhow::Result<()> {
+        const STACK_SIZE: usize = 1024 * 1024 * 8;
+
+        let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive)
+            .name("BIG_STACK_THREAD".into())
+            .stack_size(STACK_SIZE)
+            .spawn(|| self.run_())
+            .unwrap();
+
+        handle.join()
+    }
+    fn run_(self) -> anyhow::Result<()> {
         let cargo_config =
             CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() };
         let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
index ead4d706e65..ed048aa635b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
@@ -6,7 +6,7 @@ use crate::cli::{flags, read_stdin};
 
 impl flags::Parse {
     pub fn run(self) -> anyhow::Result<()> {
-        let _p = tracing::span!(tracing::Level::INFO, "parsing").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "flags::Parse::run").entered();
         let text = read_stdin()?;
         let file = SourceFile::parse(&text, Edition::CURRENT).tree();
         if !self.no_dump {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
index 6964977840a..8b143daf2ae 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
@@ -96,7 +96,7 @@ impl<'a> ProgressReport<'a> {
     }
 
     fn set_value(&mut self, value: f32) {
-        self.curr = f32::max(0.0, f32::min(1.0, value));
+        self.curr = value.clamp(0.0, 1.0);
     }
 
     fn clear(&mut self) {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index 2f9394d0ee1..85f964b1dd9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -10,7 +10,10 @@ use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use itertools::Either;
 use profile::StopWatch;
 use project_model::target_data_layout::RustcDataLayoutConfig;
-use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
+use project_model::{
+    target_data_layout, CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind,
+    RustLibSource, Sysroot,
+};
 
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
 use rustc_hash::FxHashMap;
@@ -75,14 +78,17 @@ impl Tester {
             &cargo_config.extra_env,
         );
 
-        let workspace = ProjectWorkspace::DetachedFile {
-            file: tmp_file,
+        let workspace = ProjectWorkspace {
+            kind: ProjectWorkspaceKind::DetachedFile {
+                file: ManifestPath::try_from(tmp_file).unwrap(),
+                cargo: None,
+                cargo_config_extra_env: Default::default(),
+            },
             sysroot,
             rustc_cfg: vec![],
             toolchain: None,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: Default::default(),
-            cargo_script: None,
         };
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: false,
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 e956791d9df..6c332ae1cb2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -230,7 +230,7 @@ config_data! {
         /// If `$saved_file` is part of the command, rust-analyzer will pass
         /// the absolute path of the saved file to the provided command. This is
         /// intended to be used with non-Cargo build systems.
-        /// Note that `$saved_file` is experimental and may be removed in the futureg.
+        /// Note that `$saved_file` is experimental and may be removed in the future.
         ///
         /// An example command would be:
         ///
@@ -315,8 +315,10 @@ config_data! {
         /// How to render the size information in a memory layout hover.
         hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Both),
 
-        /// How many fields of a struct to display when hovering a struct.
-        hover_show_structFields: Option<usize> = None,
+        /// How many variants of an enum to display when hovering on. Show none if empty.
+        hover_show_enumVariants: Option<usize> = Some(5),
+        /// How many fields of a struct, variant or union to display when hovering on. Show none if empty.
+        hover_show_fields: Option<usize> = Some(5),
         /// How many associated items of a trait to display when hovering a trait.
         hover_show_traitAssocItems: Option<usize> = None,
 
@@ -356,7 +358,8 @@ config_data! {
         /// of projects.
         ///
         /// Elements must be paths pointing to `Cargo.toml`,
-        /// `rust-project.json`, or JSON objects in `rust-project.json` format.
+        /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON
+        /// objects in `rust-project.json` format.
         linkedProjects: Vec<ManifestOrProjectJson> = vec![],
 
         /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
@@ -451,6 +454,9 @@ config_data! {
     /// Local configurations can be overridden for every crate by placing a `rust-analyzer.toml` on crate root.
     /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle.
     local: struct LocalDefaultConfigData <- LocalConfigInput ->  {
+        /// Term search fuel in "units of work" for assists (Defaults to 400).
+        assist_termSearch_fuel: usize = 400,
+
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = true,
@@ -512,6 +518,8 @@ config_data! {
         }"#).unwrap(),
         /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
         completion_termSearch_enable: bool = false,
+        /// Term search fuel in "units of work" for autocompletion (Defaults to 200).
+        completion_termSearch_fuel: usize = 200,
 
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = true,
@@ -1012,6 +1020,7 @@ impl Config {
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
             assist_emit_must_use: self.assist_emitMustUse().to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
+            term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
         }
     }
 
@@ -1045,6 +1054,7 @@ impl Config {
             snippets: self.snippets.clone().to_vec(),
             limit: self.completion_limit(source_root).to_owned(),
             enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
+            term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
         }
     }
@@ -1064,6 +1074,7 @@ impl Config {
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
             style_lints: self.diagnostics_styleLints_enable().to_owned(),
+            term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
         }
     }
     pub fn expand_proc_attr_macros(&self) -> bool {
@@ -1125,7 +1136,8 @@ impl Config {
             },
             keywords: self.hover_documentation_keywords_enable().to_owned(),
             max_trait_assoc_items_count: self.hover_show_traitAssocItems().to_owned(),
-            max_struct_field_count: self.hover_show_structFields().to_owned(),
+            max_fields_count: self.hover_show_fields().to_owned(),
+            max_enum_variants_count: self.hover_show_enumVariants().to_owned(),
         }
     }
 
@@ -1301,12 +1313,9 @@ impl Config {
                     self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect();
                 self.discovered_projects
                     .iter()
-                    .filter(
-                        |(ProjectManifest::ProjectJson(path)
-                         | ProjectManifest::CargoToml(path))| {
-                            !exclude_dirs.iter().any(|p| path.starts_with(p))
-                        },
-                    )
+                    .filter(|project| {
+                        !exclude_dirs.iter().any(|p| project.manifest_path().starts_with(p))
+                    })
                     .cloned()
                     .map(LinkedProject::from)
                     .collect()
@@ -1322,7 +1331,7 @@ impl Config {
                             .map(Into::into)
                     }
                     ManifestOrProjectJson::ProjectJson(it) => {
-                        Some(ProjectJson::new(&self.root_path, it.clone()).into())
+                        Some(ProjectJson::new(None, &self.root_path, it.clone()).into())
                     }
                 })
                 .collect(),
@@ -1775,7 +1784,7 @@ impl Config {
 
     pub fn lens(&self) -> LensConfig {
         LensConfig {
-            run: *self.lens_run_enable(),
+            run: *self.lens_enable() && *self.lens_run_enable(),
             debug: *self.lens_enable() && *self.lens_debug_enable(),
             interpret: *self.lens_enable() && *self.lens_run_enable() && *self.interpret_tests(),
             implementations: *self.lens_enable() && *self.lens_implementations_enable(),
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 7adaef4ff6e..cf3b8d331de 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -95,45 +95,8 @@ impl RequestDispatcher<'_> {
         self
     }
 
-    /// Dispatches a non-latency-sensitive request onto the thread pool
-    /// without retrying it if it panics.
-    pub(crate) fn on_no_retry<R>(
-        &mut self,
-        f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
-    ) -> &mut Self
-    where
-        R: lsp_types::request::Request + 'static,
-        R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
-        R::Result: Serialize,
-    {
-        let (req, params, panic_context) = match self.parse::<R>() {
-            Some(it) => it,
-            None => return self,
-        };
-
-        self.global_state.task_pool.handle.spawn(ThreadIntent::Worker, {
-            let world = self.global_state.snapshot();
-            move || {
-                let result = panic::catch_unwind(move || {
-                    let _pctx = stdx::panic_context::enter(panic_context);
-                    f(world, params)
-                });
-                match thread_result_to_response::<R>(req.id.clone(), result) {
-                    Ok(response) => Task::Response(response),
-                    Err(_) => Task::Response(lsp_server::Response::new_err(
-                        req.id,
-                        lsp_server::ErrorCode::ContentModified as i32,
-                        "content modified".to_owned(),
-                    )),
-                }
-            }
-        });
-
-        self
-    }
-
     /// Dispatches a non-latency-sensitive request onto the thread pool.
-    pub(crate) fn on<R>(
+    pub(crate) fn on<const ALLOW_RETRYING: bool, R>(
         &mut self,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
     ) -> &mut Self
@@ -142,11 +105,11 @@ impl RequestDispatcher<'_> {
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<true, R>(ThreadIntent::Worker, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
     }
 
     /// Dispatches a latency-sensitive request onto the thread pool.
-    pub(crate) fn on_latency_sensitive<R>(
+    pub(crate) fn on_latency_sensitive<const ALLOW_RETRYING: bool, R>(
         &mut self,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
     ) -> &mut Self
@@ -155,7 +118,7 @@ impl RequestDispatcher<'_> {
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<true, R>(ThreadIntent::LatencySensitive, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::LatencySensitive, f)
     }
 
     /// Formatting requests should never block on waiting a for task thread to open up, editors will wait
@@ -170,7 +133,7 @@ impl RequestDispatcher<'_> {
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<false, R>(ThreadIntent::LatencySensitive, f)
+        self.on_with_thread_intent::<false, false, R>(ThreadIntent::LatencySensitive, f)
     }
 
     pub(crate) fn finish(&mut self) {
@@ -185,7 +148,7 @@ impl RequestDispatcher<'_> {
         }
     }
 
-    fn on_with_thread_intent<const MAIN_POOL: bool, R>(
+    fn on_with_thread_intent<const MAIN_POOL: bool, const ALLOW_RETRYING: bool, R>(
         &mut self,
         intent: ThreadIntent,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
@@ -215,7 +178,12 @@ impl RequestDispatcher<'_> {
             });
             match thread_result_to_response::<R>(req.id.clone(), result) {
                 Ok(response) => Task::Response(response),
-                Err(_) => Task::Retry(req),
+                Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req),
+                Err(_cancelled) => Task::Response(lsp_server::Response::new_err(
+                    req.id,
+                    lsp_server::ErrorCode::ContentModified as i32,
+                    "content modified".to_owned(),
+                )),
             }
         });
 
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 e9bca19af64..f64e66183d1 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
@@ -3,7 +3,7 @@
 //!
 //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 
-use std::{collections::hash_map::Entry, time::Instant};
+use std::time::Instant;
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
@@ -18,10 +18,14 @@ use parking_lot::{
     RwLockWriteGuard,
 };
 use proc_macro_api::ProcMacroServer;
-use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
+use project_model::{
+    CargoWorkspace, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, Target,
+    WorkspaceBuildScripts,
+};
 use rustc_hash::{FxHashMap, FxHashSet};
+use tracing::{span, Level};
 use triomphe::Arc;
-use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
+use vfs::{AnchoredPathBuf, Vfs};
 
 use crate::{
     config::{Config, ConfigError},
@@ -125,7 +129,7 @@ pub(crate) struct GlobalState {
     /// to invalidate any salsa caches.
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
     pub(crate) crate_graph_file_dependencies: FxHashSet<vfs::VfsPath>,
-    pub(crate) detached_files: FxHashSet<vfs::AbsPathBuf>,
+    pub(crate) detached_files: FxHashSet<ManifestPath>,
 
     // op queues
     pub(crate) fetch_workspaces_queue:
@@ -249,9 +253,7 @@ impl GlobalState {
     }
 
     pub(crate) fn process_changes(&mut self) -> bool {
-        let _p = tracing::span!(tracing::Level::INFO, "GlobalState::process_changes").entered();
-
-        let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default();
+        let _p = span!(Level::INFO, "GlobalState::process_changes").entered();
         let (change, modified_rust_files, workspace_structure_change) = {
             let mut change = ChangeWithProcMacros::new();
             let mut guard = self.vfs.write();
@@ -263,58 +265,16 @@ impl GlobalState {
             // 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.
-            for changed_file in changed_files {
-                use vfs::Change::*;
-                match file_changes.entry(changed_file.file_id) {
-                    Entry::Occupied(mut o) => {
-                        let (just_created, change) = o.get_mut();
-                        match (&mut change.change, just_created, changed_file.change) {
-                            // latter `Delete` wins
-                            (change, _, Delete) => *change = Delete,
-                            // merge `Create` with `Create` or `Modify`
-                            (Create(prev), _, Create(new) | Modify(new)) => *prev = new,
-                            // collapse identical `Modify`es
-                            (Modify(prev), _, Modify(new)) => *prev = new,
-                            // equivalent to `Modify`
-                            (change @ Delete, just_created, Create(new)) => {
-                                *change = Modify(new);
-                                *just_created = true;
-                            }
-                            // shouldn't occur, but collapse into `Create`
-                            (change @ Delete, just_created, Modify(new)) => {
-                                *change = Create(new);
-                                *just_created = true;
-                            }
-                            // shouldn't occur, but keep the Create
-                            (prev @ Modify(_), _, new @ Create(_)) => *prev = new,
-                        }
-                    }
-                    Entry::Vacant(v) => {
-                        _ = v.insert((matches!(&changed_file.change, Create(_)), changed_file))
-                    }
-                }
-            }
-
-            let changed_files: Vec<_> = file_changes
-                .into_iter()
-                .filter(|(_, (just_created, change))| {
-                    !(*just_created && matches!(change.change, vfs::Change::Delete))
-                })
-                .map(|(file_id, (_, change))| vfs::ChangedFile { file_id, ..change })
-                .collect();
 
             let mut workspace_structure_change = None;
             // A file was added or deleted
             let mut has_structure_changes = false;
             let mut bytes = vec![];
             let mut modified_rust_files = vec![];
-            for file in changed_files {
+            for file in changed_files.into_values() {
                 let vfs_path = vfs.file_path(file.file_id);
                 if let Some(path) = vfs_path.as_path() {
-                    has_structure_changes = file.is_created_or_deleted();
+                    has_structure_changes |= file.is_created_or_deleted();
 
                     if file.is_modified() && path.extension() == Some("rs") {
                         modified_rust_files.push(file.file_id);
@@ -334,16 +294,17 @@ impl GlobalState {
                     self.diagnostics.clear_native_for(file.file_id);
                 }
 
-                let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
-                    String::from_utf8(v).ok().map(|text| {
-                        // FIXME: Consider doing normalization in the `vfs` instead? That allows
-                        // getting rid of some locking
-                        let (text, line_endings) = LineEndings::normalize(text);
-                        (text, line_endings)
-                    })
-                } else {
-                    None
-                };
+                let text =
+                    if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
+                        String::from_utf8(v).ok().map(|text| {
+                            // FIXME: Consider doing normalization in the `vfs` instead? That allows
+                            // getting rid of some locking
+                            let (text, line_endings) = LineEndings::normalize(text);
+                            (text, line_endings)
+                        })
+                    } else {
+                        None
+                    };
                 // 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));
@@ -363,6 +324,7 @@ impl GlobalState {
             (change, modified_rust_files, workspace_structure_change)
         };
 
+        let _p = span!(Level::INFO, "GlobalState::process_changes/apply_change").entered();
         self.analysis_host.apply_change(change);
 
         {
@@ -376,6 +338,9 @@ impl GlobalState {
             // but something's going wrong with the source root business when we add a new local
             // crate see https://github.com/rust-lang/rust-analyzer/issues/13029
             if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
+                let _p = span!(Level::INFO, "GlobalState::process_changes/ws_structure_change")
+                    .entered();
+
                 self.fetch_workspaces_queue.request_op(
                     format!("workspace vfs file change: {path}"),
                     force_crate_graph_reload,
@@ -492,6 +457,10 @@ impl GlobalStateSnapshot {
         Ok(res)
     }
 
+    pub(crate) fn file_version(&self, file_id: FileId) -> Option<i32> {
+        Some(self.mem_docs.get(self.vfs_read().file_path(file_id))?.version)
+    }
+
     pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
         let path = from_proto::vfs_path(url).ok()?;
         Some(self.mem_docs.get(&path)?.version)
@@ -516,12 +485,13 @@ impl GlobalStateSnapshot {
         let file_id = self.analysis.crate_root(crate_id).ok()?;
         let path = self.vfs_read().file_path(file_id).clone();
         let path = path.as_path()?;
-        self.workspaces.iter().find_map(|ws| match ws {
-            ProjectWorkspace::Cargo { cargo, .. } => {
+        self.workspaces.iter().find_map(|ws| match &ws.kind {
+            ProjectWorkspaceKind::Cargo { cargo, .. }
+            | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
                 cargo.target_by_root(path).map(|it| (cargo, it))
             }
-            ProjectWorkspace::Json { .. } => None,
-            ProjectWorkspace::DetachedFile { .. } => None,
+            ProjectWorkspaceKind::Json { .. } => None,
+            ProjectWorkspaceKind::DetachedFile { .. } => None,
         })
     }
 
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 4b8c3d06ce4..9d30063ccc8 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
@@ -289,17 +289,19 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
 
             // Find all workspaces that have at least one target containing the saved file
             let workspace_ids = world.workspaces.iter().enumerate().filter_map(|(idx, ws)| {
-                let package = match ws {
-                    project_model::ProjectWorkspace::Cargo { cargo, .. } => {
-                        cargo.packages().find_map(|pkg| {
-                            let has_target_with_root = cargo[pkg]
-                                .targets
-                                .iter()
-                                .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
-                            has_target_with_root.then(|| cargo[pkg].name.clone())
-                        })
-                    }
-                    project_model::ProjectWorkspace::Json { project, .. } => {
+                let package = match &ws.kind {
+                    project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
+                    | project_model::ProjectWorkspaceKind::DetachedFile {
+                        cargo: Some((cargo, _)),
+                        ..
+                    } => cargo.packages().find_map(|pkg| {
+                        let has_target_with_root = cargo[pkg]
+                            .targets
+                            .iter()
+                            .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
+                        has_target_with_root.then(|| cargo[pkg].name.clone())
+                    }),
+                    project_model::ProjectWorkspaceKind::Json(project) => {
                         if !project.crates().any(|(_, krate)| {
                             crate_root_paths.contains(&krate.root_module.as_path())
                         }) {
@@ -307,8 +309,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                         }
                         None
                     }
-                    // FIXME
-                    project_model::ProjectWorkspace::DetachedFile { .. } => return None,
+                    project_model::ProjectWorkspaceKind::DetachedFile { .. } => return None,
                 };
                 Some((idx, package))
             });
@@ -348,7 +349,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
 }
 
 pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_stop_flycheck").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "handle_cancel_flycheck").entered();
     state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
     Ok(())
 }
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 cf97d7d9d23..5ee0456c15d 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
@@ -27,7 +27,7 @@ use lsp_types::{
     SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
 use paths::Utf8PathBuf;
-use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
+use project_model::{ManifestPath, ProjectWorkspaceKind, TargetKind};
 use serde_json::json;
 use stdx::{format_to, never};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
@@ -99,10 +99,7 @@ pub(crate) fn handle_analyzer_status(
         format_to!(
             buf,
             "Workspace root folders: {:?}",
-            snap.workspaces
-                .iter()
-                .map(|ws| ws.workspace_definition_path())
-                .collect::<Vec<&AbsPath>>()
+            snap.workspaces.iter().map(|ws| ws.manifest_or_root()).collect::<Vec<&AbsPath>>()
         );
     }
     buf.push_str("\nAnalysis:\n");
@@ -228,7 +225,7 @@ pub(crate) fn handle_run_test(
     };
     let mut handles = vec![];
     for ws in &*state.workspaces {
-        if let ProjectWorkspace::Cargo { cargo, .. } = ws {
+        if let ProjectWorkspaceKind::Cargo { cargo, .. } = &ws.kind {
             let handle = flycheck::CargoTestHandle::new(
                 test_path,
                 state.config.cargo_test_options(),
@@ -769,8 +766,11 @@ pub(crate) fn handle_parent_module(
             let links: Vec<LocationLink> = snap
                 .workspaces
                 .iter()
-                .filter_map(|ws| match ws {
-                    ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
+                .filter_map(|ws| match &ws.kind {
+                    ProjectWorkspaceKind::Cargo { cargo, .. }
+                    | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
+                        cargo.parent_manifests(&manifest_path)
+                    }
                     _ => None,
                 })
                 .flatten()
@@ -855,10 +855,14 @@ pub(crate) fn handle_runnables(
     let config = snap.config.runnables();
     match cargo_spec {
         Some(spec) => {
-            let all_targets = !snap.analysis.is_crate_no_std(spec.crate_id)?;
-            for cmd in ["check", "test"] {
+            let is_crate_no_std = snap.analysis.is_crate_no_std(spec.crate_id)?;
+            for cmd in ["check", "run", "test"] {
+                if cmd == "run" && spec.target_kind != TargetKind::Bin {
+                    continue;
+                }
                 let mut cargo_args =
                     vec![cmd.to_owned(), "--package".to_owned(), spec.package.clone()];
+                let all_targets = cmd != "run" && !is_crate_no_std;
                 if all_targets {
                     cargo_args.push("--all-targets".to_owned());
                 }
@@ -930,16 +934,18 @@ pub(crate) fn handle_related_tests(
 
 pub(crate) fn handle_completion(
     snap: GlobalStateSnapshot,
-    params: lsp_types::CompletionParams,
+    lsp_types::CompletionParams { text_document_position, context,.. }: lsp_types::CompletionParams,
 ) -> anyhow::Result<Option<lsp_types::CompletionResponse>> {
     let _p = tracing::span!(tracing::Level::INFO, "handle_completion").entered();
-    let text_document_position = params.text_document_position.clone();
-    let position = from_proto::file_position(&snap, params.text_document_position)?;
+    let mut position = from_proto::file_position(&snap, text_document_position.clone())?;
+    let line_index = snap.file_line_index(position.file_id)?;
     let completion_trigger_character =
-        params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
+        context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 
     let source_root = snap.analysis.source_root(position.file_id)?;
     let completion_config = &snap.config.completion(Some(source_root));
+    // FIXME: We should fix up the position when retrying the cancelled request instead
+    position.offset = position.offset.min(line_index.index.len());
     let items = match snap.analysis.completions(
         completion_config,
         position,
@@ -948,10 +954,14 @@ pub(crate) fn handle_completion(
         None => return Ok(None),
         Some(items) => items,
     };
-    let line_index = snap.file_line_index(position.file_id)?;
 
-    let items =
-        to_proto::completion_items(&snap.config, &line_index, text_document_position, items);
+    let items = to_proto::completion_items(
+        &snap.config,
+        &line_index,
+        snap.file_version(position.file_id),
+        text_document_position,
+        items,
+    );
 
     let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
     Ok(Some(completion_list.into()))
@@ -970,16 +980,16 @@ pub(crate) fn handle_completion_resolve(
         .into());
     }
 
-    let data = match original_completion.data.take() {
-        Some(it) => it,
-        None => return Ok(original_completion),
-    };
+    let Some(data) = original_completion.data.take() else { return Ok(original_completion) };
 
     let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
 
     let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
-    let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
+    // FIXME: We should fix up the position when retrying the cancelled request instead
+    let Ok(offset) = from_proto::offset(&line_index, resolve_data.position.position) else {
+        return Ok(original_completion);
+    };
     let source_root = snap.analysis.source_root(file_id)?;
 
     let additional_edits = snap
@@ -1236,8 +1246,11 @@ pub(crate) fn handle_code_action(
         frange,
     )?;
     for (index, assist) in assists.into_iter().enumerate() {
-        let resolve_data =
-            if code_action_resolve_cap { Some((index, params.clone())) } else { None };
+        let resolve_data = if code_action_resolve_cap {
+            Some((index, params.clone(), snap.file_version(file_id)))
+        } else {
+            None
+        };
         let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
 
         // Check if the client supports the necessary `ResourceOperation`s.
@@ -1276,12 +1289,14 @@ pub(crate) fn handle_code_action_resolve(
     mut code_action: lsp_ext::CodeAction,
 ) -> anyhow::Result<lsp_ext::CodeAction> {
     let _p = tracing::span!(tracing::Level::INFO, "handle_code_action_resolve").entered();
-    let params = match code_action.data.take() {
-        Some(it) => it,
-        None => return Err(invalid_params_error("code action without data".to_owned()).into()),
+    let Some(params) = code_action.data.take() else {
+        return Err(invalid_params_error("code action without data".to_owned()).into());
     };
 
     let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
+    if snap.file_version(file_id) != params.version {
+        return Err(invalid_params_error("stale code action".to_owned()).into());
+    }
     let line_index = snap.file_line_index(file_id)?;
     let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
     let frange = FileRange { file_id, range };
@@ -1407,12 +1422,11 @@ pub(crate) fn handle_code_lens(
 
 pub(crate) fn handle_code_lens_resolve(
     snap: GlobalStateSnapshot,
-    code_lens: CodeLens,
+    mut code_lens: CodeLens,
 ) -> anyhow::Result<CodeLens> {
-    if code_lens.data.is_none() {
-        return Ok(code_lens);
-    }
-    let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else {
+    let Some(data) = code_lens.data.take() else { return Ok(code_lens) };
+    let resolve = serde_json::from_value::<lsp_ext::CodeLensResolveData>(data)?;
+    let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
         return Ok(code_lens);
     };
     let annotation = snap.analysis.resolve_annotation(annotation)?;
@@ -1491,6 +1505,10 @@ pub(crate) fn handle_inlay_hints(
     )?;
     let line_index = snap.file_line_index(file_id)?;
     let source_root = snap.analysis.source_root(file_id)?;
+    let range = TextRange::new(
+        range.start().min(line_index.index.len()),
+        range.end().min(line_index.index.len()),
+    );
 
     let inlay_hints_config = snap.config.inlay_hints(Some(source_root));
     Ok(Some(
@@ -1518,8 +1536,12 @@ pub(crate) fn handle_inlay_hints_resolve(
 
     let Some(data) = original_hint.data.take() else { return Ok(original_hint) };
     let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
-    let Some(hash) = resolve_data.hash.parse().ok() else { return Ok(original_hint) };
     let file_id = FileId::from_raw(resolve_data.file_id);
+    if resolve_data.version != snap.file_version(file_id) {
+        tracing::warn!("Inlay hint resolve data is outdated");
+        return Ok(original_hint);
+    }
+    let Some(hash) = resolve_data.hash.parse().ok() else { return Ok(original_hint) };
     anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data");
 
     let line_index = snap.file_line_index(file_id)?;
@@ -1758,12 +1780,13 @@ pub(crate) fn handle_open_docs(
     let _p = tracing::span!(tracing::Level::INFO, "handle_open_docs").entered();
     let position = from_proto::file_position(&snap, params)?;
 
-    let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws {
-        ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())),
-        ProjectWorkspace::Json { .. } => None,
-        ProjectWorkspace::DetachedFile { cargo_script, sysroot, .. } => {
-            cargo_script.as_ref().zip(Some(sysroot.as_ref().ok()))
+    let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match &ws.kind {
+        ProjectWorkspaceKind::Cargo { cargo, .. }
+        | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
+            Some((cargo, ws.sysroot.as_ref().ok()))
         }
+        ProjectWorkspaceKind::Json { .. } => None,
+        ProjectWorkspaceKind::DetachedFile { .. } => None,
     });
 
     let (cargo, sysroot) = match ws_and_sysroot {
@@ -1836,7 +1859,7 @@ pub(crate) fn handle_view_recursive_memory_layout(
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<lsp_ext::RecursiveMemoryLayout>> {
-    let _p = tracing::span!(tracing::Level::INFO, "view_recursive_memory_layout").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "handle_view_recursive_memory_layout").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
     let offset = from_proto::offset(&line_index, params.position)?;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 7b385ca9d96..cc83d6246bf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -153,6 +153,7 @@ fn integrated_completion_benchmark() {
             prefer_no_std: false,
             prefer_prelude: true,
             limit: None,
+            term_search_fuel: 200,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -197,6 +198,7 @@ fn integrated_completion_benchmark() {
             prefer_no_std: false,
             prefer_prelude: true,
             limit: None,
+            term_search_fuel: 200,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -239,6 +241,7 @@ fn integrated_completion_benchmark() {
             prefer_no_std: false,
             prefer_prelude: true,
             limit: None,
+            term_search_fuel: 200,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -295,6 +298,7 @@ fn integrated_diagnostics_benchmark() {
         },
         prefer_no_std: false,
         prefer_prelude: false,
+        term_search_fuel: 400,
     };
     host.analysis()
         .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
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 12f8e71c981..2cf9b53f7c8 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
@@ -2,6 +2,7 @@
 
 #![allow(clippy::disallowed_types)]
 
+use std::ops;
 use std::path::PathBuf;
 
 use ide_db::line_index::WideEncoding;
@@ -494,10 +495,12 @@ impl Notification for ServerStatusNotification {
 }
 
 #[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
+#[serde(rename_all = "camelCase")]
 pub struct ServerStatusParams {
     pub health: Health,
     pub quiescent: bool,
     pub message: Option<String>,
+    pub workspace_info: Option<String>,
 }
 
 #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
@@ -508,6 +511,16 @@ pub enum Health {
     Error,
 }
 
+impl ops::BitOrAssign for Health {
+    fn bitor_assign(&mut self, rhs: Self) {
+        *self = match (*self, rhs) {
+            (Health::Error, _) | (_, Health::Error) => Health::Error,
+            (Health::Warning, _) | (_, Health::Warning) => Health::Warning,
+            _ => Health::Ok,
+        }
+    }
+}
+
 pub enum CodeActionRequest {}
 
 impl Request for CodeActionRequest {
@@ -548,6 +561,7 @@ pub struct CodeAction {
 pub struct CodeActionData {
     pub code_action_params: lsp_types::CodeActionParams,
     pub id: String,
+    pub version: Option<i32>,
 }
 
 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
@@ -789,6 +803,7 @@ impl Request for OnTypeFormatting {
 pub struct CompletionResolveData {
     pub position: lsp_types::TextDocumentPositionParams,
     pub imports: Vec<CompletionImport>,
+    pub version: Option<i32>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -796,6 +811,7 @@ pub struct InlayHintResolveData {
     pub file_id: u32,
     // This is a string instead of a u64 as javascript can't represent u64 fully
     pub hash: String,
+    pub version: Option<i32>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
index f42985a9161..b6b20296d80 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
@@ -9,10 +9,8 @@ use syntax::{TextRange, TextSize};
 use vfs::AbsPathBuf;
 
 use crate::{
-    from_json,
     global_state::GlobalStateSnapshot,
     line_index::{LineIndex, PositionEncoding},
-    lsp::utils::invalid_params_error,
     lsp_ext,
 };
 
@@ -105,16 +103,13 @@ pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind>
 
 pub(crate) fn annotation(
     snap: &GlobalStateSnapshot,
-    code_lens: lsp_types::CodeLens,
+    range: lsp_types::Range,
+    data: lsp_ext::CodeLensResolveData,
 ) -> anyhow::Result<Option<Annotation>> {
-    let data =
-        code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_owned()))?;
-    let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", &data)?;
-
-    match resolve.kind {
+    match data.kind {
         lsp_ext::CodeLensResolveDataKind::Impls(params) => {
             if snap.url_file_version(&params.text_document_position_params.text_document.uri)
-                != Some(resolve.version)
+                != Some(data.version)
             {
                 return Ok(None);
             }
@@ -123,19 +118,19 @@ pub(crate) fn annotation(
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
-                range: text_range(&line_index, code_lens.range)?,
+                range: text_range(&line_index, range)?,
                 kind: AnnotationKind::HasImpls { pos, data: None },
             })
         }
         lsp_ext::CodeLensResolveDataKind::References(params) => {
-            if snap.url_file_version(&params.text_document.uri) != Some(resolve.version) {
+            if snap.url_file_version(&params.text_document.uri) != Some(data.version) {
                 return Ok(None);
             }
             let pos @ FilePosition { file_id, .. } = file_position(snap, params)?;
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
-                range: text_range(&line_index, code_lens.range)?,
+                range: text_range(&line_index, range)?,
                 kind: AnnotationKind::HasReferences { pos, data: None },
             })
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index d02f4612dc1..03daccc99c4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -225,13 +225,14 @@ pub(crate) fn snippet_text_edit_vec(
 pub(crate) fn completion_items(
     config: &Config,
     line_index: &LineIndex,
+    version: Option<i32>,
     tdpp: lsp_types::TextDocumentPositionParams,
     items: Vec<CompletionItem>,
 ) -> Vec<lsp_types::CompletionItem> {
     let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default();
     let mut res = Vec::with_capacity(items.len());
     for item in items {
-        completion_item(&mut res, config, line_index, &tdpp, max_relevance, item);
+        completion_item(&mut res, config, line_index, version, &tdpp, max_relevance, item);
     }
 
     if let Some(limit) = config.completion(None).limit {
@@ -246,6 +247,7 @@ fn completion_item(
     acc: &mut Vec<lsp_types::CompletionItem>,
     config: &Config,
     line_index: &LineIndex,
+    version: Option<i32>,
     tdpp: &lsp_types::TextDocumentPositionParams,
     max_relevance: u32,
     item: CompletionItem,
@@ -328,7 +330,7 @@ fn completion_item(
             })
             .collect::<Vec<_>>();
         if !imports.is_empty() {
-            let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports };
+            let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version };
             lsp_item.data = Some(to_value(data).unwrap());
         }
     }
@@ -483,6 +485,7 @@ pub(crate) fn inlay_hint(
             to_value(lsp_ext::InlayHintResolveData {
                 file_id: file_id.index(),
                 hash: hash.to_string(),
+                version: snap.file_version(file_id),
             })
             .unwrap(),
         ),
@@ -1318,7 +1321,7 @@ pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind {
 pub(crate) fn code_action(
     snap: &GlobalStateSnapshot,
     assist: Assist,
-    resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
+    resolve_data: Option<(usize, lsp_types::CodeActionParams, Option<i32>)>,
 ) -> Cancellable<lsp_ext::CodeAction> {
     let mut res = lsp_ext::CodeAction {
         title: assist.label.to_string(),
@@ -1336,10 +1339,11 @@ pub(crate) fn code_action(
 
     match (assist.source_change, resolve_data) {
         (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
-        (None, Some((index, code_action_params))) => {
+        (None, Some((index, code_action_params, version))) => {
             res.data = Some(lsp_ext::CodeActionData {
                 id: format!("{}:{}:{index}", assist.id.0, assist.id.1.name()),
                 code_action_params,
+                version,
             });
         }
         (None, None) => {
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 f37b25fb955..5435be3dc27 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
@@ -12,6 +12,7 @@ use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
 use lsp_server::{Connection, Notification, Request};
 use lsp_types::{notification::Notification as _, TextDocumentIdentifier};
 use stdx::thread::ThreadIntent;
+use tracing::{span, Level};
 use vfs::FileId;
 
 use crate::{
@@ -44,7 +45,7 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
     // https://github.com/rust-lang/rust-analyzer/issues/2835
     #[cfg(windows)]
     unsafe {
-        use winapi::um::processthreadsapi::*;
+        use windows_sys::Win32::System::Threading::*;
         let thread = GetCurrentThread();
         let thread_priority_above_normal = 1;
         SetThreadPriority(thread, thread_priority_above_normal);
@@ -229,8 +230,7 @@ impl GlobalState {
     fn handle_event(&mut self, event: Event) -> anyhow::Result<()> {
         let loop_start = Instant::now();
         // NOTE: don't count blocking select! call as a loop-turn time
-        let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event", event = %event)
-            .entered();
+        let _p = tracing::span!(Level::INFO, "GlobalState::handle_event", event = %event).entered();
 
         let event_dbg_msg = format!("{event:?}");
         tracing::debug!(?loop_start, ?event, "handle_event");
@@ -669,9 +669,12 @@ impl GlobalState {
     }
 
     fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
+        let _p = tracing::span!(Level::INFO, "GlobalState::handle_vfs_msg").entered();
         let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
         match message {
             vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
+                let _p = tracing::span!(Level::INFO, "GlobalState::handle_vfs_msg{changed/load}")
+                    .entered();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
                     let path = VfsPath::from(path);
@@ -685,6 +688,8 @@ impl GlobalState {
                 }
             }
             vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => {
+                let _p =
+                    tracing::span!(Level::INFO, "GlobalState::handle_vfs_mgs/progress").entered();
                 always!(config_version <= self.vfs_config_version);
 
                 let state = match n_done {
@@ -867,6 +872,8 @@ impl GlobalState {
 
     /// Registers and handles a request. This should only be called once per incoming request.
     fn on_new_request(&mut self, request_received: Instant, req: Request) {
+        let _p =
+            span!(Level::INFO, "GlobalState::on_new_request", req.method = ?req.method).entered();
         self.register_request(&req, request_received);
         self.on_request(req);
     }
@@ -894,6 +901,10 @@ impl GlobalState {
         use crate::handlers::request as handlers;
         use lsp_types::request as lsp_request;
 
+        const RETRY: bool = true;
+        const NO_RETRY: bool = false;
+
+        #[rustfmt::skip]
         dispatcher
             // Request handlers that must run on the main thread
             // because they mutate GlobalState:
@@ -919,67 +930,65 @@ impl GlobalState {
             // 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_request::Completion>(handlers::handle_completion)
-            .on_latency_sensitive::<lsp_request::ResolveCompletionItem>(
-                handlers::handle_completion_resolve,
-            )
-            .on_latency_sensitive::<lsp_request::SemanticTokensFullRequest>(
-                handlers::handle_semantic_tokens_full,
-            )
-            .on_latency_sensitive::<lsp_request::SemanticTokensFullDeltaRequest>(
-                handlers::handle_semantic_tokens_full_delta,
-            )
-            .on_latency_sensitive::<lsp_request::SemanticTokensRangeRequest>(
-                handlers::handle_semantic_tokens_range,
-            )
+            // FIXME: Retrying can make the result of this stale?
+            .on_latency_sensitive::<RETRY, lsp_request::Completion>(handlers::handle_completion)
+            // FIXME: Retrying can make the result of this stale
+            .on_latency_sensitive::<RETRY, lsp_request::ResolveCompletionItem>(handlers::handle_completion_resolve)
+            .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullRequest>(handlers::handle_semantic_tokens_full)
+            .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullDeltaRequest>(handlers::handle_semantic_tokens_full_delta)
+            .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
+            // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
             // All other request handlers
-            .on::<lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
-            .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
-            .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
-            .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
-            .on::<lsp_ext::ViewMir>(handlers::handle_view_mir)
-            .on::<lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
-            .on::<lsp_ext::ViewFileText>(handlers::handle_view_file_text)
-            .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
-            .on::<lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
-            .on::<lsp_ext::DiscoverTest>(handlers::handle_discover_test)
-            .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
-            .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
-            .on::<lsp_ext::Runnables>(handlers::handle_runnables)
-            .on::<lsp_ext::RelatedTests>(handlers::handle_related_tests)
-            .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)
-            .on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
-            .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
-            .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
-            .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_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)
+            .on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
+            .on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
+            .on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
+            .on::<RETRY, lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
+            .on::<NO_RETRY, lsp_request::GotoDefinition>(handlers::handle_goto_definition)
+            .on::<NO_RETRY, lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
+            .on::<NO_RETRY, lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
+            .on::<NO_RETRY, lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
+            .on::<RETRY, lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
+            .on::<RETRY, lsp_request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
+            .on::<NO_RETRY, lsp_request::CodeLensRequest>(handlers::handle_code_lens)
+            .on::<RETRY, lsp_request::CodeLensResolve>(handlers::handle_code_lens_resolve)
+            .on::<NO_RETRY, lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
+            .on::<NO_RETRY, lsp_request::Rename>(handlers::handle_rename)
+            .on::<NO_RETRY, lsp_request::References>(handlers::handle_references)
+            .on::<NO_RETRY, lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
+            .on::<NO_RETRY, lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
+            .on::<NO_RETRY, lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
+            .on::<NO_RETRY, lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
+            // All other request handlers (lsp extension)
+            .on::<RETRY, lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
+            .on::<RETRY, lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
+            .on::<RETRY, lsp_ext::ViewFileText>(handlers::handle_view_file_text)
+            .on::<RETRY, lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
+            .on::<RETRY, lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
+            .on::<RETRY, lsp_ext::DiscoverTest>(handlers::handle_discover_test)
+            .on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
+            .on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr)
+            .on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
+            .on::<NO_RETRY, lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
+            .on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir)
+            .on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir)
+            .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
+            .on::<NO_RETRY, lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
+            .on::<NO_RETRY, lsp_ext::ParentModule>(handlers::handle_parent_module)
+            .on::<NO_RETRY, lsp_ext::Runnables>(handlers::handle_runnables)
+            .on::<NO_RETRY, lsp_ext::RelatedTests>(handlers::handle_related_tests)
+            .on::<NO_RETRY, lsp_ext::CodeActionRequest>(handlers::handle_code_action)
+            .on::<RETRY, lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
+            .on::<NO_RETRY, lsp_ext::HoverRequest>(handlers::handle_hover)
+            .on::<NO_RETRY, lsp_ext::ExternalDocs>(handlers::handle_open_docs)
+            .on::<NO_RETRY, lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
+            .on::<NO_RETRY, lsp_ext::MoveItem>(handlers::handle_move_item)
             .finish();
     }
 
     /// Handles an incoming notification.
     fn on_notification(&mut self, not: Notification) -> anyhow::Result<()> {
+        let _p =
+            span!(Level::INFO, "GlobalState::on_notification", not.method = ?not.method).entered();
         use crate::handlers::notification as handlers;
         use lsp_types::notification as notifs;
 
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 5d8a66cabc7..fd14efa1da5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -25,7 +25,7 @@ use ide_db::{
 use itertools::Itertools;
 use load_cargo::{load_proc_macro, ProjectFolders};
 use proc_macro_api::ProcMacroServer;
-use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
+use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use stdx::{format_to, thread::ThreadIntent};
 use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, ChangeKind};
@@ -103,81 +103,48 @@ impl GlobalState {
             health: lsp_ext::Health::Ok,
             quiescent: self.is_quiescent(),
             message: None,
+            workspace_info: None,
         };
         let mut message = String::new();
 
+        if !self.config.cargo_autoreload()
+            && self.is_quiescent()
+            && self.fetch_workspaces_queue.op_requested()
+        {
+            status.health |= lsp_ext::Health::Warning;
+            message.push_str("Auto-reloading is disabled and the workspace has changed, a manual workspace reload is required.\n\n");
+        }
+
         if self.build_deps_changed {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             message.push_str(
                 "Proc-macros and/or build scripts have changed and need to be rebuilt.\n\n",
             );
         }
         if self.fetch_build_data_error().is_err() {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             message.push_str("Failed to run build scripts of some packages.\n\n");
         }
-        if self.proc_macro_clients.iter().any(|it| it.is_err()) {
-            status.health = lsp_ext::Health::Warning;
-            message.push_str("Failed to spawn one or more proc-macro servers.\n\n");
-            for err in self.proc_macro_clients.iter() {
-                if let Err(err) = err {
-                    format_to!(message, "- {err}\n");
-                }
-            }
-        }
-        if !self.config.cargo_autoreload()
-            && self.is_quiescent()
-            && self.fetch_workspaces_queue.op_requested()
-        {
-            status.health = lsp_ext::Health::Warning;
-            message.push_str("Auto-reloading is disabled and the workspace has changed, a manual workspace reload is required.\n\n");
-        }
-        if self.config.linked_or_discovered_projects().is_empty()
-            && self.config.detached_files().is_empty()
-            && self.config.notifications().cargo_toml_not_found
-        {
-            status.health = lsp_ext::Health::Warning;
-            message.push_str("Failed to discover workspace.\n");
-            message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n");
-        }
+
         if let Some(err) = &self.config_errors {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             format_to!(message, "{err}\n");
         }
         if let Some(err) = &self.last_flycheck_error {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             message.push_str(err);
             message.push('\n');
         }
 
-        for ws in self.workspaces.iter() {
-            let (ProjectWorkspace::Cargo { sysroot, .. }
-            | ProjectWorkspace::Json { sysroot, .. }
-            | ProjectWorkspace::DetachedFile { sysroot, .. }) = ws;
-            match sysroot {
-                Err(None) => (),
-                Err(Some(e)) => {
-                    status.health = lsp_ext::Health::Warning;
-                    message.push_str(e);
-                    message.push_str("\n\n");
-                }
-                Ok(s) => {
-                    if let Some(e) = s.loading_warning() {
-                        status.health = lsp_ext::Health::Warning;
-                        message.push_str(&e);
-                        message.push_str("\n\n");
-                    }
-                }
-            }
-            if let ProjectWorkspace::Cargo { rustc: Err(Some(e)), .. } = ws {
-                status.health = lsp_ext::Health::Warning;
-                message.push_str(e);
-                message.push_str("\n\n");
-            }
+        if self.config.linked_or_discovered_projects().is_empty()
+            && self.config.detached_files().is_empty()
+        {
+            status.health |= lsp_ext::Health::Warning;
+            message.push_str("Failed to discover workspace.\n");
+            message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n");
         }
-
         if self.fetch_workspace_error().is_err() {
-            status.health = lsp_ext::Health::Error;
+            status.health |= lsp_ext::Health::Error;
             message.push_str("Failed to load workspaces.");
 
             if self.config.has_linked_projects() {
@@ -193,9 +160,63 @@ impl GlobalState {
             message.push_str("\n\n");
         }
 
+        if !self.workspaces.is_empty() {
+            let proc_macro_clients =
+                self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
+
+            let mut workspace_info = "Loaded workspaces:\n".to_owned();
+            for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
+                format_to!(workspace_info, "- `{}`\n", ws.manifest_or_root());
+                format_to!(workspace_info, "    - sysroot:");
+
+                match ws.sysroot.as_ref() {
+                    Err(None) => format_to!(workspace_info, " None"),
+                    Err(Some(e)) => {
+                        status.health |= lsp_ext::Health::Warning;
+                        format_to!(workspace_info, " {e}");
+                    }
+                    Ok(s) => {
+                        format_to!(workspace_info, " `{}`", s.root().to_string());
+                        if let Some(err) = s
+                            .check_has_core()
+                            .err()
+                            .inspect(|_| status.health |= lsp_ext::Health::Warning)
+                        {
+                            format_to!(workspace_info, " ({err})");
+                        }
+                        if let Some(src_root) = s.src_root() {
+                            format_to!(
+                                workspace_info,
+                                "\n        - sysroot source: `{}`",
+                                src_root
+                            );
+                        }
+                        format_to!(workspace_info, "\n");
+                    }
+                }
+
+                if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(e)), .. } = &ws.kind {
+                    status.health |= lsp_ext::Health::Warning;
+                    format_to!(workspace_info, "    - rustc workspace: {e}\n");
+                };
+                if let Some(proc_macro_client) = proc_macro_client {
+                    format_to!(workspace_info, "    - proc-macro server: ");
+                    match proc_macro_client {
+                        Ok(it) => format_to!(workspace_info, "`{}`\n", it.path()),
+                        Err(e) => {
+                            status.health |= lsp_ext::Health::Warning;
+                            format_to!(workspace_info, "{e}\n")
+                        }
+                    }
+                }
+            }
+            status.workspace_info = Some(workspace_info);
+        }
+
         if !message.is_empty() {
             status.message = Some(message.trim_end().to_owned());
         }
+
         status
     }
 
@@ -204,7 +225,14 @@ impl GlobalState {
 
         self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, {
             let linked_projects = self.config.linked_or_discovered_projects();
-            let detached_files = self.config.detached_files().to_vec();
+            let detached_files: Vec<_> = self
+                .config
+                .detached_files()
+                .iter()
+                .cloned()
+                .map(ManifestPath::try_from)
+                .filter_map(Result::ok)
+                .collect();
             let cargo_config = self.config.cargo();
 
             move |sender| {
@@ -494,23 +522,28 @@ impl GlobalState {
                     None => ws.find_sysroot_proc_macro_srv()?,
                 };
 
-                let env =
-                    match ws {
-                        ProjectWorkspace::Cargo { cargo_config_extra_env, sysroot, .. } => {
-                            cargo_config_extra_env
-                                .iter()
-                                .chain(self.config.extra_env())
-                                .map(|(a, b)| (a.clone(), b.clone()))
-                                .chain(sysroot.as_ref().map(|it| {
-                                    ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string())
-                                }))
-                                .collect()
-                        }
-                        _ => Default::default(),
-                    };
+                let env = match &ws.kind {
+                    ProjectWorkspaceKind::Cargo { cargo_config_extra_env, .. }
+                    | ProjectWorkspaceKind::DetachedFile {
+                        cargo: Some(_),
+                        cargo_config_extra_env,
+                        ..
+                    } => cargo_config_extra_env
+                        .iter()
+                        .chain(self.config.extra_env())
+                        .map(|(a, b)| (a.clone(), b.clone()))
+                        .chain(
+                            ws.sysroot
+                                .as_ref()
+                                .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string())),
+                        )
+                        .collect(),
+
+                    _ => Default::default(),
+                };
                 tracing::info!("Using proc-macro server at {path}");
 
-                ProcMacroServer::spawn(path.clone(), &env).map_err(|err| {
+                ProcMacroServer::spawn(&path, &env).map_err(|err| {
                     tracing::error!(
                         "Failed to run proc-macro server from path {path}, error: {err:?}",
                     );
@@ -554,8 +587,8 @@ impl GlobalState {
         self.detached_files = self
             .workspaces
             .iter()
-            .filter_map(|ws| match ws {
-                ProjectWorkspace::DetachedFile { file, .. } => Some(file.clone()),
+            .filter_map(|ws| match &ws.kind {
+                ProjectWorkspaceKind::DetachedFile { file, .. } => Some(file.clone()),
                 _ => None,
             })
             .collect();
@@ -659,33 +692,37 @@ impl GlobalState {
                 config,
                 None,
                 self.config.root_path().clone(),
+                None,
             )],
             flycheck::InvocationStrategy::PerWorkspace => {
                 self.workspaces
                     .iter()
                     .enumerate()
-                    .filter_map(|(id, w)| match w {
-                        ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((
+                    .filter_map(|(id, ws)| {
+                        Some((
                             id,
-                            cargo.workspace_root(),
-                            sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
-                        )),
-                        ProjectWorkspace::Json { project, sysroot, .. } => {
-                            // Enable flychecks for json projects if a custom flycheck command was supplied
-                            // in the workspace configuration.
-                            match config {
-                                FlycheckConfig::CustomCommand { .. } => Some((
-                                    id,
-                                    project.path(),
-                                    sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
-                                )),
-                                _ => None,
-                            }
-                        }
-                        // FIXME
-                        ProjectWorkspace::DetachedFile { .. } => None,
+                            match &ws.kind {
+                                ProjectWorkspaceKind::Cargo { cargo, .. }
+                                | ProjectWorkspaceKind::DetachedFile {
+                                    cargo: Some((cargo, _)),
+                                    ..
+                                } => (cargo.workspace_root(), Some(cargo.manifest_path())),
+                                ProjectWorkspaceKind::Json(project) => {
+                                    // Enable flychecks for json projects if a custom flycheck command was supplied
+                                    // in the workspace configuration.
+                                    match config {
+                                        FlycheckConfig::CustomCommand { .. } => {
+                                            (project.path(), None)
+                                        }
+                                        _ => return None,
+                                    }
+                                }
+                                ProjectWorkspaceKind::DetachedFile { .. } => return None,
+                            },
+                            ws.sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
+                        ))
                     })
-                    .map(|(id, root, sysroot_root)| {
+                    .map(|(id, (root, manifest_path), sysroot_root)| {
                         let sender = sender.clone();
                         FlycheckHandle::spawn(
                             id,
@@ -693,6 +730,7 @@ impl GlobalState {
                             config.clone(),
                             sysroot_root,
                             root.to_path_buf(),
+                            manifest_path.map(|it| it.to_path_buf()),
                         )
                     })
                     .collect()
@@ -722,9 +760,7 @@ pub fn ws_to_crate_graph(
         let (other, mut crate_proc_macros) = ws.to_crate_graph(&mut load, extra_env);
         let num_layouts = layouts.len();
         let num_toolchains = toolchains.len();
-        let (ProjectWorkspace::Cargo { toolchain, target_layout, .. }
-        | ProjectWorkspace::Json { toolchain, target_layout, .. }
-        | ProjectWorkspace::DetachedFile { toolchain, target_layout, .. }) = ws;
+        let ProjectWorkspace { toolchain, target_layout, .. } = ws;
 
         let mapping = crate_graph.extend(
             other,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
index f7de5fb2ff1..2bcd8505e81 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
@@ -45,7 +45,7 @@ impl<T> TaskPool<T> {
 
 /// `TaskQueue`, like its name suggests, queues tasks.
 ///
-/// This should only be used used if a task must run after [`GlobalState::process_changes`]
+/// This should only be used if a task must run after [`GlobalState::process_changes`]
 /// has been called.
 pub(crate) struct TaskQueue {
     pub(crate) sender: crossbeam_channel::Sender<QueuedTask>,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
index cf38032b941..59b229cd064 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
@@ -1,24 +1,31 @@
 use std::path::PathBuf;
 
-use project_model::{CargoWorkspace, ProjectWorkspace, Sysroot, WorkspaceBuildScripts};
+use project_model::{
+    CargoWorkspace, ManifestPath, Metadata, ProjectWorkspace, ProjectWorkspaceKind, Sysroot,
+    WorkspaceBuildScripts,
+};
 use rust_analyzer::ws_to_crate_graph;
 use rustc_hash::FxHashMap;
 use serde::de::DeserializeOwned;
 use vfs::{AbsPathBuf, FileId};
 
 fn load_cargo_with_fake_sysroot(file: &str) -> ProjectWorkspace {
-    let meta = get_test_json_file(file);
-    let cargo_workspace = CargoWorkspace::new(meta);
-    ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let meta: Metadata = get_test_json_file(file);
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
+    ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         sysroot: Ok(get_fake_sysroot()),
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     }
 }
 
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 b87f02947bf..5a1397bbb0e 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
@@ -150,6 +150,7 @@ use dependency2::Spam;
     )
     .with_config(serde_json::json!({
         "cargo": { "sysroot": null },
+        "linkedProjects": ["src/lib.rs"],
     }))
     .server()
     .wait_until_workspace_is_loaded();
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 f04962a7a27..cf27cc7eeff 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
@@ -185,11 +185,7 @@ impl Project<'_> {
             roots,
             None,
         );
-        // TODO: don't hardcode src/lib.rs as detached file
-        let mut c = self.config;
-        let p = tmp_dir_path.join("src/lib.rs").to_string();
-        c["detachedFiles"] = serde_json::json!([p]);
-        config.update(c).expect("invalid config");
+        config.update(self.config).expect("invalid config");
         config.rediscover_workspaces();
 
         Server::new(tmp_dir.keep(), config)
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 34439391333..4a7415b016d 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
@@ -144,6 +144,7 @@ MIT OR Apache-2.0
 MIT OR Apache-2.0 OR Zlib
 MIT OR Zlib OR Apache-2.0
 MIT/Apache-2.0
+MPL-2.0
 Unlicense OR MIT
 Unlicense/MIT
 Zlib OR Apache-2.0 OR MIT
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
index f86683ee77a..5dde0d560f1 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
@@ -443,7 +443,7 @@ pub trait QueryDb<'d>: Sized {
 /// Trait implements by all of the "special types" associated with
 /// each of your queries.
 pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> {
-    /// Type that you you give as a parameter -- for queries with zero
+    /// Type that you give as a parameter -- for queries with zero
     /// or more than one input, this will be a tuple.
     type Key: Clone + Debug + Hash + Eq;
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lru.rs b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
index edad551842d..f63f4c1e986 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lru.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
@@ -285,7 +285,7 @@ where
 
 impl Default for LruIndex {
     fn default() -> Self {
-        Self { index: AtomicUsize::new(std::usize::MAX) }
+        Self { index: AtomicUsize::new(usize::MAX) }
     }
 }
 
@@ -299,11 +299,11 @@ impl LruIndex {
     }
 
     fn clear(&self) {
-        self.store(std::usize::MAX);
+        self.store(usize::MAX);
     }
 
     fn is_in_lru(&self) -> bool {
-        self.load() != std::usize::MAX
+        self.load() != usize::MAX
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/revision.rs b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
index 204c0883b85..7f4c333fb19 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/revision.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
@@ -60,7 +60,7 @@ impl AtomicRevision {
     /// Increment by 1, returning previous value.
     pub(crate) fn fetch_then_increment(&self) -> Revision {
         let v = self.data.fetch_add(1, Ordering::SeqCst);
-        assert!(v != u32::max_value(), "revision overflow");
+        assert!(v != u32::MAX, "revision overflow");
         Revision::from(v)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 6cca1163353..99824df1f69 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -22,7 +22,7 @@ itertools.workspace = true
 
 [target.'cfg(windows)'.dependencies]
 miow = "0.6.0"
-winapi = { version = "0.3.9", features = ["winerror"] }
+windows-sys = { version = "0.52", features = ["Win32_Foundation"] }
 
 [features]
 # Uncomment to enable for the whole crate graph
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 0504ca50b88..54f10df42a8 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -22,6 +22,10 @@ pub fn is_ci() -> bool {
     option_env!("CI").is_some()
 }
 
+pub fn hash_once<Hasher: std::hash::Hasher + Default>(thing: impl std::hash::Hash) -> u64 {
+    std::hash::BuildHasher::hash_one(&std::hash::BuildHasherDefault::<Hasher>::default(), thing)
+}
+
 #[must_use]
 #[allow(clippy::print_stderr)]
 pub fn timeit(label: &'static str) -> impl Drop {
diff --git a/src/tools/rust-analyzer/crates/stdx/src/process.rs b/src/tools/rust-analyzer/crates/stdx/src/process.rs
index e6935f06b2c..c54d850d7b5 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/process.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/process.rs
@@ -162,7 +162,7 @@ mod imp {
         pipe::NamedPipe,
         Overlapped,
     };
-    use winapi::shared::winerror::ERROR_BROKEN_PIPE;
+    use windows_sys::Win32::Foundation::ERROR_BROKEN_PIPE;
 
     struct Pipe<'a> {
         dst: &'a mut Vec<u8>,
diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
index a235e3e17ce..c2c6dac72de 100644
--- a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
@@ -3,7 +3,7 @@ name = "syntax-fuzz"
 version = "0.0.1"
 publish = false
 edition = "2021"
-rust-version = "1.76"
+rust-version = "1.78"
 
 [package.metadata]
 cargo-fuzz = true
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index e1765b25fd8..8c772b9c7a2 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -314,7 +314,9 @@ Attr =
   '#' '!'? '[' Meta ']'
 
 Meta =
-  Path ('=' Expr | TokenTree)?
+  'unsafe' '(' Path ('=' Expr | TokenTree)? ')'
+| Path ('=' Expr | TokenTree)?
+
 
 //****************************//
 // Statements and Expressions //
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 c82bc4151ac..98186c5473d 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
@@ -778,7 +778,10 @@ impl Meta {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
     pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
index 7cd1f1550b9..16599881d64 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
@@ -6,7 +6,7 @@ use std::{
 };
 
 use rustc_lexer::unescape::{
-    unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode,
+    unescape_byte, unescape_char, unescape_mixed, unescape_unicode, EscapeError, MixedUnit, Mode,
 };
 
 use crate::{
@@ -180,10 +180,7 @@ pub trait IsString: AstToken {
     fn close_quote_text_range(&self) -> Option<TextRange> {
         self.quote_offsets().map(|it| it.quotes.1)
     }
-    fn escaped_char_ranges(
-        &self,
-        cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
-    ) {
+    fn escaped_char_ranges(&self, cb: &mut dyn FnMut(TextRange, Result<char, EscapeError>)) {
         let text_range_no_quotes = match self.text_range_between_quotes() {
             Some(it) => it,
             None => return,
@@ -212,20 +209,17 @@ impl IsString for ast::String {
 }
 
 impl ast::String {
-    pub fn value(&self) -> Option<Cow<'_, str>> {
+    pub fn value(&self) -> Result<Cow<'_, str>, EscapeError> {
+        let text = self.text();
+        let text_range = self.text_range_between_quotes().ok_or(EscapeError::LoneSlash)?;
+        let text = &text[text_range - self.syntax().text_range().start()];
         if self.is_raw() {
-            let text = self.text();
-            let text =
-                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text));
+            return Ok(Cow::Borrowed(text));
         }
 
-        let text = self.text();
-        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-
         let mut buf = String::new();
         let mut prev_end = 0;
-        let mut has_error = false;
+        let mut has_error = None;
         unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
@@ -239,13 +233,13 @@ impl ast::String {
                 buf.push_str(&text[..prev_end]);
                 buf.push(c);
             }
-            (Err(_), _) => has_error = true,
+            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
-            (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text)),
-            (false, false) => Some(Cow::Owned(buf)),
+            (Some(e), _) => Err(e),
+            (None, true) => Ok(Cow::Borrowed(text)),
+            (None, false) => Ok(Cow::Owned(buf)),
         }
     }
 }
@@ -256,20 +250,17 @@ impl IsString for ast::ByteString {
 }
 
 impl ast::ByteString {
-    pub fn value(&self) -> Option<Cow<'_, [u8]>> {
+    pub fn value(&self) -> Result<Cow<'_, [u8]>, EscapeError> {
+        let text = self.text();
+        let text_range = self.text_range_between_quotes().ok_or(EscapeError::LoneSlash)?;
+        let text = &text[text_range - self.syntax().text_range().start()];
         if self.is_raw() {
-            let text = self.text();
-            let text =
-                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text.as_bytes()));
+            return Ok(Cow::Borrowed(text.as_bytes()));
         }
 
-        let text = self.text();
-        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-
         let mut buf: Vec<u8> = Vec::new();
         let mut prev_end = 0;
-        let mut has_error = false;
+        let mut has_error = None;
         unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
@@ -283,13 +274,13 @@ impl ast::ByteString {
                 buf.extend_from_slice(text[..prev_end].as_bytes());
                 buf.push(c as u8);
             }
-            (Err(_), _) => has_error = true,
+            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
-            (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text.as_bytes())),
-            (false, false) => Some(Cow::Owned(buf)),
+            (Some(e), _) => Err(e),
+            (None, true) => Ok(Cow::Borrowed(text.as_bytes())),
+            (None, false) => Ok(Cow::Owned(buf)),
         }
     }
 }
@@ -298,10 +289,7 @@ impl IsString for ast::CString {
     const RAW_PREFIX: &'static str = "cr";
     const MODE: Mode = Mode::CStr;
 
-    fn escaped_char_ranges(
-        &self,
-        cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
-    ) {
+    fn escaped_char_ranges(&self, cb: &mut dyn FnMut(TextRange, Result<char, EscapeError>)) {
         let text_range_no_quotes = match self.text_range_between_quotes() {
             Some(it) => it,
             None => return,
@@ -322,20 +310,17 @@ impl IsString for ast::CString {
 }
 
 impl ast::CString {
-    pub fn value(&self) -> Option<Cow<'_, [u8]>> {
+    pub fn value(&self) -> Result<Cow<'_, [u8]>, EscapeError> {
+        let text = self.text();
+        let text_range = self.text_range_between_quotes().ok_or(EscapeError::LoneSlash)?;
+        let text = &text[text_range - self.syntax().text_range().start()];
         if self.is_raw() {
-            let text = self.text();
-            let text =
-                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text.as_bytes()));
+            return Ok(Cow::Borrowed(text.as_bytes()));
         }
 
-        let text = self.text();
-        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-
         let mut buf = Vec::new();
         let mut prev_end = 0;
-        let mut has_error = false;
+        let mut has_error = None;
         let extend_unit = |buf: &mut Vec<u8>, unit: MixedUnit| match unit {
             MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()),
             MixedUnit::HighByte(b) => buf.push(b),
@@ -353,13 +338,13 @@ impl ast::CString {
                 buf.extend(text[..prev_end].as_bytes());
                 extend_unit(&mut buf, u);
             }
-            (Err(_), _) => has_error = true,
+            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
-            (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text.as_bytes())),
-            (false, false) => Some(Cow::Owned(buf)),
+            (Some(e), _) => Err(e),
+            (None, true) => Ok(Cow::Borrowed(text.as_bytes())),
+            (None, false) => Ok(Cow::Owned(buf)),
         }
     }
 }
@@ -478,34 +463,34 @@ impl Radix {
 }
 
 impl ast::Char {
-    pub fn value(&self) -> Option<char> {
+    pub fn value(&self) -> Result<char, EscapeError> {
         let mut text = self.text();
         if text.starts_with('\'') {
             text = &text[1..];
         } else {
-            return None;
+            return Err(EscapeError::ZeroChars);
         }
         if text.ends_with('\'') {
             text = &text[0..text.len() - 1];
         }
 
-        unescape_char(text).ok()
+        unescape_char(text)
     }
 }
 
 impl ast::Byte {
-    pub fn value(&self) -> Option<u8> {
+    pub fn value(&self) -> Result<u8, EscapeError> {
         let mut text = self.text();
         if text.starts_with("b\'") {
             text = &text[2..];
         } else {
-            return None;
+            return Err(EscapeError::ZeroChars);
         }
         if text.ends_with('\'') {
             text = &text[0..text.len() - 1];
         }
 
-        unescape_byte(text).ok()
+        unescape_byte(text)
     }
 }
 
@@ -559,7 +544,10 @@ mod tests {
 
     fn check_string_value<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
         assert_eq!(
-            ast::String { syntax: make::tokens::literal(&format!("\"{lit}\"")) }.value().as_deref(),
+            ast::String { syntax: make::tokens::literal(&format!("\"{lit}\"")) }
+                .value()
+                .as_deref()
+                .ok(),
             expected.into()
         );
     }
@@ -584,7 +572,8 @@ bcde", "abcde",
         assert_eq!(
             ast::ByteString { syntax: make::tokens::literal(&format!("b\"{lit}\"")) }
                 .value()
-                .as_deref(),
+                .as_deref()
+                .ok(),
             expected.into().map(|value| &value[..])
         );
     }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs b/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
index 8eb4a10a3f5..fe3d61bef16 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
@@ -9,7 +9,7 @@ use crate::{
 pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) {
     if let Some(parent) = block.syntax().parent() {
         match parent.kind() {
-            FN | EXPR_STMT | STMT_LIST => return,
+            FN | EXPR_STMT | STMT_LIST | MACRO_STMTS => return,
             _ => {}
         }
     }
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 89ed6a61579..be9961120d5 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -240,7 +240,12 @@ impl ChangeFixture {
                 crate_graph
                     .add_dep(
                         from_id,
-                        Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude),
+                        Dependency::with_prelude(
+                            CrateName::new(&to).unwrap(),
+                            to_id,
+                            prelude,
+                            false,
+                        ),
                     )
                     .unwrap();
             }
@@ -275,7 +280,15 @@ impl ChangeFixture {
 
             for krate in all_crates {
                 crate_graph
-                    .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate))
+                    .add_dep(
+                        krate,
+                        Dependency::with_prelude(
+                            CrateName::new("core").unwrap(),
+                            core_crate,
+                            true,
+                            true,
+                        ),
+                    )
                     .unwrap();
             }
         }
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 f125792d125..0257ed9ab41 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -28,7 +28,7 @@
 //!     env: option
 //!     eq: sized
 //!     error: fmt
-//!     fmt: option, result, transmute, coerce_unsized
+//!     fmt: option, result, transmute, coerce_unsized, copy, clone, derive
 //!     fn:
 //!     from: sized
 //!     future: pin
@@ -913,11 +913,13 @@ pub mod fmt {
     }
 
     mod rt {
+        use super::*;
 
         extern "C" {
             type Opaque;
         }
 
+        #[derive(Copy, Clone)]
         #[lang = "format_argument"]
         pub struct Argument<'a> {
             value: &'a Opaque,
@@ -930,8 +932,8 @@ pub mod fmt {
                 unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
             }
 
-            pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
-                Self::new(x, Display::fmt)
+            pub fn new_display<'b, T: crate::fmt::Display>(x: &'b T) -> Argument<'_> {
+                Self::new(x, crate::fmt::Display::fmt)
             }
         }
 
@@ -968,7 +970,9 @@ pub mod fmt {
                 flags: u32,
                 precision: Count,
                 width: Count,
-            ) -> Self;
+            ) -> Self {
+                Placeholder { position, fill, align, flags, precision, width }
+            }
         }
 
         #[lang = "format_unsafe_arg"]
@@ -977,10 +981,13 @@ pub mod fmt {
         }
 
         impl UnsafeArg {
-            pub unsafe fn new() -> Self;
+            pub unsafe fn new() -> Self {
+                UnsafeArg { _private: () }
+            }
         }
     }
 
+    #[derive(Copy, Clone)]
     #[lang = "format_arguments"]
     pub struct Arguments<'a> {
         pieces: &'a [&'static str],
@@ -1005,6 +1012,14 @@ pub mod fmt {
         ) -> Arguments<'a> {
             Arguments { pieces, fmt: Some(fmt), args }
         }
+
+        pub const fn as_str(&self) -> Option<&'static str> {
+            match (self.pieces, self.args) {
+                ([], []) => Some(""),
+                ([s], []) => Some(s),
+                _ => None,
+            }
+        }
     }
 
     // region:derive
@@ -1154,8 +1169,8 @@ pub mod pin {
         pointer: P,
     }
     impl<P> Pin<P> {
-        pub fn new(_pointer: P) -> Pin<P> {
-            loop {}
+        pub fn new(pointer: P) -> Pin<P> {
+            Pin { pointer }
         }
     }
     // region:deref
@@ -1356,18 +1371,48 @@ pub mod iter {
 // region:panic
 mod panic {
     pub macro panic_2021 {
-        () => (
-            $crate::panicking::panic("explicit panic")
-        ),
-        ($($t:tt)+) => (
-            $crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
-        ),
+        () => ({
+            const fn panic_cold_explicit() -> ! {
+                $crate::panicking::panic_explicit()
+            }
+            panic_cold_explicit();
+        }),
+        // Special-case the single-argument case for const_panic.
+        ("{}", $arg:expr $(,)?) => ({
+            #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
+            #[rustc_do_not_const_check] // hooked by const-eval
+            const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
+                $crate::panicking::panic_display(arg)
+            }
+            panic_cold_display(&$arg);
+        }),
+        ($($t:tt)+) => ({
+            // Semicolon to prevent temporaries inside the formatting machinery from
+            // being considered alive in the caller after the panic_fmt call.
+            $crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
+        }),
     }
 }
 
 mod panicking {
-    #[lang = "panic_fmt"]
-    pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! {
+    #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
+    pub const fn panic_display<T: crate::fmt::Display>(x: &T) -> ! {
+        panic_fmt(crate::format_args!("{}", *x));
+    }
+
+    // This function is used instead of panic_fmt in const eval.
+    #[lang = "const_panic_fmt"]
+    pub const fn const_panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
+        if let Some(msg) = fmt.as_str() {
+            // The panic_display function is hooked by const eval.
+            panic_display(&msg);
+        } else {
+            loop {}
+        }
+    }
+
+    #[lang = "panic_fmt"] // needed for const-evaluated panics
+    pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
         loop {}
     }
 
@@ -1378,6 +1423,7 @@ mod panicking {
 }
 // endregion:panic
 
+#[macro_use]
 mod macros {
     // region:panic
     #[macro_export]
@@ -1470,7 +1516,6 @@ mod macros {
     }
     // endregion:unimplemented
 
-
     // region:derive
     pub(crate) mod builtin {
         #[rustc_builtin_macro]
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
index 45bb777d4d2..1dbccab370c 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
@@ -222,7 +222,7 @@ impl NotifyActor {
                         let depth = entry.depth();
                         let is_dir = entry.file_type().is_dir();
                         let is_file = entry.file_type().is_file();
-                        let abs_path = AbsPathBuf::try_from(entry.into_path()).unwrap();
+                        let abs_path = AbsPathBuf::try_from(entry.into_path()).ok()?;
                         if depth < 2 && is_dir {
                             self.send(make_message(abs_path.clone()));
                         }
diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
index c88f3466559..84f2110ebad 100644
--- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
 
 [dependencies]
 rustc-hash.workspace = true
+tracing.workspace = true
 fst = "0.4.7"
 indexmap.workspace = true
 nohash-hasher.workspace = true
@@ -21,4 +22,4 @@ paths.workspace = true
 stdx.workspace = true
 
 [lints]
-workspace = true
\ No newline at end of file
+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 ddd6bbe3f7a..b07e97cd6cd 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -46,7 +46,7 @@ pub mod loader;
 mod path_interner;
 mod vfs_path;
 
-use std::{fmt, mem};
+use std::{fmt, hash::BuildHasherDefault, mem};
 
 use crate::path_interner::PathInterner;
 
@@ -54,8 +54,13 @@ pub use crate::{
     anchored_path::{AnchoredPath, AnchoredPathBuf},
     vfs_path::VfsPath,
 };
+use indexmap::{map::Entry, IndexMap};
 pub use paths::{AbsPath, AbsPathBuf};
 
+use rustc_hash::FxHasher;
+use stdx::hash_once;
+use tracing::{span, Level};
+
 /// Handle to a file in [`Vfs`]
 ///
 /// Most functions in rust-analyzer use this when they need to refer to a file.
@@ -91,20 +96,13 @@ impl nohash_hasher::IsEnabled for FileId {}
 pub struct Vfs {
     interner: PathInterner,
     data: Vec<FileState>,
-    // FIXME: This should be a HashMap<FileId, ChangeFile>
-    // right now we do a nasty deduplication in GlobalState::process_changes that would be a lot
-    // easier to handle here on insertion.
-    changes: Vec<ChangedFile>,
-    // The above FIXME would then also get rid of this probably
-    created_this_cycle: Vec<FileId>,
+    changes: IndexMap<FileId, ChangedFile, BuildHasherDefault<FxHasher>>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
 pub enum FileState {
-    /// The file has been created this cycle.
-    Created,
-    /// The file exists.
-    Exists,
+    /// The file exists with the given content hash.
+    Exists(u64),
     /// The file is deleted.
     Deleted,
 }
@@ -127,23 +125,23 @@ impl ChangedFile {
     /// Returns `true` if the change is [`Create`](ChangeKind::Create) or
     /// [`Delete`](Change::Delete).
     pub fn is_created_or_deleted(&self) -> bool {
-        matches!(self.change, Change::Create(_) | Change::Delete)
+        matches!(self.change, Change::Create(_, _) | Change::Delete)
     }
 
     /// Returns `true` if the change is [`Create`](ChangeKind::Create).
     pub fn is_created(&self) -> bool {
-        matches!(self.change, Change::Create(_))
+        matches!(self.change, Change::Create(_, _))
     }
 
     /// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
     pub fn is_modified(&self) -> bool {
-        matches!(self.change, Change::Modify(_))
+        matches!(self.change, Change::Modify(_, _))
     }
 
     pub fn kind(&self) -> ChangeKind {
         match self.change {
-            Change::Create(_) => ChangeKind::Create,
-            Change::Modify(_) => ChangeKind::Modify,
+            Change::Create(_, _) => ChangeKind::Create,
+            Change::Modify(_, _) => ChangeKind::Modify,
             Change::Delete => ChangeKind::Delete,
         }
     }
@@ -153,9 +151,9 @@ impl ChangedFile {
 #[derive(Eq, PartialEq, Debug)]
 pub enum Change {
     /// The file was (re-)created
-    Create(Vec<u8>),
+    Create(Vec<u8>, u64),
     /// The file was modified
-    Modify(Vec<u8>),
+    Modify(Vec<u8>, u64),
     /// The file was deleted
     Delete,
 }
@@ -174,9 +172,7 @@ pub enum ChangeKind {
 impl Vfs {
     /// Id of the given path if it exists in the `Vfs` and is not deleted.
     pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
-        self.interner
-            .get(path)
-            .filter(|&it| matches!(self.get(it), FileState::Exists | FileState::Created))
+        self.interner.get(path).filter(|&it| matches!(self.get(it), FileState::Exists(_)))
     }
 
     /// File path corresponding to the given `file_id`.
@@ -194,9 +190,7 @@ impl Vfs {
     pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
         (0..self.data.len())
             .map(|it| FileId(it as u32))
-            .filter(move |&file_id| {
-                matches!(self.get(file_id), FileState::Exists | FileState::Created)
-            })
+            .filter(move |&file_id| matches!(self.get(file_id), FileState::Exists(_)))
             .map(move |file_id| {
                 let path = self.interner.lookup(file_id);
                 (file_id, path)
@@ -210,44 +204,79 @@ impl Vfs {
     /// If the path does not currently exists in the `Vfs`, allocates a new
     /// [`FileId`] for it.
     pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
+        let _p = span!(Level::INFO, "Vfs::set_file_contents").entered();
         let file_id = self.alloc_file_id(path);
         let state = self.get(file_id);
         let change_kind = match (state, contents) {
             (FileState::Deleted, None) => return false,
-            (FileState::Deleted, Some(v)) => Change::Create(v),
-            (FileState::Exists | FileState::Created, None) => Change::Delete,
-            (FileState::Exists | FileState::Created, Some(v)) => Change::Modify(v),
-        };
-        self.data[file_id.0 as usize] = match change_kind {
-            Change::Create(_) => {
-                self.created_this_cycle.push(file_id);
-                FileState::Created
+            (FileState::Deleted, Some(v)) => {
+                let hash = hash_once::<FxHasher>(&*v);
+                Change::Create(v, hash)
+            }
+            (FileState::Exists(_), None) => Change::Delete,
+            (FileState::Exists(hash), Some(v)) => {
+                let new_hash = hash_once::<FxHasher>(&*v);
+                if new_hash == hash {
+                    return false;
+                }
+                Change::Modify(v, new_hash)
             }
-            // If the file got created this cycle, make sure we keep it that way even
-            // if a modify comes in
-            Change::Modify(_) if matches!(state, FileState::Created) => FileState::Created,
-            Change::Modify(_) => FileState::Exists,
-            Change::Delete => FileState::Deleted,
         };
+
+        let mut set_data = |change_kind| {
+            self.data[file_id.0 as usize] = match change_kind {
+                &Change::Create(_, hash) | &Change::Modify(_, hash) => FileState::Exists(hash),
+                Change::Delete => FileState::Deleted,
+            };
+        };
+
         let changed_file = ChangedFile { file_id, change: change_kind };
-        self.changes.push(changed_file);
+        match self.changes.entry(file_id) {
+            // two changes to the same file in one cycle, merge them appropriately
+            Entry::Occupied(mut o) => {
+                use Change::*;
+
+                match (&mut o.get_mut().change, changed_file.change) {
+                    // newer `Delete` wins
+                    (change, Delete) => *change = Delete,
+                    // merge `Create` with `Create` or `Modify`
+                    (Create(prev, old_hash), Create(new, new_hash) | Modify(new, new_hash)) => {
+                        *prev = new;
+                        *old_hash = new_hash;
+                    }
+                    // collapse identical `Modify`es
+                    (Modify(prev, old_hash), Modify(new, new_hash)) => {
+                        *prev = new;
+                        *old_hash = new_hash;
+                    }
+                    // equivalent to `Modify`
+                    (change @ Delete, Create(new, new_hash)) => {
+                        *change = Modify(new, new_hash);
+                    }
+                    // shouldn't occur, but collapse into `Create`
+                    (change @ Delete, Modify(new, new_hash)) => {
+                        stdx::never!();
+                        *change = Create(new, new_hash);
+                    }
+                    // shouldn't occur, but keep the Create
+                    (prev @ Modify(_, _), new @ Create(_, _)) => *prev = new,
+                }
+                set_data(&o.get().change);
+            }
+            Entry::Vacant(v) => set_data(&v.insert(changed_file).change),
+        };
+
         true
     }
 
     /// Drain and returns all the changes in the `Vfs`.
-    pub fn take_changes(&mut self) -> Vec<ChangedFile> {
-        for file_id in self.created_this_cycle.drain(..) {
-            if self.data[file_id.0 as usize] == FileState::Created {
-                // downgrade the file from `Created` to `Exists` as the cycle is done
-                self.data[file_id.0 as usize] = FileState::Exists;
-            }
-        }
+    pub fn take_changes(&mut self) -> IndexMap<FileId, ChangedFile, BuildHasherDefault<FxHasher>> {
         mem::take(&mut self.changes)
     }
 
     /// Provides a panic-less way to verify file_id validity.
     pub fn exists(&self, file_id: FileId) -> bool {
-        matches!(self.get(file_id), FileState::Exists | FileState::Created)
+        matches!(self.get(file_id), FileState::Exists(_))
     }
 
     /// Returns the id associated with `path`
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index cdab6b09928..8897f02e277 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -229,12 +229,22 @@ Release steps:
      * publishes the VS Code extension to the marketplace
    * call the GitHub API for PR details
    * create a new changelog in `rust-analyzer.github.io`
-3. While the release is in progress, fill in the changelog
-4. Commit & push the changelog
+3. While the release is in progress, fill in the changelog.
+4. Commit & push the changelog.
 5. Run `cargo xtask publish-release-notes <CHANGELOG>` -- this will convert the changelog entry in AsciiDoc to Markdown and update the body of GitHub Releases entry.
-6. Tweet
-7. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
-   Self-approve the PR.
+6. Tweet.
+7. Make a new branch and run `cargo xtask rustc-pull`, open a PR, and merge it.
+   This will pull any changes from `rust-lang/rust` into `rust-analyzer`.
+8. Switch to `master`, pull, then run `cargo xtask rustc-push --rust-path ../rust-rust-analyzer --rust-fork matklad/rust`.
+   Replace `matklad/rust` with your own fork of `rust-lang/rust`.
+   You can use the token to authenticate when you get prompted for a password, since `josh` will push over HTTPS, not SSH.
+   This will push the `rust-analyzer` changes to your fork.
+   You can then open a PR against `rust-lang/rust`.
+
+Note: besides the `rust-rust-analyzer` clone, the Josh cache (stored under `~/.cache/rust-analyzer-josh`) will contain a bare clone of `rust-lang/rust`.
+This currently takes about 3.5 GB.
+
+This [HackMD](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg) has details about how `josh` syncs work.
 
 If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
 If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over.
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index f1815082e2e..46c1ccb79bf 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: dd51139b0530147e
+lsp/ext.rs hash: a39009c351009d16
 
 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:
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index a03ab0031d1..8993a46d2b8 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -9,6 +9,11 @@ for enum variants.
 --
 Placeholder expression to use for missing expressions in assists.
 --
+[[rust-analyzer.assist.termSearch.fuel]]rust-analyzer.assist.termSearch.fuel (default: `400`)::
++
+--
+Term search fuel in "units of work" for assists (Defaults to 400).
+--
 [[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`)::
 +
 --
@@ -256,7 +261,7 @@ by changing `#rust-analyzer.check.invocationStrategy#` and
 If `$saved_file` is part of the command, rust-analyzer will pass
 the absolute path of the saved file to the provided command. This is
 intended to be used with non-Cargo build systems.
-Note that `$saved_file` is experimental and may be removed in the futureg.
+Note that `$saved_file` is experimental and may be removed in the future.
 
 An example command would be:
 
@@ -373,6 +378,11 @@ Custom completion snippets.
 --
 Whether to enable term search based snippets like `Some(foo.bar().baz())`.
 --
+[[rust-analyzer.completion.termSearch.fuel]]rust-analyzer.completion.termSearch.fuel (default: `200`)::
++
+--
+Term search fuel in "units of work" for autocompletion (Defaults to 200).
+--
 [[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`)::
 +
 --
@@ -529,10 +539,15 @@ How to render the offset information in a memory layout hover.
 --
 How to render the size information in a memory layout hover.
 --
-[[rust-analyzer.hover.show.structFields]]rust-analyzer.hover.show.structFields (default: `null`)::
+[[rust-analyzer.hover.show.enumVariants]]rust-analyzer.hover.show.enumVariants (default: `5`)::
++
+--
+How many variants of an enum to display when hovering on. Show none if empty.
+--
+[[rust-analyzer.hover.show.fields]]rust-analyzer.hover.show.fields (default: `5`)::
 +
 --
-How many fields of a struct to display when hovering a struct.
+How many fields of a struct, variant or union to display when hovering on. Show none if empty.
 --
 [[rust-analyzer.hover.show.traitAssocItems]]rust-analyzer.hover.show.traitAssocItems (default: `null`)::
 +
@@ -778,7 +793,8 @@ Disable project auto-discovery in favor of explicitly specified set
 of projects.
 
 Elements must be paths pointing to `Cargo.toml`,
-`rust-project.json`, or JSON objects in `rust-project.json` format.
+`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON
+objects in `rust-project.json` format.
 --
 [[rust-analyzer.lru.capacity]]rust-analyzer.lru.capacity (default: `null`)::
 +
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 6521b6d8b36..8e6c53d0c5a 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -376,7 +376,7 @@ If you're running Neovim 0.10 or later, you can enable inlay hints via `on_attac
 ----
 lspconfig.rust_analyzer.setup({
     on_attach = function(client, bufnr)
-        vim.lsp.inlay_hint.enable(bufnr)
+        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
     end
 })
 ----
@@ -787,8 +787,6 @@ There are three ways to feed `rust-project.json` to rust-analyzer:
 
 Relative paths are interpreted relative to `rust-project.json` file location or (for inline JSON) relative to `rootUri`.
 
-See https://github.com/rust-analyzer/rust-project.json-example for a small example.
-
 You can set the `RA_LOG` environment variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
 
 Note that calls to `cargo check` are disabled when using `rust-project.json` by default, so compilation errors and warnings will no longer be sent to your LSP client.
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 389e1b8742c..6e4fedd992c 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -534,6 +534,12 @@
                         "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
                     ]
                 },
+                "rust-analyzer.assist.termSearch.fuel": {
+                    "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 400).",
+                    "default": 400,
+                    "type": "integer",
+                    "minimum": 0
+                },
                 "rust-analyzer.cachePriming.enable": {
                     "markdownDescription": "Warm up caches on project load.",
                     "default": true,
@@ -798,7 +804,7 @@
                     ]
                 },
                 "rust-analyzer.check.overrideCommand": {
-                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the futureg.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
+                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the future.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
                     "default": null,
                     "type": [
                         "null",
@@ -930,6 +936,12 @@
                     "default": false,
                     "type": "boolean"
                 },
+                "rust-analyzer.completion.termSearch.fuel": {
+                    "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 200).",
+                    "default": 200,
+                    "type": "integer",
+                    "minimum": 0
+                },
                 "rust-analyzer.diagnostics.disabled": {
                     "markdownDescription": "List of rust-analyzer diagnostics to disable.",
                     "default": [],
@@ -1145,9 +1157,18 @@
                         }
                     ]
                 },
-                "rust-analyzer.hover.show.structFields": {
-                    "markdownDescription": "How many fields of a struct to display when hovering a struct.",
-                    "default": null,
+                "rust-analyzer.hover.show.enumVariants": {
+                    "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.",
+                    "default": 5,
+                    "type": [
+                        "null",
+                        "integer"
+                    ],
+                    "minimum": 0
+                },
+                "rust-analyzer.hover.show.fields": {
+                    "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if empty.",
+                    "default": 5,
                     "type": [
                         "null",
                         "integer"
@@ -1495,7 +1516,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.linkedProjects": {
-                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.",
+                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON\nobjects in `rust-project.json` format.",
                     "default": [],
                     "type": "array",
                     "items": {
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index f76dec2629a..5b683dccdc2 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -433,7 +433,6 @@ export class Ctx implements RustAnalyzerExtensionApi {
         statusBar.tooltip.isTrusted = true;
         switch (status.health) {
             case "ok":
-                statusBar.tooltip.appendText(status.message ?? "Ready");
                 statusBar.color = undefined;
                 statusBar.backgroundColor = undefined;
                 if (this.config.statusBarClickAction === "stopServer") {
@@ -444,9 +443,6 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 this.dependencies?.refresh();
                 break;
             case "warning":
-                if (status.message) {
-                    statusBar.tooltip.appendText(status.message);
-                }
                 statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground");
                 statusBar.backgroundColor = new vscode.ThemeColor(
                     "statusBarItem.warningBackground",
@@ -455,9 +451,6 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 icon = "$(warning) ";
                 break;
             case "error":
-                if (status.message) {
-                    statusBar.tooltip.appendText(status.message);
-                }
                 statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground");
                 statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
                 statusBar.command = "rust-analyzer.openLogs";
@@ -476,6 +469,15 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 statusBar.text = "$(stop-circle) rust-analyzer";
                 return;
         }
+        if (status.message) {
+            statusBar.tooltip.appendText(status.message);
+        }
+        if (status.workspaceInfo) {
+            if (statusBar.tooltip.value) {
+                statusBar.tooltip.appendMarkdown("\n\n---\n\n");
+            }
+            statusBar.tooltip.appendMarkdown(status.workspaceInfo);
+        }
         if (statusBar.tooltip.value) {
             statusBar.tooltip.appendMarkdown("\n\n---\n\n");
         }
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index 9a7a4aae959..7d6b16b0197 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -241,6 +241,7 @@ export type ServerStatusParams = {
     health: "ok" | "warning" | "error";
     quiescent: boolean;
     message?: string;
+    workspaceInfo?: string;
 };
 export type SsrParams = {
     query: string;
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index 71e5933689a..53c64796f28 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -153,6 +153,14 @@ pub struct Notification {
     pub params: serde_json::Value,
 }
 
+fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
+    io::Error::new(io::ErrorKind::InvalidData, error)
+}
+
+macro_rules! invalid_data {
+    ($($tt:tt)*) => (invalid_data(format!($($tt)*)))
+}
+
 impl Message {
     pub fn read(r: &mut impl BufRead) -> io::Result<Option<Message>> {
         Message::_read(r)
@@ -162,7 +170,14 @@ impl Message {
             None => return Ok(None),
             Some(text) => text,
         };
-        let msg = serde_json::from_str(&text)?;
+
+        let msg = match serde_json::from_str(&text) {
+            Ok(msg) => msg,
+            Err(e) => {
+                return Err(invalid_data!("malformed LSP payload: {:?}", e));
+            }
+        };
+
         Ok(Some(msg))
     }
     pub fn write(self, w: &mut impl Write) -> io::Result<()> {
@@ -240,13 +255,6 @@ impl Notification {
 }
 
 fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
-    fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
-        io::Error::new(io::ErrorKind::InvalidData, error)
-    }
-    macro_rules! invalid_data {
-        ($($tt:tt)*) => (invalid_data(format!($($tt)*)))
-    }
-
     let mut size = None;
     let mut buf = String::new();
     loop {
@@ -264,12 +272,12 @@ fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
         let mut parts = buf.splitn(2, ": ");
         let header_name = parts.next().unwrap();
         let header_value =
-            parts.next().ok_or_else(|| invalid_data(format!("malformed header: {:?}", buf)))?;
+            parts.next().ok_or_else(|| invalid_data!("malformed header: {:?}", buf))?;
         if header_name.eq_ignore_ascii_case("Content-Length") {
             size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
         }
     }
-    let size: usize = size.ok_or_else(|| invalid_data("no Content-Length".to_owned()))?;
+    let size: usize = size.ok_or_else(|| invalid_data!("no Content-Length"))?;
     let mut buf = buf.into_bytes();
     buf.resize(size, 0);
     inp.read_exact(&mut buf)?;
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
new file mode 100644
index 00000000000..207ef6c5de7
--- /dev/null
+++ b/src/tools/rust-analyzer/rust-version
@@ -0,0 +1 @@
+6579ed89f0fcc26da71afdd11d30d63f6f812a0a
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index a83d32e4141..192de869472 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -8,6 +8,7 @@ rust-version.workspace = true
 
 [dependencies]
 anyhow.workspace = true
+directories = "5.0"
 flate2 = "1.0.24"
 write-json = "0.1.2"
 xshell.workspace = true
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 90665459208..dd7bfd0bda0 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -14,16 +14,16 @@ xflags::xflags! {
         cmd install {
             /// Install only VS Code plugin.
             optional --client
-            /// One of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'.
+            /// One of `code`, `code-exploration`, `code-insiders`, `codium`, or `code-oss`.
             optional --code-bin name: String
 
             /// Install only the language server.
             optional --server
-            /// Use mimalloc allocator for server
+            /// Use mimalloc allocator for server.
             optional --mimalloc
-            /// Use jemalloc allocator for server
+            /// Use jemalloc allocator for server.
             optional --jemalloc
-            /// build in release with debug info set to 2
+            /// build in release with debug info set to 2.
             optional --dev-rel
         }
 
@@ -32,9 +32,21 @@ xflags::xflags! {
         cmd release {
             optional --dry-run
         }
-        cmd promote {
-            optional --dry-run
+
+        cmd rustc-pull {
+            /// rustc commit to pull.
+            optional --commit refspec: String
+        }
+
+        cmd rustc-push {
+            /// rust local path, e.g. `../rust-rust-analyzer`.
+            required --rust-path rust_path: String
+            /// rust fork name, e.g.  `matklad/rust`.
+            required --rust-fork rust_fork: String
+            /// branch name.
+            optional --branch branch: String
         }
+
         cmd dist {
             /// Use mimalloc allocator for server
             optional --mimalloc
@@ -77,7 +89,8 @@ pub enum XtaskCmd {
     Install(Install),
     FuzzTests(FuzzTests),
     Release(Release),
-    Promote(Promote),
+    RustcPull(RustcPull),
+    RustcPush(RustcPush),
     Dist(Dist),
     PublishReleaseNotes(PublishReleaseNotes),
     Metrics(Metrics),
@@ -104,8 +117,15 @@ pub struct Release {
 }
 
 #[derive(Debug)]
-pub struct Promote {
-    pub dry_run: bool,
+pub struct RustcPull {
+    pub commit: Option<String>,
+}
+
+#[derive(Debug)]
+pub struct RustcPush {
+    pub rust_path: String,
+    pub rust_fork: String,
+    pub branch: Option<String>,
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs
index 9418675a348..e0705763035 100644
--- a/src/tools/rust-analyzer/xtask/src/main.rs
+++ b/src/tools/rust-analyzer/xtask/src/main.rs
@@ -34,7 +34,8 @@ fn main() -> anyhow::Result<()> {
         flags::XtaskCmd::Install(cmd) => cmd.run(sh),
         flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
         flags::XtaskCmd::Release(cmd) => cmd.run(sh),
-        flags::XtaskCmd::Promote(cmd) => cmd.run(sh),
+        flags::XtaskCmd::RustcPull(cmd) => cmd.run(sh),
+        flags::XtaskCmd::RustcPush(cmd) => cmd.run(sh),
         flags::XtaskCmd::Dist(cmd) => cmd.run(sh),
         flags::XtaskCmd::PublishReleaseNotes(cmd) => cmd.run(sh),
         flags::XtaskCmd::Metrics(cmd) => cmd.run(sh),
diff --git a/src/tools/rust-analyzer/xtask/src/release.rs b/src/tools/rust-analyzer/xtask/src/release.rs
index 1a5e6dfb4cc..5699053a23d 100644
--- a/src/tools/rust-analyzer/xtask/src/release.rs
+++ b/src/tools/rust-analyzer/xtask/src/release.rs
@@ -1,5 +1,12 @@
 mod changelog;
 
+use std::process::{Command, Stdio};
+use std::thread;
+use std::time::Duration;
+
+use anyhow::{bail, Context as _};
+use directories::ProjectDirs;
+use stdx::JodChild;
 use xshell::{cmd, Shell};
 
 use crate::{codegen, date_iso, flags, is_release_tag, project_root};
@@ -71,26 +78,167 @@ impl flags::Release {
     }
 }
 
-impl flags::Promote {
+// git sync implementation adapted from https://github.com/rust-lang/miri/blob/62039ac/miri-script/src/commands.rs
+impl flags::RustcPull {
     pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
-        let _dir = sh.push_dir("../rust-rust-analyzer");
-        cmd!(sh, "git switch master").run()?;
-        cmd!(sh, "git fetch upstream").run()?;
-        cmd!(sh, "git reset --hard upstream/master").run()?;
+        sh.change_dir(project_root());
+        let commit = self.commit.map(Result::Ok).unwrap_or_else(|| {
+            let rust_repo_head =
+                cmd!(sh, "git ls-remote https://github.com/rust-lang/rust/ HEAD").read()?;
+            rust_repo_head
+                .split_whitespace()
+                .next()
+                .map(|front| front.trim().to_owned())
+                .ok_or_else(|| anyhow::format_err!("Could not obtain Rust repo HEAD from remote."))
+        })?;
+        // Make sure the repo is clean.
+        if !cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty() {
+            bail!("working directory must be clean before running `cargo xtask pull`");
+        }
+        // This should not add any new root commits. So count those before and after merging.
+        let num_roots = || -> anyhow::Result<u32> {
+            Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
+                .read()
+                .context("failed to determine the number of root commits")?
+                .parse::<u32>()?)
+        };
+        let num_roots_before = num_roots()?;
+        // Make sure josh is running.
+        let josh = start_josh()?;
 
-        let date = date_iso(sh)?;
-        let branch = format!("rust-analyzer-{date}");
-        cmd!(sh, "git switch -c {branch}").run()?;
-        cmd!(sh, "git subtree pull -m ':arrow_up: rust-analyzer' -P src/tools/rust-analyzer rust-analyzer release").run()?;
+        // Update rust-version file. As a separate commit, since making it part of
+        // the merge has confused the heck out of josh in the past.
+        // We pass `--no-verify` to avoid running any git hooks that might exist,
+        // in case they dirty the repository.
+        sh.write_file("rust-version", format!("{commit}\n"))?;
+        const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rust-lang/rust";
+        cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
+            .run()
+            .context("FAILED to commit rust-version file, something went wrong")?;
 
-        if !self.dry_run {
-            cmd!(sh, "git push -u origin {branch}").run()?;
-            cmd!(
-                sh,
-                "xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost"
-            )
+        // Fetch given rustc commit.
+        cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
+            .run()
+            .map_err(|e| {
+                // Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
+                cmd!(sh, "git reset --hard HEAD^")
+                    .run()
+                    .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
+                e
+            })
+            .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
+
+        // Merge the fetched commit.
+        const MERGE_COMMIT_MESSAGE: &str = "Merge from rust-lang/rust";
+        cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
+            .run()
+            .context("FAILED to merge new commits, something went wrong")?;
+
+        // Check that the number of roots did not increase.
+        if num_roots()? != num_roots_before {
+            bail!("Josh created a new root commit. This is probably not the history you want.");
+        }
+
+        drop(josh);
+        Ok(())
+    }
+}
+
+impl flags::RustcPush {
+    pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
+        let branch = self.branch.as_deref().unwrap_or("sync-from-ra");
+        let rust_path = self.rust_path;
+        let rust_fork = self.rust_fork;
+
+        sh.change_dir(project_root());
+        let base = sh.read_file("rust-version")?.trim().to_owned();
+        // Make sure the repo is clean.
+        if !cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty() {
+            bail!("working directory must be clean before running `cargo xtask push`");
+        }
+        // Make sure josh is running.
+        let josh = start_josh()?;
+
+        // Find a repo we can do our preparation in.
+        sh.change_dir(rust_path);
+
+        // Prepare the branch. Pushing works much better if we use as base exactly
+        // the commit that we pulled from last time, so we use the `rust-version`
+        // file to find out which commit that would be.
+        println!("Preparing {rust_fork} (base: {base})...");
+        if cmd!(sh, "git fetch https://github.com/{rust_fork} {branch}")
+            .ignore_stderr()
+            .read()
+            .is_ok()
+        {
+            bail!(
+                "The branch `{branch}` seems to already exist in `https://github.com/{rust_fork}`. Please delete it and try again."
+            );
+        }
+        cmd!(sh, "git fetch https://github.com/rust-lang/rust {base}").run()?;
+        cmd!(sh, "git push https://github.com/{rust_fork} {base}:refs/heads/{branch}")
+            .ignore_stdout()
+            .ignore_stderr() // silence the "create GitHub PR" message
             .run()?;
+        println!();
+
+        // Do the actual push.
+        sh.change_dir(project_root());
+        println!("Pushing rust-analyzer changes...");
+        cmd!(
+            sh,
+            "git push http://localhost:{JOSH_PORT}/{rust_fork}.git{JOSH_FILTER}.git HEAD:{branch}"
+        )
+        .run()?;
+        println!();
+
+        // Do a round-trip check to make sure the push worked as expected.
+        cmd!(
+            sh,
+            "git fetch http://localhost:{JOSH_PORT}/{rust_fork}.git{JOSH_FILTER}.git {branch}"
+        )
+        .ignore_stderr()
+        .read()?;
+        let head = cmd!(sh, "git rev-parse HEAD").read()?;
+        let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
+        if head != fetch_head {
+            bail!("Josh created a non-roundtrip push! Do NOT merge this into rustc!");
         }
+        println!("Confirmed that the push round-trips back to rust-analyzer properly. Please create a rustc PR:");
+        // https://github.com/github-linguist/linguist/compare/master...octocat:linguist:master
+        let fork_path = rust_fork.replace('/', ":");
+        println!(
+            "    https://github.com/rust-lang/rust/compare/{fork_path}:{branch}?quick_pull=1&title=Subtree+update+of+rust-analyzer&body=r?+@ghost"
+        );
+
+        drop(josh);
         Ok(())
     }
 }
+
+/// Used for rustc syncs.
+const JOSH_FILTER: &str =
+    ":rev(55d9a533b309119c8acd13061581b43ae8840823:prefix=src/tools/rust-analyzer):/src/tools/rust-analyzer";
+const JOSH_PORT: &str = "42042";
+
+fn start_josh() -> anyhow::Result<impl Drop> {
+    // Determine cache directory.
+    let local_dir = {
+        let user_dirs = ProjectDirs::from("org", "rust-lang", "rust-analyzer-josh").unwrap();
+        user_dirs.cache_dir().to_owned()
+    };
+
+    // Start josh, silencing its output.
+    let mut cmd = Command::new("josh-proxy");
+    cmd.arg("--local").arg(local_dir);
+    cmd.arg("--remote").arg("https://github.com");
+    cmd.arg("--port").arg(JOSH_PORT);
+    cmd.arg("--no-background");
+    cmd.stdout(Stdio::null());
+    cmd.stderr(Stdio::null());
+    let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
+    // Give it some time so hopefully the port is open. (100ms was not enough.)
+    thread::sleep(Duration::from_millis(200));
+
+    Ok(JodChild(josh))
+}
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
new file mode 160000
+Subproject 4f313add609f43e928e98132358e8426ed3969a
diff --git a/src/tools/tidy/config/black.toml b/src/tools/tidy/config/black.toml
index 51a722979f5..e73847a93ba 100644
--- a/src/tools/tidy/config/black.toml
+++ b/src/tools/tidy/config/black.toml
@@ -11,5 +11,6 @@ extend-exclude = """(\
     src/doc/edition-guide/|\
     src/llvm-project/|\
     src/doc/embedded-book/|\
+    src/tools/rustc-perf/|\
     library/backtrace/
     )"""
diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml
index cf08c62648b..cf89ffd9ac7 100644
--- a/src/tools/tidy/config/ruff.toml
+++ b/src/tools/tidy/config/ruff.toml
@@ -26,6 +26,7 @@ extend-exclude = [
     "src/llvm-project/",
     "src/doc/embedded-book/",
     "library/backtrace/",
+    "src/tools/rustc-perf/",
     # Hack: CI runs from a subdirectory under the main checkout
     "../src/doc/nomicon/",
     "../src/tools/cargo/",
@@ -38,4 +39,5 @@ extend-exclude = [
     "../src/llvm-project/",
     "../src/doc/embedded-book/",
     "../library/backtrace/",
+    "../src/tools/rustc-perf/",
 ]
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index d1ae24007b3..9233dd8c89f 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -177,7 +177,6 @@ run-make/no-alloc-shim/Makefile
 run-make/no-builtins-attribute/Makefile
 run-make/no-builtins-lto/Makefile
 run-make/no-duplicate-libs/Makefile
-run-make/no-intermediate-extras/Makefile
 run-make/obey-crate-type-flag/Makefile
 run-make/optimization-remarks-dir-pgo/Makefile
 run-make/optimization-remarks-dir/Makefile
@@ -235,12 +234,8 @@ run-make/rmeta-preferred/Makefile
 run-make/rustc-macro-dep-files/Makefile
 run-make/rustdoc-io-error/Makefile
 run-make/rustdoc-scrape-examples-macros/Makefile
-run-make/rustdoc-scrape-examples-multiple/Makefile
-run-make/rustdoc-scrape-examples-test/Makefile
-run-make/rustdoc-scrape-examples-whitespace/Makefile
 run-make/rustdoc-verify-output-files/Makefile
 run-make/rustdoc-with-output-option/Makefile
-run-make/rustdoc-with-short-out-dir-option/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
 run-make/sanitizer-staticlib-link/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 1b73b67b755..efcd2a181ff 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -81,12 +81,10 @@ const EXCEPTIONS: ExceptionList = &[
     ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
     ("colored", "MPL-2.0"),                                  // rustfmt
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
-    ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), // opt-dist
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
     ("fortanix-sgx-abi", "MPL-2.0"),                         // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above.
     ("instant", "BSD-3-Clause"),                             // rustc_driver/tracing-subscriber/parking_lot
     ("mdbook", "MPL-2.0"),                                   // mdbook
-    ("openssl", "Apache-2.0"),                               // opt-dist
     ("option-ext", "MPL-2.0"),                               // cargo-miri (via `directories`)
     ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"),     // rustc (license is the same as LLVM uses)
     ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0                       // cargo/... (because of serde)
@@ -135,6 +133,7 @@ const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[
     // tidy-alphabetical-start
     ("dissimilar", "Apache-2.0"),
     ("notify", "CC0-1.0"),
+    ("option-ext", "MPL-2.0"),
     ("pulldown-cmark-to-cmark", "Apache-2.0"),
     ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"),
     ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 6e92dab1abc..e1c6c9a2dac 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -16,7 +16,7 @@ const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
 const ISSUES_ENTRY_LIMIT: usize = 1676;
-const ROOT_ENTRY_LIMIT: usize = 859;
+const ROOT_ENTRY_LIMIT: usize = 757;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 851c21f1c0f..f68b7675c76 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -18,6 +18,7 @@ pub fn filter_dirs(path: &Path) -> bool {
         "src/tools/clippy",
         "src/tools/miri",
         "src/tools/rust-analyzer",
+        "src/tools/rustc-perf",
         "src/tools/rustfmt",
         "src/doc/book",
         "src/doc/edition-guide",
diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs
new file mode 100644
index 00000000000..194c0adf1d2
--- /dev/null
+++ b/tests/codegen/array-cmp.rs
@@ -0,0 +1,18 @@
+// Ensure the asm for array comparisons is properly optimized.
+
+//@ compile-flags: -C opt-level=2
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @compare
+// CHECK: start:
+// CHECK-NEXT: ret i1 true
+#[no_mangle]
+pub fn compare() -> bool {
+    let bytes = 12.5f32.to_ne_bytes();
+    bytes == if cfg!(target_endian = "big") {
+        [0x41, 0x48, 0x00, 0x00]
+    } else {
+        [0x00, 0x00, 0x48, 0x41]
+    }
+}
diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs
index 7a175dc4f7e..c6b77363a4e 100644
--- a/tests/codegen/vec-in-place.rs
+++ b/tests/codegen/vec-in-place.rs
@@ -90,3 +90,25 @@ pub fn vec_iterator_cast_deaggregate_fold(vec: Vec<Baz>) -> Vec<[u64; 4]> {
     // correct.
     vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
 }
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap_drop
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+
+    vec.into_iter().map(|Wrapper(e)| e).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrap_drop
+#[no_mangle]
+pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+
+    vec.into_iter().map(Wrapper).collect()
+}
diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map
index 1c36f2871dd..5673fa98ca6 100644
--- a/tests/coverage/abort.cov-map
+++ b/tests/coverage/abort.cov-map
@@ -1,45 +1,37 @@
 Function name: abort::main
-Raw bytes (105): 0x[01, 01, 12, 01, 47, 05, 09, 03, 0d, 42, 11, 03, 0d, 11, 3e, 42, 11, 03, 0d, 3b, 15, 11, 3e, 42, 11, 03, 0d, 15, 36, 3b, 15, 11, 3e, 42, 11, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 42, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 3e, 02, 0a, 00, 0b, 3b, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 36, 00, 31, 00, 32, 33, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 47, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
+Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 18
-- expression 0 operands: lhs = Counter(0), rhs = Expression(17, Add)
+Number of expressions: 10
+- expression 0 operands: lhs = Counter(0), rhs = Expression(9, Add)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 3 operands: lhs = Expression(8, Sub), rhs = Counter(4)
 - expression 4 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(4), rhs = Expression(15, Sub)
-- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 6 operands: lhs = Expression(8, Sub), rhs = Counter(5)
 - expression 7 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Expression(14, Add), rhs = Counter(5)
-- expression 9 operands: lhs = Counter(4), rhs = Expression(15, Sub)
-- expression 10 operands: lhs = Expression(16, Sub), rhs = Counter(4)
-- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(5), rhs = Expression(13, Sub)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(5)
-- expression 14 operands: lhs = Counter(4), rhs = Expression(15, Sub)
-- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(4)
-- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 17 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 13
 - Code(Counter(0)) at (prev + 14, 1) to (start + 1, 27)
 - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
     = (c0 + (c1 + c2))
-- Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25)
     = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10)
-- Code(Expression(15, Sub)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(3, Sub)) at (prev + 2, 10) to (start + 0, 11)
     = (((c0 + (c1 + c2)) - c3) - c4)
-- Code(Expression(14, Add)) at (prev + 2, 12) to (start + 0, 25)
-    = (c4 + (((c0 + (c1 + c2)) - c3) - c4))
+- Code(Expression(8, Sub)) at (prev + 2, 12) to (start + 0, 25)
+    = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49)
-- Code(Expression(13, Sub)) at (prev + 0, 49) to (start + 0, 50)
-    = ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5)
-- Code(Expression(12, Add)) at (prev + 4, 12) to (start + 0, 25)
-    = (c5 + ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5))
+- Code(Expression(6, Sub)) at (prev + 0, 49) to (start + 0, 50)
+    = (((c0 + (c1 + c2)) - c3) - c5)
+- Code(Expression(8, Sub)) at (prev + 4, 12) to (start + 0, 25)
+    = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49)
 - Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50)
-- Code(Expression(17, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(9, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (c1 + c2)
 - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2)
 
diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map
index e06d1676358..7d16372375a 100644
--- a/tests/coverage/async.cov-map
+++ b/tests/coverage/async.cov-map
@@ -7,19 +7,17 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 9, 1) to (start + 0, 25)
 
 Function name: async::c::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 09, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 09, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 9, 25) to (start + 1, 14)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: async::d
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 14]
@@ -188,19 +186,17 @@ Number of file 0 mappings: 9
     = ((c1 + c2) + c3)
 
 Function name: async::j::c
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 55, 5) to (start + 1, 18)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14)
 - Code(Expression(0, Sub)) at (prev + 10, 13) to (start + 0, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: async::j::d
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 46, 05, 00, 17]
diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map
index 28f319bfb80..e39a1d7dd2f 100644
--- a/tests/coverage/async2.cov-map
+++ b/tests/coverage/async2.cov-map
@@ -7,17 +7,15 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)
 
 Function name: async2::async_func::{closure#0}
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: async2::async_func_just_println
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]
@@ -44,15 +42,13 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 25, 1) to (start + 7, 2)
 
 Function name: async2::non_async_func
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 05, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 05, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 5, 1) to (start + 3, 9)
 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map
index 104133f6e67..e54c15c0436 100644
--- a/tests/coverage/async_block.cov-map
+++ b/tests/coverage/async_block.cov-map
@@ -1,10 +1,9 @@
 Function name: async_block::main
-Raw bytes (38): 0x[01, 01, 02, 01, 05, 03, 05, 06, 01, 05, 01, 00, 0b, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 13, 05, 00, 14, 01, 16, 05, 07, 0a, 02, 06, 06, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 05, 01, 00, 0b, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 13, 05, 00, 14, 01, 16, 05, 07, 0a, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 5, 1) to (start + 0, 11)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
@@ -12,21 +11,18 @@ Number of file 0 mappings: 6
     = (c0 + c1)
 - Code(Counter(1)) at (prev + 0, 20) to (start + 1, 22)
 - Code(Counter(1)) at (prev + 7, 10) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c0 + c1) - c1)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: async_block::main::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 07, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 07, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 7, 28) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
diff --git a/tests/coverage/branch/generics.cov-map b/tests/coverage/branch/generics.cov-map
index d729b0c260a..2e5668c8b56 100644
--- a/tests/coverage/branch/generics.cov-map
+++ b/tests/coverage/branch/generics.cov-map
@@ -1,10 +1,9 @@
 Function name: generics::print_size::<()>
-Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
@@ -13,16 +12,14 @@ Number of file 0 mappings: 5
 - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: generics::print_size::<u32>
-Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
@@ -31,16 +28,14 @@ Number of file 0 mappings: 5
 - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: generics::print_size::<u64>
-Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
@@ -49,6 +44,5 @@ Number of file 0 mappings: 5
 - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map
index 0c7d986933e..0b098bc6497 100644
--- a/tests/coverage/branch/if-let.cov-map
+++ b/tests/coverage/branch/if-let.cov-map
@@ -1,10 +1,9 @@
 Function name: if_let::if_let
-Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02]
+Raw bytes (43): 0x[01, 01, 01, 05, 09, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 05, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 12) to (start + 0, 19)
@@ -16,8 +15,7 @@ Number of file 0 mappings: 7
 - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6)
     = (c1 - c2)
 - Code(Counter(2)) at (prev + 2, 12) to (start + 2, 6)
-- Code(Expression(1, Add)) at (prev + 3, 5) to (start + 1, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 3, 5) to (start + 1, 2)
 
 Function name: if_let::if_let_chain
 Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02]
diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map
index 50f6216e069..7f4ee980e26 100644
--- a/tests/coverage/branch/if.cov-map
+++ b/tests/coverage/branch/if.cov-map
@@ -24,51 +24,17 @@ Number of file 0 mappings: 8
     = (c4 + (c3 + (c1 - c2)))
 
 Function name: if::branch_not
-Raw bytes (224): 0x[01, 01, 29, 05, 09, 09, 02, a3, 01, 0d, 09, 02, a3, 01, 0d, 09, 02, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 15, 8e, 01, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, a3, 01, 01, 08, 00, 0a, 20, 9e, 01, 0d, 00, 08, 00, 0a, 9e, 01, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 9b, 01, 01, 08, 00, 0b, 20, 11, 96, 01, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 96, 01, 02, 06, 00, 07, 93, 01, 01, 08, 00, 0c, 20, 8e, 01, 15, 00, 08, 00, 0c, 8e, 01, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 8b, 01, 01, 01, 00, 02]
+Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 06, 00, 07, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 05, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 41
+Number of expressions: 7
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 6 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 7 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 9 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 10 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 11 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 13 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 15 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 17 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 18 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 19 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 20 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 22 operands: lhs = Expression(36, Add), rhs = Counter(5)
-- expression 23 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 24 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 25 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 26 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 27 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(5)
-- expression 29 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 30 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 31 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 33 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 34 operands: lhs = Counter(5), rhs = Expression(35, Sub)
-- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(5)
-- expression 36 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 37 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 38 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 40 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 5 operands: lhs = Counter(1), rhs = Counter(5)
+- expression 6 operands: lhs = Counter(1), rhs = Counter(5)
 Number of file 0 mappings: 18
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
@@ -78,60 +44,39 @@ Number of file 0 mappings: 18
 - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17)
 - Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7)
     = (c1 - c2)
-- Code(Expression(40, Add)) at (prev + 1, 8) to (start + 0, 10)
-    = (c2 + (c1 - c2))
-- Branch { true: Expression(39, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10)
-    true  = ((c2 + (c1 - c2)) - c3)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 10)
+- Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10)
+    true  = (c1 - c3)
     false = c3
-- Code(Expression(39, Sub)) at (prev + 0, 11) to (start + 2, 6)
-    = ((c2 + (c1 - c2)) - c3)
+- Code(Expression(2, Sub)) at (prev + 0, 11) to (start + 2, 6)
+    = (c1 - c3)
 - Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(38, Add)) at (prev + 1, 8) to (start + 0, 11)
-    = (c3 + ((c2 + (c1 - c2)) - c3))
-- Branch { true: Counter(4), false: Expression(37, Sub) } at (prev + 0, 8) to (start + 0, 11)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 11)
+- Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 8) to (start + 0, 11)
     true  = c4
-    false = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+    false = (c1 - c4)
 - Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6)
-- Code(Expression(37, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
-- Code(Expression(36, Add)) at (prev + 1, 8) to (start + 0, 12)
-    = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4))
-- Branch { true: Expression(35, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12)
-    true  = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)
+- Code(Expression(4, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = (c1 - c4)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 12)
+- Branch { true: Expression(6, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12)
+    true  = (c1 - c5)
     false = c5
-- Code(Expression(35, Sub)) at (prev + 0, 13) to (start + 2, 6)
-    = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)
+- Code(Expression(6, Sub)) at (prev + 0, 13) to (start + 2, 6)
+    = (c1 - c5)
 - Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(34, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c5 + ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5))
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: if::branch_not_as
-Raw bytes (124): 0x[01, 01, 16, 05, 09, 09, 02, 57, 0d, 09, 02, 57, 0d, 09, 02, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 11, 4a, 4f, 11, 0d, 52, 57, 0d, 09, 02, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 57, 01, 08, 00, 15, 20, 0d, 52, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 52, 02, 06, 00, 07, 4f, 01, 08, 00, 16, 20, 4a, 11, 00, 08, 00, 16, 4a, 00, 17, 02, 06, 11, 02, 06, 00, 07, 47, 01, 01, 00, 02]
+Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 06, 00, 07, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 06, 00, 07, 05, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 22
+Number of expressions: 5
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 6 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 7 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 9 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 10 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 11 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 13 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 15 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 17 operands: lhs = Counter(4), rhs = Expression(18, Sub)
-- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 19 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(4)
 Number of file 0 mappings: 14
 - Code(Counter(0)) at (prev + 29, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 20)
@@ -141,24 +86,21 @@ Number of file 0 mappings: 14
 - Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6)
     = (c1 - c2)
 - Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(21, Add)) at (prev + 1, 8) to (start + 0, 21)
-    = (c2 + (c1 - c2))
-- Branch { true: Counter(3), false: Expression(20, Sub) } at (prev + 0, 8) to (start + 0, 21)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 21)
+- Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 8) to (start + 0, 21)
     true  = c3
-    false = ((c2 + (c1 - c2)) - c3)
+    false = (c1 - c3)
 - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6)
-- Code(Expression(20, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = ((c2 + (c1 - c2)) - c3)
-- Code(Expression(19, Add)) at (prev + 1, 8) to (start + 0, 22)
-    = (c3 + ((c2 + (c1 - c2)) - c3))
-- Branch { true: Expression(18, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22)
-    true  = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Expression(2, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = (c1 - c3)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 22)
+- Branch { true: Expression(4, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22)
+    true  = (c1 - c4)
     false = c4
-- Code(Expression(18, Sub)) at (prev + 0, 23) to (start + 2, 6)
-    = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 2, 6)
+    = (c1 - c4)
 - Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(17, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4))
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: if::branch_or
 Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map
index e2d731022d7..09ce9137673 100644
--- a/tests/coverage/branch/lazy-boolean.cov-map
+++ b/tests/coverage/branch/lazy-boolean.cov-map
@@ -1,44 +1,35 @@
 Function name: lazy_boolean::branch_and
-Raw bytes (42): 0x[01, 01, 03, 09, 0a, 05, 09, 05, 09, 06, 01, 13, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 0a, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 03, 01, 05, 01, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 13, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 02, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 05, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
-- expression 0 operands: lhs = Counter(2), rhs = Expression(2, Sub)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 19, 1) to (start + 1, 16)
-- Code(Expression(0, Add)) at (prev + 4, 9) to (start + 0, 10)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
     false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19)
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2)
 
 Function name: lazy_boolean::branch_or
-Raw bytes (44): 0x[01, 01, 04, 09, 0e, 05, 09, 05, 09, 05, 09, 06, 01, 1b, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 03, 01, 05, 01, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 1b, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 05, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Counter(2), rhs = Expression(3, Sub)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 27, 1) to (start + 1, 16)
-- Code(Expression(0, Add)) at (prev + 4, 9) to (start + 0, 10)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
     false = (c1 - c2)
-- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
     = (c1 - c2)
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2)
 
 Function name: lazy_boolean::chain
 Raw bytes (149): 0x[01, 01, 13, 11, 07, 0b, 16, 15, 1a, 09, 0d, 05, 09, 05, 09, 09, 0d, 47, 25, 4b, 21, 19, 1d, 03, 19, 03, 19, 3e, 1d, 03, 19, 3e, 1d, 03, 19, 47, 25, 4b, 21, 19, 1d, 13, 01, 24, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 16, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 1a, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 15, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 03, 01, 05, 00, 11, 43, 03, 09, 00, 0a, 03, 00, 0d, 00, 12, 20, 19, 3e, 00, 0d, 00, 12, 3e, 00, 16, 00, 1b, 20, 1d, 3a, 00, 16, 00, 1b, 3a, 00, 1f, 00, 24, 20, 21, 25, 00, 1f, 00, 24, 25, 00, 28, 00, 2d, 43, 01, 05, 01, 02]
@@ -105,73 +96,71 @@ Number of file 0 mappings: 19
     = (((c6 + c7) + c8) + c9)
 
 Function name: lazy_boolean::nested_mixed
-Raw bytes (159): 0x[01, 01, 18, 07, 22, 11, 36, 3b, 11, 09, 0d, 26, 0d, 05, 09, 05, 09, 05, 09, 26, 0d, 05, 09, 09, 0d, 3b, 11, 09, 0d, 3b, 11, 09, 0d, 19, 5f, 1d, 21, 03, 15, 15, 19, 52, 56, 15, 19, 03, 15, 19, 5f, 1d, 21, 13, 01, 31, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 26, 00, 0e, 00, 13, 26, 00, 17, 00, 1d, 20, 0d, 22, 00, 17, 00, 1d, 3b, 00, 23, 00, 28, 20, 11, 36, 00, 23, 00, 28, 36, 00, 2c, 00, 33, 03, 01, 05, 00, 11, 5b, 03, 09, 00, 0a, 03, 00, 0e, 00, 13, 20, 15, 56, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 52, 00, 17, 00, 1c, 4f, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 5b, 01, 05, 01, 02]
+Raw bytes (155): 0x[01, 01, 16, 33, 1a, 09, 0d, 1e, 0d, 05, 09, 05, 09, 05, 09, 1e, 0d, 05, 09, 09, 0d, 33, 11, 09, 0d, 33, 11, 09, 0d, 19, 57, 1d, 21, 03, 15, 15, 19, 4a, 4e, 15, 19, 03, 15, 19, 57, 1d, 21, 13, 01, 31, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 1e, 00, 0e, 00, 13, 1e, 00, 17, 00, 1d, 20, 0d, 1a, 00, 17, 00, 1d, 33, 00, 23, 00, 28, 20, 11, 2e, 00, 23, 00, 28, 2e, 00, 2c, 00, 33, 03, 01, 05, 00, 11, 53, 03, 09, 00, 0a, 03, 00, 0e, 00, 13, 20, 15, 4e, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 4a, 00, 17, 00, 1c, 47, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 53, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 24
-- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(8, Sub)
-- expression 1 operands: lhs = Counter(4), rhs = Expression(13, Sub)
-- expression 2 operands: lhs = Expression(14, Add), rhs = Counter(4)
-- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 4 operands: lhs = Expression(9, Sub), rhs = Counter(3)
+Number of expressions: 22
+- expression 0 operands: lhs = Expression(12, Add), rhs = Expression(6, Sub)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(7, Sub), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 5 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(3)
 - expression 7 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 8 operands: lhs = Expression(9, Sub), rhs = Counter(3)
-- expression 9 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(4)
 - expression 10 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 11 operands: lhs = Expression(14, Add), rhs = Counter(4)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(4)
 - expression 12 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 15 operands: lhs = Counter(6), rhs = Expression(23, Add)
-- expression 16 operands: lhs = Counter(7), rhs = Counter(8)
-- expression 17 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 13 operands: lhs = Counter(6), rhs = Expression(21, Add)
+- expression 14 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 15 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 16 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 17 operands: lhs = Expression(18, Sub), rhs = Expression(19, Sub)
 - expression 18 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 19 operands: lhs = Expression(20, Sub), rhs = Expression(21, Sub)
-- expression 20 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 21 operands: lhs = Expression(0, Add), rhs = Counter(5)
-- expression 22 operands: lhs = Counter(6), rhs = Expression(23, Add)
-- expression 23 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 19 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 20 operands: lhs = Counter(6), rhs = Expression(21, Add)
+- expression 21 operands: lhs = Counter(7), rhs = Counter(8)
 Number of file 0 mappings: 19
 - Code(Counter(0)) at (prev + 49, 1) to (start + 1, 16)
 - Code(Expression(0, Add)) at (prev + 4, 9) to (start + 0, 10)
-    = ((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3))
+    = ((c2 + c3) + ((c1 - c2) - c3))
 - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19)
-- Branch { true: Counter(2), false: Expression(9, Sub) } at (prev + 0, 14) to (start + 0, 19)
+- Branch { true: Counter(2), false: Expression(7, Sub) } at (prev + 0, 14) to (start + 0, 19)
     true  = c2
     false = (c1 - c2)
-- Code(Expression(9, Sub)) at (prev + 0, 23) to (start + 0, 29)
+- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 29)
     = (c1 - c2)
-- Branch { true: Counter(3), false: Expression(8, Sub) } at (prev + 0, 23) to (start + 0, 29)
+- Branch { true: Counter(3), false: Expression(6, Sub) } at (prev + 0, 23) to (start + 0, 29)
     true  = c3
     false = ((c1 - c2) - c3)
-- Code(Expression(14, Add)) at (prev + 0, 35) to (start + 0, 40)
+- Code(Expression(12, Add)) at (prev + 0, 35) to (start + 0, 40)
     = (c2 + c3)
-- Branch { true: Counter(4), false: Expression(13, Sub) } at (prev + 0, 35) to (start + 0, 40)
+- Branch { true: Counter(4), false: Expression(11, Sub) } at (prev + 0, 35) to (start + 0, 40)
     true  = c4
     false = ((c2 + c3) - c4)
-- Code(Expression(13, Sub)) at (prev + 0, 44) to (start + 0, 51)
+- Code(Expression(11, Sub)) at (prev + 0, 44) to (start + 0, 51)
     = ((c2 + c3) - c4)
 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 17)
-    = ((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3))
-- Code(Expression(22, Add)) at (prev + 3, 9) to (start + 0, 10)
+    = ((c2 + c3) + ((c1 - c2) - c3))
+- Code(Expression(20, Add)) at (prev + 3, 9) to (start + 0, 10)
     = (c6 + (c7 + c8))
 - Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 19)
-    = ((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3))
-- Branch { true: Counter(5), false: Expression(21, Sub) } at (prev + 0, 14) to (start + 0, 19)
+    = ((c2 + c3) + ((c1 - c2) - c3))
+- Branch { true: Counter(5), false: Expression(19, Sub) } at (prev + 0, 14) to (start + 0, 19)
     true  = c5
-    false = (((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3)) - c5)
+    false = (((c2 + c3) + ((c1 - c2) - c3)) - c5)
 - Code(Counter(5)) at (prev + 0, 23) to (start + 0, 28)
-- Branch { true: Counter(6), false: Expression(20, Sub) } at (prev + 0, 23) to (start + 0, 28)
+- Branch { true: Counter(6), false: Expression(18, Sub) } at (prev + 0, 23) to (start + 0, 28)
     true  = c6
     false = (c5 - c6)
-- Code(Expression(19, Add)) at (prev + 0, 34) to (start + 0, 40)
-    = ((c5 - c6) + (((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3)) - c5))
+- Code(Expression(17, Add)) at (prev + 0, 34) to (start + 0, 40)
+    = ((c5 - c6) + (((c2 + c3) + ((c1 - c2) - c3)) - c5))
 - Branch { true: Counter(7), false: Counter(8) } at (prev + 0, 34) to (start + 0, 40)
     true  = c7
     false = c8
 - Code(Counter(7)) at (prev + 0, 44) to (start + 0, 51)
-- Code(Expression(22, Add)) at (prev + 1, 5) to (start + 1, 2)
+- Code(Expression(20, Add)) at (prev + 1, 5) to (start + 1, 2)
     = (c6 + (c7 + c8))
 
diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map
index c7f7adddbc2..07079934464 100644
--- a/tests/coverage/branch/let-else.cov-map
+++ b/tests/coverage/branch/let-else.cov-map
@@ -1,10 +1,9 @@
 Function name: let_else::let_else
-Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 07, 01, 01, 00, 02]
+Raw bytes (43): 0x[01, 01, 01, 05, 09, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 05, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 9) to (start + 0, 16)
@@ -16,6 +15,5 @@ Number of file 0 mappings: 7
 - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15)
 - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 11)
     = (c1 - c2)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map
index 5a3ef096bed..fd05bbb69a5 100644
--- a/tests/coverage/branch/while.cov-map
+++ b/tests/coverage/branch/while.cov-map
@@ -1,42 +1,36 @@
 Function name: while::while_cond
-Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 0c, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 10, 20, 09, 0a, 00, 0b, 00, 10, 09, 00, 11, 02, 06, 0a, 03, 01, 00, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 0c, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 10, 20, 09, 05, 00, 0b, 00, 10, 09, 00, 11, 02, 06, 05, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18)
 - Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 16)
     = (c1 + c2)
-- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 16)
+- Branch { true: Counter(2), false: Counter(1) } at (prev + 0, 11) to (start + 0, 16)
     true  = c2
-    false = ((c1 + c2) - c2)
+    false = c1
 - Code(Counter(2)) at (prev + 0, 17) to (start + 2, 6)
-- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c1 + c2) - c2)
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: while::while_cond_not
-Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 0a, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 0a, 03, 01, 00, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 05, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 05, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 21, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18)
 - Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 20)
     = (c1 + c2)
-- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 20)
+- Branch { true: Counter(2), false: Counter(1) } at (prev + 0, 11) to (start + 0, 20)
     true  = c2
-    false = ((c1 + c2) - c2)
+    false = c1
 - Code(Counter(2)) at (prev + 0, 21) to (start + 2, 6)
-- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c1 + c2) - c2)
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: while::while_op_and
 Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 11, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02]
diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map
index 9f0d33745bc..f36ef7af7ac 100644
--- a/tests/coverage/closure.cov-map
+++ b/tests/coverage/closure.cov-map
@@ -1,10 +1,9 @@
 Function name: closure::main
-Raw bytes (128): 0x[01, 01, 02, 01, 05, 05, 02, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 07, 01, 05, 03, 02]
+Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 01, 01, 05, 03, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 24
 - Code(Counter(0)) at (prev + 9, 1) to (start + 15, 13)
 - Code(Counter(0)) at (prev + 22, 14) to (start + 6, 10)
@@ -30,8 +29,7 @@ Number of file 0 mappings: 24
 - Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6)
 - Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 3, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2)
 
 Function name: closure::main::{closure#0} (unused)
 Raw bytes (24): 0x[01, 01, 00, 04, 00, 28, 05, 02, 14, 00, 02, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06]
@@ -77,72 +75,60 @@ Number of file 0 mappings: 1
 - Code(Zero) at (prev + 172, 13) to (start + 2, 14)
 
 Function name: closure::main::{closure#14}
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e]
+Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 179, 13) to (start + 2, 27)
 - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37)
 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14)
 
 Function name: closure::main::{closure#15}
-Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a]
+Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
-- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 187, 9) to (start + 0, 10)
-- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21)
 - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
 - Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
-- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+- Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(0, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
 
 Function name: closure::main::{closure#16}
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e]
+Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 197, 13) to (start + 2, 27)
 - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37)
 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14)
 
 Function name: closure::main::{closure#17}
-Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a]
+Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
-- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 205, 9) to (start + 0, 10)
-- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21)
 - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
 - Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
-- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+- Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(0, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
 
 Function name: closure::main::{closure#18} (unused)
 Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 12, 00, 13, 00, 01, 11, 01, 0e]
@@ -156,49 +142,43 @@ Number of file 0 mappings: 4
 - Code(Zero) at (prev + 1, 17) to (start + 1, 14)
 
 Function name: closure::main::{closure#19}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 01, 01, 11, 01, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 67, 13) to (start + 2, 28)
 - Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18)
 - Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 17) to (start + 1, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14)
 
 Function name: closure::main::{closure#1}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 82, 5) to (start + 2, 20)
 - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6)
 
 Function name: closure::main::{closure#2}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 104, 5) to (start + 2, 20)
 - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6)
 
 Function name: closure::main::{closure#3} (unused)
 Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06]
diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map
index 160b348bd63..32e8db5fb2f 100644
--- a/tests/coverage/closure_bug.cov-map
+++ b/tests/coverage/closure_bug.cov-map
@@ -1,133 +1,84 @@
 Function name: closure_bug::main
-Raw bytes (201): 0x[01, 01, 26, 01, 05, 05, 02, 05, 02, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 82, 01, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 97, 01, 02, 09, 00, 0a, 97, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 92, 01, 00, 17, 00, 18, 8f, 01, 02, 09, 00, 0a, 8f, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 8a, 01, 00, 17, 00, 18, 87, 01, 02, 09, 00, 0a, 87, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 82, 01, 00, 17, 00, 18, 7f, 01, 01, 00, 02]
+Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 17, 00, 18, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 38
+Number of expressions: 4
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 3 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 5 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 6 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 7 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 9 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 11 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 13 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 14 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 15 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 16 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 17 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 18 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 19 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 20 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 21 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 22 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 23 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 24 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 25 operands: lhs = Expression(33, Add), rhs = Counter(4)
-- expression 26 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 27 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 28 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 29 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 30 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 31 operands: lhs = Counter(4), rhs = Expression(32, Sub)
-- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(4)
-- expression 33 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 35 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 37 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(0), rhs = Counter(4)
 Number of file 0 mappings: 17
 - Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10)
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14)
 - Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23)
 - Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 24)
     = (c0 - c1)
-- Code(Expression(37, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
-- Code(Expression(37, Add)) at (prev + 6, 5) to (start + 1, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14)
 - Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23)
-- Code(Expression(36, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(35, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(35, Add)) at (prev + 6, 5) to (start + 1, 14)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14)
 - Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23)
-- Code(Expression(34, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
-- Code(Expression(33, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
-- Code(Expression(33, Add)) at (prev + 6, 5) to (start + 1, 14)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c3)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14)
 - Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23)
-- Code(Expression(32, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)
-- Code(Expression(31, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Expression(3, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c4)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: closure_bug::main::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 14, 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))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
 Function name: closure_bug::main::{closure#1}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 23, 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))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
 Function name: closure_bug::main::{closure#2}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 32, 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))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
 Function name: closure_bug::main::{closure#3}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 41, 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))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map
index e43ed1f76f3..fd8fbd9fa75 100644
--- a/tests/coverage/closure_macro.cov-map
+++ b/tests/coverage/closure_macro.cov-map
@@ -7,12 +7,11 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2)
 
 Function name: closure_macro::main
-Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18)
@@ -22,8 +21,7 @@ Number of file 0 mappings: 6
 - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: closure_macro::main::{closure#0}
 Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map
index 212b67a8a3e..43b52008f33 100644
--- a/tests/coverage/closure_macro_async.cov-map
+++ b/tests/coverage/closure_macro_async.cov-map
@@ -15,12 +15,11 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43)
 
 Function name: closure_macro_async::test::{closure#0}
-Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18)
@@ -30,8 +29,7 @@ Number of file 0 mappings: 6
 - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: closure_macro_async::test::{closure#0}::{closure#0}
 Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map
index a6a427aca00..17143775b7b 100644
--- a/tests/coverage/conditions.cov-map
+++ b/tests/coverage/conditions.cov-map
@@ -1,259 +1,263 @@
 Function name: conditions::main
-Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, 31, ab, 04, 2d, 25, 29, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 04, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02]
+Raw bytes (799): 0x[01, 01, 94, 01, 09, 2b, 2f, 41, 33, 3d, 35, 39, 01, 09, 0d, 35, 1e, 39, 0d, 35, 33, 3d, 35, 39, 2f, 41, 33, 3d, 35, 39, ce, 04, 0d, 01, 09, 03, 49, 62, 31, 03, 49, 5e, 4d, 62, 31, 03, 49, 5a, 51, 5e, 4d, 62, 31, 03, 49, 87, 01, 55, 4d, 51, 83, 01, 59, 87, 01, 55, 4d, 51, 49, 7f, 83, 01, 59, 87, 01, 55, 4d, 51, 5d, 65, ae, 01, 2d, 5d, 65, aa, 01, 69, ae, 01, 2d, 5d, 65, a6, 01, 6d, aa, 01, 69, ae, 01, 2d, 5d, 65, f3, 02, 71, 69, 6d, ef, 02, 75, f3, 02, 71, 69, 6d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, d6, 02, 85, 01, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 8f, 04, 89, 01, 81, 01, 85, 01, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, f6, 03, 19, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, b7, 04, 1d, 15, 19, b3, 04, 21, b7, 04, 1d, 15, 19, ab, 04, bb, 04, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, bf, 04, ca, 04, c3, 04, 31, c7, 04, 2d, 25, 29, ce, 04, 0d, 01, 09, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ce, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 2b, 01, 09, 01, 12, ca, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 02, 08, 00, 15, 49, 00, 16, 02, 06, 62, 02, 0f, 00, 1c, 5e, 01, 0c, 00, 19, 5a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 83, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 7f, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 7b, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, 5d, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, ae, 01, 04, 11, 00, 1e, aa, 01, 01, 10, 00, 1d, a6, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, ef, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, eb, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, e3, 02, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 04, 02, 09, 00, 0a, e3, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, de, 02, 02, 0f, 00, 1c, da, 02, 01, 0c, 00, 19, d6, 02, 00, 1d, 00, 2a, d2, 02, 00, 2e, 00, 3c, 8b, 04, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, 87, 04, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, ab, 04, 05, 09, 00, 0a, 83, 04, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, fe, 03, 02, 0f, 00, 1c, fa, 03, 01, 0c, 00, 19, f6, 03, 00, 1d, 00, 2a, f2, 03, 00, 2e, 00, 3c, b3, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, af, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, a7, 04, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 142
-- expression 0 operands: lhs = Counter(2), rhs = Expression(12, Add)
-- expression 1 operands: lhs = Expression(13, Add), rhs = Counter(16)
-- expression 2 operands: lhs = Expression(14, Add), rhs = Counter(15)
+Number of expressions: 148
+- expression 0 operands: lhs = Counter(2), rhs = Expression(10, Add)
+- expression 1 operands: lhs = Expression(11, Add), rhs = Counter(16)
+- expression 2 operands: lhs = Expression(12, Add), rhs = Counter(15)
 - expression 3 operands: lhs = Counter(13), rhs = Counter(14)
-- expression 4 operands: lhs = Counter(1), rhs = Zero
-- expression 5 operands: lhs = Expression(141, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Zero
+- expression 4 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 5 operands: lhs = Counter(3), rhs = Counter(13)
+- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(14)
 - expression 7 operands: lhs = Counter(3), rhs = Counter(13)
-- expression 8 operands: lhs = Expression(9, Sub), rhs = Counter(14)
-- expression 9 operands: lhs = Counter(3), rhs = Counter(13)
-- expression 10 operands: lhs = Expression(14, Add), rhs = Counter(15)
-- expression 11 operands: lhs = Counter(13), rhs = Counter(14)
-- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(16)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(15)
-- expression 14 operands: lhs = Counter(13), rhs = Counter(14)
-- expression 15 operands: lhs = Expression(140, Sub), rhs = Counter(3)
-- expression 16 operands: lhs = Expression(141, Add), rhs = Counter(2)
-- expression 17 operands: lhs = Counter(1), rhs = Zero
-- expression 18 operands: lhs = Counter(17), rhs = Zero
-- expression 19 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 20 operands: lhs = Counter(17), rhs = Zero
-- expression 21 operands: lhs = Expression(31, Sub), rhs = Counter(12)
-- expression 22 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 23 operands: lhs = Counter(17), rhs = Zero
-- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(19)
-- expression 25 operands: lhs = Expression(31, Sub), rhs = Counter(12)
-- expression 26 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 27 operands: lhs = Counter(17), rhs = Zero
-- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(20)
-- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(19)
-- expression 30 operands: lhs = Expression(31, Sub), rhs = Counter(12)
-- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 32 operands: lhs = Counter(17), rhs = Zero
-- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(21)
-- expression 34 operands: lhs = Counter(19), rhs = Counter(20)
-- expression 35 operands: lhs = Expression(40, Add), rhs = Counter(22)
-- expression 36 operands: lhs = Expression(41, Add), rhs = Counter(21)
-- expression 37 operands: lhs = Counter(19), rhs = Counter(20)
-- expression 38 operands: lhs = Counter(18), rhs = Expression(39, Add)
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(22)
-- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(21)
-- expression 41 operands: lhs = Counter(19), rhs = Counter(20)
-- expression 42 operands: lhs = Counter(24), rhs = Zero
-- expression 43 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 44 operands: lhs = Counter(24), rhs = Zero
-- expression 45 operands: lhs = Expression(55, Sub), rhs = Counter(11)
-- expression 46 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 47 operands: lhs = Counter(24), rhs = Zero
-- expression 48 operands: lhs = Expression(54, Sub), rhs = Counter(26)
-- expression 49 operands: lhs = Expression(55, Sub), rhs = Counter(11)
-- expression 50 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 51 operands: lhs = Counter(24), rhs = Zero
-- expression 52 operands: lhs = Expression(53, Sub), rhs = Counter(27)
-- expression 53 operands: lhs = Expression(54, Sub), rhs = Counter(26)
-- expression 54 operands: lhs = Expression(55, Sub), rhs = Counter(11)
-- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 56 operands: lhs = Counter(24), rhs = Zero
-- expression 57 operands: lhs = Expression(66, Add), rhs = Counter(28)
-- expression 58 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 59 operands: lhs = Expression(65, Add), rhs = Counter(29)
-- expression 60 operands: lhs = Expression(66, Add), rhs = Counter(28)
-- expression 61 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 62 operands: lhs = Expression(63, Add), rhs = Zero
-- expression 63 operands: lhs = Counter(25), rhs = Expression(64, Add)
-- expression 64 operands: lhs = Expression(65, Add), rhs = Counter(29)
-- expression 65 operands: lhs = Expression(66, Add), rhs = Counter(28)
-- expression 66 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 67 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 68 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 69 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 70 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 71 operands: lhs = Counter(30), rhs = Zero
-- expression 72 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 73 operands: lhs = Counter(30), rhs = Zero
-- expression 74 operands: lhs = Expression(84, Sub), rhs = Counter(10)
-- expression 75 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 76 operands: lhs = Counter(30), rhs = Zero
-- expression 77 operands: lhs = Expression(83, Sub), rhs = Counter(32)
-- expression 78 operands: lhs = Expression(84, Sub), rhs = Counter(10)
-- expression 79 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 80 operands: lhs = Counter(30), rhs = Zero
-- expression 81 operands: lhs = Expression(82, Sub), rhs = Counter(33)
-- expression 82 operands: lhs = Expression(83, Sub), rhs = Counter(32)
-- expression 83 operands: lhs = Expression(84, Sub), rhs = Counter(10)
-- expression 84 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 85 operands: lhs = Counter(30), rhs = Zero
-- expression 86 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 87 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 88 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 89 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 90 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 91 operands: lhs = Counter(4), rhs = Expression(132, Add)
-- expression 92 operands: lhs = Expression(133, Add), rhs = Counter(8)
-- expression 93 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 94 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 95 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 96 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 97 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 98 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 99 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 100 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 101 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 102 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 103 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 104 operands: lhs = Expression(120, Sub), rhs = Counter(9)
-- expression 105 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 106 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 107 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 108 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 109 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 110 operands: lhs = Expression(119, Sub), rhs = Counter(5)
-- expression 111 operands: lhs = Expression(120, Sub), rhs = Counter(9)
-- expression 112 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 113 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 114 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 115 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 8 operands: lhs = Expression(12, Add), rhs = Counter(15)
+- expression 9 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(16)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(15)
+- expression 12 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 13 operands: lhs = Expression(147, Sub), rhs = Counter(3)
+- expression 14 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 15 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 16 operands: lhs = Expression(24, Sub), rhs = Counter(12)
+- expression 17 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 18 operands: lhs = Expression(23, Sub), rhs = Counter(19)
+- expression 19 operands: lhs = Expression(24, Sub), rhs = Counter(12)
+- expression 20 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 21 operands: lhs = Expression(22, Sub), rhs = Counter(20)
+- expression 22 operands: lhs = Expression(23, Sub), rhs = Counter(19)
+- expression 23 operands: lhs = Expression(24, Sub), rhs = Counter(12)
+- expression 24 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 25 operands: lhs = Expression(33, Add), rhs = Counter(21)
+- expression 26 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 27 operands: lhs = Expression(32, Add), rhs = Counter(22)
+- expression 28 operands: lhs = Expression(33, Add), rhs = Counter(21)
+- expression 29 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 30 operands: lhs = Counter(18), rhs = Expression(31, Add)
+- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(22)
+- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(21)
+- expression 33 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 34 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 35 operands: lhs = Expression(43, Sub), rhs = Counter(11)
+- expression 36 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 37 operands: lhs = Expression(42, Sub), rhs = Counter(26)
+- expression 38 operands: lhs = Expression(43, Sub), rhs = Counter(11)
+- expression 39 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(27)
+- expression 41 operands: lhs = Expression(42, Sub), rhs = Counter(26)
+- expression 42 operands: lhs = Expression(43, Sub), rhs = Counter(11)
+- expression 43 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 44 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 45 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 46 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 47 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 48 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 49 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 50 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 51 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 52 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 53 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 54 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 55 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 56 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 57 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 58 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 59 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 60 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 61 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 62 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 63 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 64 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 65 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 66 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 67 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 68 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 69 operands: lhs = Expression(87, Sub), rhs = Counter(10)
+- expression 70 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 71 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 72 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 73 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 74 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 75 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 76 operands: lhs = Expression(86, Sub), rhs = Counter(32)
+- expression 77 operands: lhs = Expression(87, Sub), rhs = Counter(10)
+- expression 78 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 79 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 80 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 81 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 82 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 83 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 84 operands: lhs = Expression(85, Sub), rhs = Counter(33)
+- expression 85 operands: lhs = Expression(86, Sub), rhs = Counter(32)
+- expression 86 operands: lhs = Expression(87, Sub), rhs = Counter(10)
+- expression 87 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 88 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 89 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 90 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 91 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 92 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 93 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 94 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 95 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 96 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 97 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 98 operands: lhs = Counter(4), rhs = Expression(139, Add)
+- expression 99 operands: lhs = Expression(140, Add), rhs = Counter(8)
+- expression 100 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 101 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 102 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 103 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 104 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 105 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 106 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 107 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 108 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 109 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 110 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 111 operands: lhs = Expression(127, Sub), rhs = Counter(9)
+- expression 112 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 113 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 114 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 115 operands: lhs = Expression(131, Add), rhs = Counter(34)
 - expression 116 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 117 operands: lhs = Expression(118, Sub), rhs = Counter(6)
-- expression 118 operands: lhs = Expression(119, Sub), rhs = Counter(5)
-- expression 119 operands: lhs = Expression(120, Sub), rhs = Counter(9)
-- expression 120 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 121 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 122 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 123 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 124 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 125 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 126 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 127 operands: lhs = Expression(133, Add), rhs = Counter(8)
-- expression 128 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 129 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 130 operands: lhs = Expression(131, Add), rhs = Expression(135, Add)
-- expression 131 operands: lhs = Counter(4), rhs = Expression(132, Add)
-- expression 132 operands: lhs = Expression(133, Add), rhs = Counter(8)
-- expression 133 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 134 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 135 operands: lhs = Expression(136, Add), rhs = Expression(139, Sub)
-- expression 136 operands: lhs = Expression(137, Add), rhs = Counter(12)
-- expression 137 operands: lhs = Expression(138, Add), rhs = Counter(11)
-- expression 138 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 139 operands: lhs = Expression(140, Sub), rhs = Counter(3)
-- expression 140 operands: lhs = Expression(141, Add), rhs = Counter(2)
-- expression 141 operands: lhs = Counter(1), rhs = Zero
+- expression 117 operands: lhs = Expression(126, Sub), rhs = Counter(5)
+- expression 118 operands: lhs = Expression(127, Sub), rhs = Counter(9)
+- expression 119 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 120 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 121 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 122 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 123 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 124 operands: lhs = Expression(125, Sub), rhs = Counter(6)
+- expression 125 operands: lhs = Expression(126, Sub), rhs = Counter(5)
+- expression 126 operands: lhs = Expression(127, Sub), rhs = Counter(9)
+- expression 127 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 128 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 129 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 130 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 131 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 132 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 133 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 134 operands: lhs = Expression(140, Add), rhs = Counter(8)
+- expression 135 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 136 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 137 operands: lhs = Expression(138, Add), rhs = Expression(142, Add)
+- expression 138 operands: lhs = Counter(4), rhs = Expression(139, Add)
+- expression 139 operands: lhs = Expression(140, Add), rhs = Counter(8)
+- expression 140 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 141 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 142 operands: lhs = Expression(143, Add), rhs = Expression(146, Sub)
+- expression 143 operands: lhs = Expression(144, Add), rhs = Counter(12)
+- expression 144 operands: lhs = Expression(145, Add), rhs = Counter(11)
+- expression 145 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 146 operands: lhs = Expression(147, Sub), rhs = Counter(3)
+- expression 147 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 68
 - Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10)
     = (c2 + (((c13 + c14) + c15) + c16))
-- Code(Expression(141, Add)) at (prev + 0, 16) to (start + 0, 29)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29)
 - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 10)
-- Code(Expression(140, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((c1 + Zero) - c2)
+- Code(Expression(147, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = (c0 - c2)
 - Code(Counter(3)) at (prev + 1, 12) to (start + 0, 25)
-- Code(Expression(9, Sub)) at (prev + 0, 29) to (start + 0, 42)
+- Code(Expression(7, Sub)) at (prev + 0, 29) to (start + 0, 42)
     = (c3 - c13)
-- Code(Expression(8, Sub)) at (prev + 0, 46) to (start + 0, 60)
+- Code(Expression(6, Sub)) at (prev + 0, 46) to (start + 0, 60)
     = ((c3 - c13) - c14)
-- Code(Expression(13, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(11, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c13 + c14) + c15)
 - Code(Counter(16)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 1, 18)
+- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 18)
     = (((c13 + c14) + c15) + c16)
-- Code(Expression(139, Sub)) at (prev + 3, 9) to (start + 0, 15)
-    = (((c1 + Zero) - c2) - c3)
+- Code(Expression(146, Sub)) at (prev + 3, 9) to (start + 0, 15)
+    = ((c0 - c2) - c3)
 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12)
     = (c2 + (((c13 + c14) + c15) + c16))
 - Code(Counter(17)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(32, Add)) at (prev + 2, 8) to (start + 0, 21)
-    = (c17 + Zero)
+- Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21)
+    = (c2 + (((c13 + c14) + c15) + c16))
 - Code(Counter(18)) at (prev + 0, 22) to (start + 2, 6)
-- Code(Expression(31, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((c17 + Zero) - c18)
-- Code(Expression(30, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = (((c17 + Zero) - c18) - c12)
-- Code(Expression(29, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = ((((c17 + Zero) - c18) - c12) - c19)
-- Code(Expression(28, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (((((c17 + Zero) - c18) - c12) - c19) - c20)
-- Code(Expression(40, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(24, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = ((c2 + (((c13 + c14) + c15) + c16)) - c18)
+- Code(Expression(23, Sub)) at (prev + 1, 12) to (start + 0, 25)
+    = (((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12)
+- Code(Expression(22, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = ((((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12) - c19)
+- Code(Expression(21, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = (((((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12) - c19) - c20)
+- Code(Expression(32, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c19 + c20) + c21)
 - Code(Counter(22)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(39, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(31, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (((c19 + c20) + c21) + c22)
 - Code(Counter(12)) at (prev + 2, 9) to (start + 0, 15)
-- Code(Expression(38, Add)) at (prev + 3, 8) to (start + 0, 12)
+- Code(Expression(30, Add)) at (prev + 3, 8) to (start + 0, 12)
     = (c18 + (((c19 + c20) + c21) + c22))
 - Code(Counter(23)) at (prev + 1, 13) to (start + 1, 16)
 - Code(Counter(24)) at (prev + 1, 17) to (start + 2, 10)
 - Code(Zero) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(56, Add)) at (prev + 2, 12) to (start + 0, 25)
-    = (c24 + Zero)
+- Code(Counter(23)) at (prev + 2, 12) to (start + 0, 25)
 - Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10)
-- Code(Expression(55, Sub)) at (prev + 4, 17) to (start + 0, 30)
-    = ((c24 + Zero) - c25)
-- Code(Expression(54, Sub)) at (prev + 1, 16) to (start + 0, 29)
-    = (((c24 + Zero) - c25) - c11)
-- Code(Expression(53, Sub)) at (prev + 0, 33) to (start + 0, 46)
-    = ((((c24 + Zero) - c25) - c11) - c26)
-- Code(Expression(52, Sub)) at (prev + 0, 50) to (start + 0, 64)
-    = (((((c24 + Zero) - c25) - c11) - c26) - c27)
-- Code(Expression(65, Add)) at (prev + 0, 65) to (start + 2, 14)
+- Code(Expression(43, Sub)) at (prev + 4, 17) to (start + 0, 30)
+    = (c23 - c25)
+- Code(Expression(42, Sub)) at (prev + 1, 16) to (start + 0, 29)
+    = ((c23 - c25) - c11)
+- Code(Expression(41, Sub)) at (prev + 0, 33) to (start + 0, 46)
+    = (((c23 - c25) - c11) - c26)
+- Code(Expression(40, Sub)) at (prev + 0, 50) to (start + 0, 64)
+    = ((((c23 - c25) - c11) - c26) - c27)
+- Code(Expression(91, Add)) at (prev + 0, 65) to (start + 2, 14)
     = ((c26 + c27) + c28)
 - Code(Counter(29)) at (prev + 2, 14) to (start + 0, 15)
-- Code(Expression(64, Add)) at (prev + 1, 13) to (start + 0, 27)
+- Code(Expression(90, Add)) at (prev + 1, 13) to (start + 0, 27)
     = (((c26 + c27) + c28) + c29)
 - Code(Counter(11)) at (prev + 2, 13) to (start + 0, 19)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(62, Add)) at (prev + 2, 9) to (start + 1, 12)
+- Code(Expression(88, Add)) at (prev + 2, 9) to (start + 1, 12)
     = ((c25 + (((c26 + c27) + c28) + c29)) + Zero)
 - Code(Counter(30)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(121, Add)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Expression(128, Add)) at (prev + 2, 9) to (start + 0, 10)
     = (c31 + (((c32 + c33) + c34) + c35))
-- Code(Expression(85, Add)) at (prev + 0, 16) to (start + 0, 29)
-    = (c30 + Zero)
+- Code(Expression(88, Add)) at (prev + 0, 16) to (start + 0, 29)
+    = ((c25 + (((c26 + c27) + c28) + c29)) + Zero)
 - Code(Counter(31)) at (prev + 0, 30) to (start + 2, 6)
-- Code(Expression(84, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((c30 + Zero) - c31)
-- Code(Expression(83, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = (((c30 + Zero) - c31) - c10)
-- Code(Expression(82, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = ((((c30 + Zero) - c31) - c10) - c32)
-- Code(Expression(81, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (((((c30 + Zero) - c31) - c10) - c32) - c33)
-- Code(Expression(123, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(87, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = (((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31)
+- Code(Expression(86, Sub)) at (prev + 1, 12) to (start + 0, 25)
+    = ((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10)
+- Code(Expression(85, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = (((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10) - c32)
+- Code(Expression(84, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = ((((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10) - c32) - c33)
+- Code(Expression(130, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c32 + c33) + c34)
 - Code(Counter(35)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(122, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(129, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (((c32 + c33) + c34) + c35)
 - Code(Counter(10)) at (prev + 2, 13) to (start + 2, 15)
-- Code(Expression(131, Add)) at (prev + 5, 9) to (start + 0, 10)
+- Code(Expression(138, Add)) at (prev + 5, 9) to (start + 0, 10)
     = (c4 + (((c5 + c6) + c7) + c8))
-- Code(Expression(121, Add)) at (prev + 0, 16) to (start + 0, 29)
+- Code(Expression(128, Add)) at (prev + 0, 16) to (start + 0, 29)
     = (c31 + (((c32 + c33) + c34) + c35))
 - Code(Counter(4)) at (prev + 0, 30) to (start + 2, 6)
-- Code(Expression(120, Sub)) at (prev + 2, 15) to (start + 0, 28)
+- Code(Expression(127, Sub)) at (prev + 2, 15) to (start + 0, 28)
     = ((c31 + (((c32 + c33) + c34) + c35)) - c4)
-- Code(Expression(119, Sub)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(126, Sub)) at (prev + 1, 12) to (start + 0, 25)
     = (((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9)
-- Code(Expression(118, Sub)) at (prev + 0, 29) to (start + 0, 42)
+- Code(Expression(125, Sub)) at (prev + 0, 29) to (start + 0, 42)
     = ((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5)
-- Code(Expression(117, Sub)) at (prev + 0, 46) to (start + 0, 60)
+- Code(Expression(124, Sub)) at (prev + 0, 46) to (start + 0, 60)
     = (((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) - c6)
-- Code(Expression(133, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(140, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c5 + c6) + c7)
 - Code(Counter(8)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(132, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(139, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (((c5 + c6) + c7) + c8)
 - Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15)
-- Code(Expression(130, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = ((c4 + (((c5 + c6) + c7) + c8)) + ((((c9 + c10) + c11) + c12) + (((c1 + Zero) - c2) - c3)))
+- Code(Expression(137, Add)) at (prev + 2, 1) to (start + 0, 2)
+    = ((c4 + (((c5 + c6) + c7) + c8)) + ((((c9 + c10) + c11) + c12) + ((c0 - c2) - c3)))
 
diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map
index 255708d365e..6ead788b82f 100644
--- a/tests/coverage/coroutine.cov-map
+++ b/tests/coverage/coroutine.cov-map
@@ -1,17 +1,15 @@
 Function name: coroutine::get_u32
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 11, 1) to (start + 1, 11)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 40)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: coroutine::main
 Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map
index 0b8a40a8cde..31599d9072c 100644
--- a/tests/coverage/dead_code.cov-map
+++ b/tests/coverage/dead_code.cov-map
@@ -1,17 +1,15 @@
 Function name: dead_code::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 27, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: dead_code::unused_fn (unused)
 Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map
index 203d1048b05..eb9d7d7acfd 100644
--- a/tests/coverage/drop_trait.cov-map
+++ b/tests/coverage/drop_trait.cov-map
@@ -7,15 +7,13 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6)
 
 Function name: drop_trait::main
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12)
 - Code(Counter(1)) at (prev + 6, 9) to (start + 1, 22)
 - Code(Zero) at (prev + 2, 6) to (start + 4, 11)
-- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map
index c3969f8ce99..49758954831 100644
--- a/tests/coverage/fn_sig_into_try.cov-map
+++ b/tests/coverage/fn_sig_into_try.cov-map
@@ -7,47 +7,41 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2)
 
 Function name: fn_sig_into_try::b
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 17, 1) to (start + 3, 15)
 - Code(Zero) at (prev + 3, 15) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: fn_sig_into_try::c
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 24, 1) to (start + 3, 23)
 - Code(Zero) at (prev + 3, 23) to (start + 0, 24)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: fn_sig_into_try::d
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 31, 1) to (start + 4, 15)
 - Code(Zero) at (prev + 4, 15) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map
index 6079a433cd0..48e191c1156 100644
--- a/tests/coverage/generics.cov-map
+++ b/tests/coverage/generics.cov-map
@@ -31,15 +31,13 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6)
 
 Function name: generics::main
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12)
 - Code(Counter(1)) at (prev + 9, 9) to (start + 1, 22)
 - Code(Zero) at (prev + 2, 6) to (start + 4, 11)
-- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map
index d7122f4b1a0..2b5ae97b406 100644
--- a/tests/coverage/if.cov-map
+++ b/tests/coverage/if.cov-map
@@ -1,15 +1,13 @@
 Function name: if::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 4, 1) to (start + 18, 16)
 - Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6)
 - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map
index 7163681d3a0..c2111917e55 100644
--- a/tests/coverage/if_else.cov-map
+++ b/tests/coverage/if_else.cov-map
@@ -1,25 +1,18 @@
 Function name: if_else::main
-Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 1b, 06, 09, 00, 10, 09, 01, 05, 05, 06, 16, 07, 05, 05, 06, 13, 06, 01, 00, 02]
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 7
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 4, 1) to (start + 8, 16)
 - Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6)
 - Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16)
     = (c0 - c1)
-- Code(Expression(6, Add)) at (prev + 6, 9) to (start + 0, 16)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 6, 9) to (start + 0, 16)
 - Code(Counter(2)) at (prev + 1, 5) to (start + 5, 6)
-- Code(Expression(5, Sub)) at (prev + 7, 5) to (start + 5, 6)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(4, Add)) at (prev + 6, 1) to (start + 0, 2)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(1, Sub)) at (prev + 7, 5) to (start + 5, 6)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map
index 3c660551dea..9e11ed787a8 100644
--- a/tests/coverage/if_not.cov-map
+++ b/tests/coverage/if_not.cov-map
@@ -1,39 +1,23 @@
 Function name: if_not::if_not
-Raw bytes (86): 0x[01, 01, 10, 01, 05, 05, 02, 3f, 09, 05, 02, 09, 3a, 3f, 09, 05, 02, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0d, 32, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 3f, 03, 09, 01, 0d, 3a, 02, 05, 02, 06, 09, 02, 06, 00, 07, 37, 03, 09, 01, 0d, 32, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 2f, 03, 01, 00, 02]
+Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 16
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(2), rhs = Expression(14, Sub)
-- expression 5 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 7 operands: lhs = Expression(13, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(14, Sub)
-- expression 9 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 11 operands: lhs = Counter(3), rhs = Expression(12, Sub)
-- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(3)
-- expression 13 operands: lhs = Counter(2), rhs = Expression(14, Sub)
-- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 15 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13)
 - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6)
     = (c0 - c1)
 - Code(Counter(1)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(15, Add)) at (prev + 3, 9) to (start + 1, 13)
-    = (c1 + (c0 - c1))
-- Code(Expression(14, Sub)) at (prev + 2, 5) to (start + 2, 6)
-    = ((c1 + (c0 - c1)) - c2)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13)
+- Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 2, 6)
+    = (c0 - c2)
 - Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(13, Add)) at (prev + 3, 9) to (start + 1, 13)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(12, Sub)) at (prev + 2, 5) to (start + 2, 6)
-    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13)
+- Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 2, 6)
+    = (c0 - c3)
 - Code(Counter(3)) at (prev + 2, 12) to (start + 2, 6)
-- Code(Expression(11, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map
index f77781ca028..96b907cbe15 100644
--- a/tests/coverage/inline-dead.cov-map
+++ b/tests/coverage/inline-dead.cov-map
@@ -7,19 +7,17 @@ Number of file 0 mappings: 1
 - Code(Zero) at (prev + 23, 1) to (start + 2, 2)
 
 Function name: inline_dead::live::<false>
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 0e, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 0e, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9)
 - Code(Zero) at (prev + 2, 9) to (start + 0, 15)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: inline_dead::main
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02]
diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map
index 001c333ae6d..2366a3bc534 100644
--- a/tests/coverage/inline.cov-map
+++ b/tests/coverage/inline.cov-map
@@ -1,18 +1,16 @@
 Function name: inline::display::<char>
-Raw bytes (33): 0x[01, 01, 02, 01, 05, 03, 05, 05, 01, 29, 01, 00, 22, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 10, 05, 00, 11, 02, 06, 06, 03, 05, 01, 02]
+Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 29, 01, 00, 22, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 10, 05, 00, 11, 02, 06, 01, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 41, 1) to (start + 0, 34)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 16)
     = (c0 + c1)
 - Code(Counter(1)) at (prev + 0, 17) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 3, 5) to (start + 1, 2)
-    = ((c0 + c1) - c1)
+- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2)
 
 Function name: inline::error
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 14]
diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map
index 3f39d74efba..6ccc3f0bafc 100644
--- a/tests/coverage/inner_items.cov-map
+++ b/tests/coverage/inner_items.cov-map
@@ -15,29 +15,22 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10)
 
 Function name: inner_items::main
-Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1b, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 16, 02, 06, 00, 07, 13, 02, 09, 05, 02]
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 06, 00, 07, 01, 02, 09, 05, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 7
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(6, Add)) at (prev + 36, 8) to (start + 0, 15)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 36, 8) to (start + 0, 15)
 - Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6)
-- Code(Expression(5, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(4, Add)) at (prev + 2, 9) to (start + 5, 2)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(1, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2)
 
 Function name: inner_items::main::in_func
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06]
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
index ab66a2fffce..c4087d9369d 100644
--- a/tests/coverage/issue-84561.cov-map
+++ b/tests/coverage/issue-84561.cov-map
@@ -1,17 +1,15 @@
 Function name: <issue_84561::Foo as core::fmt::Debug>::fmt
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06]
+Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 138, 5) to (start + 1, 37)
 - Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38)
 - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6)
 
 Function name: issue_84561::main
 Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02]
@@ -22,51 +20,30 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2)
 
 Function name: issue_84561::test1
-Raw bytes (78): 0x[01, 01, 0e, 05, 06, 01, 05, 09, 36, 03, 09, 0d, 2e, 33, 0d, 09, 36, 03, 09, 11, 26, 2b, 11, 0d, 2e, 33, 0d, 09, 36, 03, 09, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 03, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 33, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 2b, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 23, 01, 01, 00, 02]
+Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 14
-- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(2), rhs = Expression(13, Sub)
-- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(3), rhs = Expression(11, Sub)
-- expression 5 operands: lhs = Expression(12, Add), rhs = Counter(3)
-- expression 6 operands: lhs = Counter(2), rhs = Expression(13, Sub)
-- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 8 operands: lhs = Counter(4), rhs = Expression(9, Sub)
-- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(4)
-- expression 10 operands: lhs = Counter(3), rhs = Expression(11, Sub)
-- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(13, Sub)
-- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(2)
+Number of expressions: 0
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11)
 - Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30)
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 11)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11)
 - Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30)
-- Code(Expression(12, Add)) at (prev + 1, 13) to (start + 1, 11)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 1, 11)
 - Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30)
-- Code(Expression(10, Add)) at (prev + 1, 5) to (start + 3, 11)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 11)
 - Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30)
-- Code(Expression(8, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: issue_84561::test2
-Raw bytes (24): 0x[01, 01, 02, 05, 06, 01, 05, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 03, 01, 01, 00, 02]
+Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
-- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 0
 Number of file 0 mappings: 3
 - Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35)
-- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: issue_84561::test2::call_print
 Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a]
@@ -77,10 +54,10 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10)
 
 Function name: issue_84561::test3
-Raw bytes (436): 0x[01, 01, 41, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 00, fe, 01, 82, 02, 00, 69, 6d, 69, 6d, 82, 02, 00, 69, 6d, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
+Raw bytes (375): 0x[01, 01, 31, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 7a, 55, 51, 00, 7a, 55, 51, 00, 77, 5d, 7a, 55, 51, 00, 77, 61, 7a, 55, 51, 00, 72, 65, 77, 61, 7a, 55, 51, 00, 75, be, 01, c2, 01, 79, 69, 6d, 69, 6d, 69, 6d, c2, 01, 00, 69, 6d, c2, 01, 79, 69, 6d, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, b6, 01, 00, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 77, 03, 05, 00, 0f, 77, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 56, 02, 0d, 00, 13, 72, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 6e, 02, 0d, 00, 13, bb, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, c2, 01, 02, 0d, 00, 17, c2, 01, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 92, 01, 02, 15, 00, 1b, be, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, b6, 01, 02, 05, 00, 0f, b2, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 65
+Number of expressions: 49
 - expression 0 operands: lhs = Counter(1), rhs = Zero
 - expression 1 operands: lhs = Counter(3), rhs = Zero
 - expression 2 operands: lhs = Counter(5), rhs = Zero
@@ -98,54 +75,38 @@ Number of expressions: 65
 - expression 14 operands: lhs = Expression(15, Add), rhs = Counter(20)
 - expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(18)
 - expression 16 operands: lhs = Counter(17), rhs = Zero
-- expression 17 operands: lhs = Counter(23), rhs = Expression(34, Sub)
-- expression 18 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 19 operands: lhs = Expression(36, Sub), rhs = Counter(21)
+- expression 17 operands: lhs = Expression(30, Sub), rhs = Counter(21)
+- expression 18 operands: lhs = Counter(20), rhs = Zero
+- expression 19 operands: lhs = Expression(30, Sub), rhs = Counter(21)
 - expression 20 operands: lhs = Counter(20), rhs = Zero
-- expression 21 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 22 operands: lhs = Counter(20), rhs = Zero
-- expression 23 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 24 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 25 operands: lhs = Counter(20), rhs = Zero
-- expression 26 operands: lhs = Expression(33, Add), rhs = Counter(24)
-- expression 27 operands: lhs = Counter(23), rhs = Expression(34, Sub)
-- expression 28 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 29 operands: lhs = Expression(36, Sub), rhs = Counter(21)
+- expression 21 operands: lhs = Expression(29, Add), rhs = Counter(23)
+- expression 22 operands: lhs = Expression(30, Sub), rhs = Counter(21)
+- expression 23 operands: lhs = Counter(20), rhs = Zero
+- expression 24 operands: lhs = Expression(29, Add), rhs = Counter(24)
+- expression 25 operands: lhs = Expression(30, Sub), rhs = Counter(21)
+- expression 26 operands: lhs = Counter(20), rhs = Zero
+- expression 27 operands: lhs = Expression(28, Sub), rhs = Counter(25)
+- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(24)
+- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(21)
 - expression 30 operands: lhs = Counter(20), rhs = Zero
-- expression 31 operands: lhs = Expression(32, Sub), rhs = Counter(25)
-- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(24)
-- expression 33 operands: lhs = Counter(23), rhs = Expression(34, Sub)
-- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 36 operands: lhs = Counter(20), rhs = Zero
-- expression 37 operands: lhs = Counter(29), rhs = Expression(61, Sub)
-- expression 38 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 39 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 40 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 41 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 42 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 43 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 44 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 45 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 46 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 47 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 48 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 49 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 50 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 51 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 52 operands: lhs = Expression(60, Add), rhs = Counter(31)
-- expression 53 operands: lhs = Counter(29), rhs = Expression(61, Sub)
-- expression 54 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 55 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 56 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 57 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 58 operands: lhs = Expression(59, Sub), rhs = Zero
-- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(31)
-- expression 60 operands: lhs = Counter(29), rhs = Expression(61, Sub)
-- expression 61 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 62 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 63 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 64 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 31 operands: lhs = Counter(29), rhs = Expression(47, Sub)
+- expression 32 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 33 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 34 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 35 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 36 operands: lhs = Expression(48, Sub), rhs = Zero
+- expression 37 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 38 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 39 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 40 operands: lhs = Expression(46, Add), rhs = Counter(31)
+- expression 41 operands: lhs = Counter(29), rhs = Expression(47, Sub)
+- expression 42 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 43 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero
+- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(31)
+- expression 46 operands: lhs = Counter(29), rhs = Expression(47, Sub)
+- expression 47 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 48 operands: lhs = Counter(26), rhs = Counter(27)
 Number of file 0 mappings: 51
 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28)
 - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28)
@@ -187,37 +148,37 @@ Number of file 0 mappings: 51
 - Code(Expression(14, Sub)) at (prev + 3, 9) to (start + 0, 19)
     = (((c17 - Zero) + c18) - c20)
 - Code(Zero) at (prev + 3, 13) to (start + 0, 29)
-- Code(Expression(33, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c23 + (((c20 - Zero) + c21) - c23))
-- Code(Expression(35, Add)) at (prev + 1, 12) to (start + 0, 19)
+- Code(Expression(29, Add)) at (prev + 3, 5) to (start + 0, 15)
+    = ((c20 - Zero) + c21)
+- Code(Expression(29, Add)) at (prev + 1, 12) to (start + 0, 19)
     = ((c20 - Zero) + c21)
 - Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19)
-- Code(Expression(34, Sub)) at (prev + 2, 13) to (start + 0, 19)
+- Code(Expression(21, Sub)) at (prev + 2, 13) to (start + 0, 19)
     = (((c20 - Zero) + c21) - c23)
-- Code(Expression(32, Sub)) at (prev + 4, 5) to (start + 2, 19)
-    = ((c23 + (((c20 - Zero) + c21) - c23)) - c24)
+- Code(Expression(28, Sub)) at (prev + 4, 5) to (start + 2, 19)
+    = (((c20 - Zero) + c21) - c24)
 - Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19)
-- Code(Expression(31, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (((c23 + (((c20 - Zero) + c21) - c23)) - c24) - c25)
-- Code(Expression(60, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c29 + ((Zero + ((c26 - c27) - Zero)) - c30))
+- Code(Expression(27, Sub)) at (prev + 2, 13) to (start + 0, 19)
+    = ((((c20 - Zero) + c21) - c24) - c25)
+- Code(Expression(46, Add)) at (prev + 3, 5) to (start + 0, 15)
+    = (c29 + ((c26 - c27) - c30))
 - Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19)
 - Code(Counter(27)) at (prev + 1, 13) to (start + 3, 14)
 - Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19)
-- Code(Expression(62, Add)) at (prev + 2, 13) to (start + 0, 23)
-    = (Zero + ((c26 - c27) - Zero))
-- Code(Expression(64, Sub)) at (prev + 1, 20) to (start + 0, 27)
+- Code(Expression(48, Sub)) at (prev + 2, 13) to (start + 0, 23)
+    = (c26 - c27)
+- Code(Expression(48, Sub)) at (prev + 1, 20) to (start + 0, 27)
     = (c26 - c27)
 - Code(Zero) at (prev + 1, 21) to (start + 0, 27)
-- Code(Expression(63, Sub)) at (prev + 2, 21) to (start + 0, 27)
+- Code(Expression(36, Sub)) at (prev + 2, 21) to (start + 0, 27)
     = ((c26 - c27) - Zero)
-- Code(Expression(61, Sub)) at (prev + 4, 13) to (start + 0, 19)
-    = ((Zero + ((c26 - c27) - Zero)) - c30)
+- Code(Expression(47, Sub)) at (prev + 4, 13) to (start + 0, 19)
+    = ((c26 - c27) - c30)
 - Code(Counter(31)) at (prev + 3, 9) to (start + 0, 25)
-- Code(Expression(59, Sub)) at (prev + 2, 5) to (start + 0, 15)
-    = ((c29 + ((Zero + ((c26 - c27) - Zero)) - c30)) - c31)
-- Code(Expression(58, Sub)) at (prev + 3, 9) to (start + 0, 34)
-    = (((c29 + ((Zero + ((c26 - c27) - Zero)) - c30)) - c31) - Zero)
+- Code(Expression(45, Sub)) at (prev + 2, 5) to (start + 0, 15)
+    = ((c29 + ((c26 - c27) - c30)) - c31)
+- Code(Expression(44, Sub)) at (prev + 3, 9) to (start + 0, 34)
+    = (((c29 + ((c26 - c27) - c30)) - c31) - Zero)
 - Code(Zero) at (prev + 2, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 3, 9) to (start + 0, 44)
 - Code(Zero) at (prev + 2, 1) to (start + 0, 2)
diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map
index 03dbb59d26b..8dca205d33f 100644
--- a/tests/coverage/lazy_boolean.cov-map
+++ b/tests/coverage/lazy_boolean.cov-map
@@ -1,219 +1,49 @@
 Function name: lazy_boolean::main
-Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 03, 09, 01, 10, ea, 04, 02, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 08, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02]
+Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 09, 01, 0d, 01, 19, 01, 1d, 01, 21, 01, 25, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 11, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 19, 03, 06, 00, 07, 01, 03, 09, 00, 10, 1d, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 21, 02, 06, 00, 07, 01, 02, 08, 00, 0f, 25, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 164
+Number of expressions: 7
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 2 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 5 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 7 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 8 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 9 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 10 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 11 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 13 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 14 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 15 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 17 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 18 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 19 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 20 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 21 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 22 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 23 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 24 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 25 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 26 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 27 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 28 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 29 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 30 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 31 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 32 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 33 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 34 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 35 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 36 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 37 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 38 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 39 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 40 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 41 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 42 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 43 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 44 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 45 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 46 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 47 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 48 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 49 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 50 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 51 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 52 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 53 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 54 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 55 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 56 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 57 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 58 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 59 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 60 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 61 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 62 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 63 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 64 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 65 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 66 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 67 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 68 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 69 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 70 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 71 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 72 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 73 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 74 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 75 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 76 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 77 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 78 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 79 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 80 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 81 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 82 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 83 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 84 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 85 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 86 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 87 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 88 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 89 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 90 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 91 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 92 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 93 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 94 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 95 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 96 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 97 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 98 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 99 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 100 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 101 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 102 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 103 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 104 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 105 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 106 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 107 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 108 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 109 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 110 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 111 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 112 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 113 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 114 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 115 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 116 operands: lhs = Counter(8), rhs = Expression(150, Sub)
-- expression 117 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 118 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 119 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 120 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 121 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 122 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 123 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 124 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 125 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 126 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 127 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 128 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 129 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 130 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 131 operands: lhs = Expression(149, Add), rhs = Counter(9)
-- expression 132 operands: lhs = Counter(8), rhs = Expression(150, Sub)
-- expression 133 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 134 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 135 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 136 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 137 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 138 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 139 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 140 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 141 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 142 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 143 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 144 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 145 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 146 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 147 operands: lhs = Counter(9), rhs = Expression(148, Sub)
-- expression 148 operands: lhs = Expression(149, Add), rhs = Counter(9)
-- expression 149 operands: lhs = Counter(8), rhs = Expression(150, Sub)
-- expression 150 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 151 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 152 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 153 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 154 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 155 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 156 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 157 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 158 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 159 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 160 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 161 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 162 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 163 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(0), rhs = Counter(6)
+- expression 4 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 5 operands: lhs = Counter(0), rhs = Counter(8)
+- expression 6 operands: lhs = Counter(0), rhs = Counter(9)
 Number of file 0 mappings: 28
 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6)
 - Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(161, Add)) at (prev + 2, 9) to (start + 0, 17)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(163, Add)) at (prev + 2, 13) to (start + 0, 18)
-    = (c1 + (c0 - c1))
-- Code(Expression(162, Sub)) at (prev + 2, 13) to (start + 0, 18)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(159, Add)) at (prev + 3, 9) to (start + 0, 17)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
-- Code(Expression(161, Add)) at (prev + 2, 13) to (start + 0, 18)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(160, Sub)) at (prev + 2, 13) to (start + 0, 18)
-    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
-- Code(Expression(157, Add)) at (prev + 2, 9) to (start + 0, 17)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
-- Code(Expression(159, Add)) at (prev + 0, 20) to (start + 0, 25)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18)
+- Code(Expression(1, Sub)) at (prev + 2, 13) to (start + 0, 18)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18)
+- Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 18)
+    = (c0 - c3)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 25)
 - Code(Counter(4)) at (prev + 0, 29) to (start + 0, 34)
-- Code(Expression(155, Add)) at (prev + 1, 9) to (start + 0, 17)
-    = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
-- Code(Expression(157, Add)) at (prev + 0, 20) to (start + 0, 25)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 25)
 - Code(Counter(5)) at (prev + 0, 29) to (start + 0, 34)
-- Code(Expression(155, Add)) at (prev + 3, 9) to (start + 1, 16)
-    = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
-- Code(Expression(154, Sub)) at (prev + 2, 5) to (start + 3, 6)
-    = ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 16)
+- Code(Expression(3, Sub)) at (prev + 2, 5) to (start + 3, 6)
+    = (c0 - c6)
 - Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7)
-- Code(Expression(153, Add)) at (prev + 3, 9) to (start + 0, 16)
-    = (c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16)
 - Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6)
-- Code(Expression(152, Sub)) at (prev + 5, 5) to (start + 3, 6)
-    = ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)
-- Code(Expression(151, Add)) at (prev + 5, 8) to (start + 0, 16)
-    = (c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7))
-- Code(Expression(150, Sub)) at (prev + 0, 17) to (start + 2, 6)
-    = ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)
+- Code(Expression(4, Sub)) at (prev + 5, 5) to (start + 3, 6)
+    = (c0 - c7)
+- Code(Counter(0)) at (prev + 5, 8) to (start + 0, 16)
+- Code(Expression(5, Sub)) at (prev + 0, 17) to (start + 2, 6)
+    = (c0 - c8)
 - Code(Counter(8)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(149, Add)) at (prev + 2, 8) to (start + 0, 15)
-    = (c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8))
+- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 15)
 - Code(Counter(9)) at (prev + 0, 16) to (start + 2, 6)
-- Code(Expression(148, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9)
-- Code(Expression(147, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c9 + ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9))
+- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c9)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map
index 8dc35321133..9187dcbd865 100644
--- a/tests/coverage/loops_branches.cov-map
+++ b/tests/coverage/loops_branches.cov-map
@@ -1,57 +1,50 @@
 Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt
-Raw bytes (249): 0x[01, 01, 31, 05, 00, 00, 02, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, bf, 01, c3, 01, 0d, 00, 11, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, a3, 01, 19, 25, a6, 01, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, b6, 01, 03, 0d, 00, 0e, bb, 01, 00, 12, 00, 17, b6, 01, 01, 10, 00, 14, b2, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, ae, 01, 01, 12, 00, 13, ab, 01, 01, 11, 00, 22, a6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 9f, 01, 01, 05, 00, 06]
+Raw bytes (228): 0x[01, 01, 2a, 05, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, a3, 01, a7, 01, 0d, 00, 11, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 8f, 01, 19, 25, 92, 01, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 05, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 9a, 01, 03, 0d, 00, 0e, 9f, 01, 00, 12, 00, 17, 9a, 01, 01, 10, 00, 14, 96, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 46, 01, 12, 00, 13, 96, 01, 01, 11, 00, 22, 92, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 8b, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 49
+Number of expressions: 42
 - expression 0 operands: lhs = Counter(1), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 3 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 4 operands: lhs = Counter(3), rhs = Zero
-- expression 5 operands: lhs = Counter(4), rhs = Zero
-- expression 6 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 7 operands: lhs = Counter(3), rhs = Zero
-- expression 8 operands: lhs = Counter(4), rhs = Zero
-- expression 9 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 10 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 11 operands: lhs = Counter(3), rhs = Zero
-- expression 12 operands: lhs = Counter(4), rhs = Zero
-- expression 13 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 14 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 15 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 16 operands: lhs = Counter(3), rhs = Zero
-- expression 17 operands: lhs = Counter(4), rhs = Zero
-- expression 18 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 19 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 20 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 21 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 22 operands: lhs = Counter(3), rhs = Zero
-- expression 23 operands: lhs = Counter(4), rhs = Zero
-- expression 24 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 25 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 26 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 27 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 28 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 29 operands: lhs = Counter(3), rhs = Zero
-- expression 30 operands: lhs = Counter(4), rhs = Zero
-- expression 31 operands: lhs = Expression(42, Add), rhs = Counter(4)
-- expression 32 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 33 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 34 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 35 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 36 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 37 operands: lhs = Counter(3), rhs = Zero
-- expression 38 operands: lhs = Counter(4), rhs = Zero
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(6)
-- expression 40 operands: lhs = Counter(9), rhs = Expression(41, Sub)
-- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(4)
-- expression 42 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 43 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 46 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 47 operands: lhs = Counter(3), rhs = Zero
-- expression 48 operands: lhs = Counter(4), rhs = Zero
+- expression 1 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 2 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 3 operands: lhs = Counter(3), rhs = Zero
+- expression 4 operands: lhs = Counter(4), rhs = Zero
+- expression 5 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 6 operands: lhs = Counter(3), rhs = Zero
+- expression 7 operands: lhs = Counter(4), rhs = Zero
+- expression 8 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 9 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 10 operands: lhs = Counter(3), rhs = Zero
+- expression 11 operands: lhs = Counter(4), rhs = Zero
+- expression 12 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 13 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 14 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 15 operands: lhs = Counter(3), rhs = Zero
+- expression 16 operands: lhs = Counter(4), rhs = Zero
+- expression 17 operands: lhs = Expression(37, Sub), rhs = Zero
+- expression 18 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 19 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 20 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 21 operands: lhs = Counter(3), rhs = Zero
+- expression 22 operands: lhs = Counter(4), rhs = Zero
+- expression 23 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 24 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 25 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 26 operands: lhs = Counter(3), rhs = Zero
+- expression 27 operands: lhs = Counter(4), rhs = Zero
+- expression 28 operands: lhs = Expression(37, Sub), rhs = Counter(4)
+- expression 29 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 30 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 31 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 32 operands: lhs = Counter(3), rhs = Zero
+- expression 33 operands: lhs = Counter(4), rhs = Zero
+- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(6)
+- expression 35 operands: lhs = Counter(9), rhs = Expression(36, Sub)
+- expression 36 operands: lhs = Expression(37, Sub), rhs = Counter(4)
+- expression 37 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 38 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 39 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 40 operands: lhs = Counter(3), rhs = Zero
+- expression 41 operands: lhs = Counter(4), rhs = Zero
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21)
@@ -59,87 +52,78 @@ Number of file 0 mappings: 20
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
 - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15)
     = (c1 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = (Zero + (c1 - Zero))
+- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 30)
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
 - Code(Zero) at (prev + 1, 16) to (start + 1, 10)
-- Code(Expression(45, Sub)) at (prev + 3, 13) to (start + 0, 14)
+- Code(Expression(38, Sub)) at (prev + 3, 13) to (start + 0, 14)
     = (((c3 + Zero) + (c4 + Zero)) - c6)
-- Code(Expression(46, Add)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Expression(39, Add)) at (prev + 0, 18) to (start + 0, 23)
     = ((c3 + Zero) + (c4 + Zero))
-- Code(Expression(45, Sub)) at (prev + 1, 16) to (start + 0, 20)
+- Code(Expression(38, Sub)) at (prev + 1, 16) to (start + 0, 20)
     = (((c3 + Zero) + (c4 + Zero)) - c6)
-- Code(Expression(44, Sub)) at (prev + 1, 20) to (start + 0, 25)
+- Code(Expression(37, Sub)) at (prev + 1, 20) to (start + 0, 25)
     = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(43, Sub)) at (prev + 1, 18) to (start + 0, 19)
+- Code(Expression(17, Sub)) at (prev + 1, 18) to (start + 0, 19)
     = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)
-- Code(Expression(42, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = (Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero))
-- Code(Expression(41, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4)
+- Code(Expression(37, Sub)) at (prev + 1, 17) to (start + 0, 34)
+    = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero)
+- Code(Expression(36, Sub)) at (prev + 0, 34) to (start + 0, 35)
+    = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - c4)
 - Code(Zero) at (prev + 1, 20) to (start + 1, 14)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(39, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = ((c9 + ((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4)) + c6)
+- Code(Expression(34, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = ((c9 + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - c4)) + c6)
 
 Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt
-Raw bytes (253): 0x[01, 01, 33, 01, 00, 02, 00, 00, 0e, 02, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, c7, 01, cb, 01, 00, 0d, 00, 15, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, b3, 01, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, ab, 01, 25, ae, 01, 19, b3, 01, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, be, 01, 02, 0d, 00, 0e, c3, 01, 00, 12, 00, 17, be, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ba, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b6, 01, 01, 12, 00, 13, b3, 01, 01, 11, 00, 22, ae, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, a7, 01, 01, 05, 00, 06]
+Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0e, 00, 0f, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 12, 00, 13, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 51
+Number of expressions: 43
 - expression 0 operands: lhs = Counter(0), rhs = Zero
 - expression 1 operands: lhs = Expression(0, Sub), rhs = Zero
-- expression 2 operands: lhs = Zero, rhs = Expression(3, Sub)
-- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero
-- expression 4 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 5 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 6 operands: lhs = Zero, rhs = Counter(3)
-- expression 7 operands: lhs = Zero, rhs = Counter(5)
-- expression 8 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 9 operands: lhs = Zero, rhs = Counter(3)
-- expression 10 operands: lhs = Zero, rhs = Counter(5)
-- expression 11 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 12 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 13 operands: lhs = Zero, rhs = Counter(3)
-- expression 14 operands: lhs = Zero, rhs = Counter(5)
-- expression 15 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 16 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 17 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 18 operands: lhs = Zero, rhs = Counter(3)
-- expression 19 operands: lhs = Zero, rhs = Counter(5)
-- expression 20 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 21 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 22 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 23 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 24 operands: lhs = Zero, rhs = Counter(3)
-- expression 25 operands: lhs = Zero, rhs = Counter(5)
-- expression 26 operands: lhs = Zero, rhs = Expression(45, Sub)
-- expression 27 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 28 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 29 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 30 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 31 operands: lhs = Zero, rhs = Counter(3)
-- expression 32 operands: lhs = Zero, rhs = Counter(5)
-- expression 33 operands: lhs = Expression(44, Add), rhs = Counter(5)
-- expression 34 operands: lhs = Zero, rhs = Expression(45, Sub)
-- expression 35 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 36 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 37 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 38 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 39 operands: lhs = Zero, rhs = Counter(3)
-- expression 40 operands: lhs = Zero, rhs = Counter(5)
-- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(9)
-- expression 42 operands: lhs = Expression(43, Sub), rhs = Counter(6)
-- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(5)
-- expression 44 operands: lhs = Zero, rhs = Expression(45, Sub)
-- expression 45 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 46 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 49 operands: lhs = Zero, rhs = Counter(3)
-- expression 50 operands: lhs = Zero, rhs = Counter(5)
+- expression 2 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 3 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 4 operands: lhs = Zero, rhs = Counter(3)
+- expression 5 operands: lhs = Zero, rhs = Counter(5)
+- expression 6 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 7 operands: lhs = Zero, rhs = Counter(3)
+- expression 8 operands: lhs = Zero, rhs = Counter(5)
+- expression 9 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 10 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 11 operands: lhs = Zero, rhs = Counter(3)
+- expression 12 operands: lhs = Zero, rhs = Counter(5)
+- expression 13 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 14 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 15 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 16 operands: lhs = Zero, rhs = Counter(3)
+- expression 17 operands: lhs = Zero, rhs = Counter(5)
+- expression 18 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 19 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 20 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 21 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 22 operands: lhs = Zero, rhs = Counter(3)
+- expression 23 operands: lhs = Zero, rhs = Counter(5)
+- expression 24 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 25 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 26 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 27 operands: lhs = Zero, rhs = Counter(3)
+- expression 28 operands: lhs = Zero, rhs = Counter(5)
+- expression 29 operands: lhs = Expression(38, Sub), rhs = Counter(5)
+- expression 30 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 31 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 32 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 33 operands: lhs = Zero, rhs = Counter(3)
+- expression 34 operands: lhs = Zero, rhs = Counter(5)
+- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(9)
+- expression 36 operands: lhs = Expression(37, Sub), rhs = Counter(6)
+- expression 37 operands: lhs = Expression(38, Sub), rhs = Counter(5)
+- expression 38 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 40 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 41 operands: lhs = Zero, rhs = Counter(3)
+- expression 42 operands: lhs = Zero, rhs = Counter(5)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17)
 - Code(Zero) at (prev + 1, 18) to (start + 1, 10)
@@ -147,31 +131,31 @@ Number of file 0 mappings: 20
     = (c0 - Zero)
 - Code(Zero) at (prev + 1, 23) to (start + 0, 27)
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
-- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 15)
+- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 15)
     = ((c0 - Zero) - Zero)
-- Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = (Zero + ((c0 - Zero) - Zero))
+- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 30)
+    = (c0 - Zero)
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
-- Code(Expression(47, Sub)) at (prev + 2, 13) to (start + 0, 14)
+- Code(Expression(39, Sub)) at (prev + 2, 13) to (start + 0, 14)
     = (((Zero + c3) + (Zero + c5)) - c6)
-- Code(Expression(48, Add)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Expression(40, Add)) at (prev + 0, 18) to (start + 0, 23)
     = ((Zero + c3) + (Zero + c5))
-- Code(Expression(47, Sub)) at (prev + 1, 16) to (start + 0, 21)
+- Code(Expression(39, Sub)) at (prev + 1, 16) to (start + 0, 21)
     = (((Zero + c3) + (Zero + c5)) - c6)
 - Code(Zero) at (prev + 0, 22) to (start + 1, 14)
-- Code(Expression(46, Sub)) at (prev + 2, 20) to (start + 0, 25)
+- Code(Expression(38, Sub)) at (prev + 2, 20) to (start + 0, 25)
     = ((((Zero + c3) + (Zero + c5)) - c6) - Zero)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(45, Sub)) at (prev + 1, 18) to (start + 0, 19)
+- Code(Expression(18, Sub)) at (prev + 1, 18) to (start + 0, 19)
     = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)
-- Code(Expression(44, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = (Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero))
-- Code(Expression(43, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5)
+- Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 34)
+    = ((((Zero + c3) + (Zero + c5)) - c6) - Zero)
+- Code(Expression(37, Sub)) at (prev + 0, 34) to (start + 0, 35)
+    = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - c5)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(41, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = ((((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5) + c6) + c9)
+- Code(Expression(35, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = (((((((Zero + c3) + (Zero + c5)) - c6) - Zero) - c5) + c6) + c9)
 
 Function name: loops_branches::main
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02]
diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map
index d63407a99c3..60b7024533d 100644
--- a/tests/coverage/match_or_pattern.cov-map
+++ b/tests/coverage/match_or_pattern.cov-map
@@ -1,83 +1,75 @@
 Function name: match_or_pattern::main
-Raw bytes (202): 0x[01, 01, 23, 01, 05, 05, 02, 09, 0d, 2f, 11, 09, 0d, 2b, 15, 2f, 11, 09, 0d, 15, 26, 2b, 15, 2f, 11, 09, 0d, 19, 1d, 57, 21, 19, 1d, 53, 25, 57, 21, 19, 1d, 25, 4e, 53, 25, 57, 21, 19, 1d, 29, 2d, 7f, 31, 29, 2d, 7b, 35, 7f, 31, 29, 2d, 35, 76, 7b, 35, 7f, 31, 29, 2d, 39, 3d, 8b, 01, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 07, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 2f, 01, 0e, 00, 10, 2b, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 26, 03, 06, 00, 07, 23, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 57, 01, 0e, 00, 10, 53, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 4e, 03, 06, 00, 07, 4b, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 7f, 01, 0e, 00, 10, 7b, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 76, 03, 06, 00, 07, 73, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 8b, 01, 01, 0e, 00, 10, 87, 01, 02, 01, 00, 02]
+Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 06, 00, 07, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 06, 00, 07, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 06, 00, 07, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 35
+Number of expressions: 28
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 5 operands: lhs = Expression(10, Add), rhs = Counter(5)
-- expression 6 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(5), rhs = Expression(9, Sub)
-- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5)
-- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 13 operands: lhs = Expression(21, Add), rhs = Counter(8)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(8, Add), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 4 operands: lhs = Expression(7, Add), rhs = Counter(5)
+- expression 5 operands: lhs = Expression(8, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(4)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 10 operands: lhs = Expression(16, Add), rhs = Counter(8)
+- expression 11 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 12 operands: lhs = Expression(15, Add), rhs = Counter(9)
+- expression 13 operands: lhs = Expression(16, Add), rhs = Counter(8)
 - expression 14 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 15 operands: lhs = Expression(20, Add), rhs = Counter(9)
-- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(8)
-- expression 17 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 18 operands: lhs = Counter(9), rhs = Expression(19, Sub)
-- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(9)
-- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(8)
-- expression 21 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 15 operands: lhs = Expression(16, Add), rhs = Counter(8)
+- expression 16 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 17 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 18 operands: lhs = Expression(24, Add), rhs = Counter(12)
+- expression 19 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 20 operands: lhs = Expression(23, Add), rhs = Counter(13)
+- expression 21 operands: lhs = Expression(24, Add), rhs = Counter(12)
 - expression 22 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 23 operands: lhs = Expression(31, Add), rhs = Counter(12)
+- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(12)
 - expression 24 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 25 operands: lhs = Expression(30, Add), rhs = Counter(13)
-- expression 26 operands: lhs = Expression(31, Add), rhs = Counter(12)
-- expression 27 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 28 operands: lhs = Counter(13), rhs = Expression(29, Sub)
-- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(13)
-- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(12)
-- expression 31 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 32 operands: lhs = Counter(14), rhs = Counter(15)
-- expression 33 operands: lhs = Expression(34, Add), rhs = Counter(16)
-- expression 34 operands: lhs = Counter(14), rhs = Counter(15)
+- expression 25 operands: lhs = Counter(14), rhs = Counter(15)
+- expression 26 operands: lhs = Expression(27, Add), rhs = Counter(16)
+- expression 27 operands: lhs = Counter(14), rhs = Counter(15)
 Number of file 0 mappings: 25
 - Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15)
 - Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6)
 - Code(Expression(0, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 11) to (start + 0, 17)
 - Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29)
-- Code(Expression(11, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(8, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c2 + c3)
-- Code(Expression(10, Add)) at (prev + 2, 8) to (start + 0, 15)
+- Code(Expression(7, Add)) at (prev + 2, 8) to (start + 0, 15)
     = ((c2 + c3) + c4)
 - Code(Counter(5)) at (prev + 0, 16) to (start + 3, 6)
-- Code(Expression(9, Sub)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(4, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (((c2 + c3) + c4) - c5)
-- Code(Expression(8, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c5 + (((c2 + c3) + c4) - c5))
+- Code(Expression(7, Add)) at (prev + 1, 11) to (start + 0, 17)
+    = ((c2 + c3) + c4)
 - Code(Counter(8)) at (prev + 1, 27) to (start + 0, 29)
-- Code(Expression(21, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(16, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c6 + c7)
-- Code(Expression(20, Add)) at (prev + 2, 8) to (start + 0, 15)
+- Code(Expression(15, Add)) at (prev + 2, 8) to (start + 0, 15)
     = ((c6 + c7) + c8)
 - Code(Counter(9)) at (prev + 0, 16) to (start + 3, 6)
-- Code(Expression(19, Sub)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(12, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (((c6 + c7) + c8) - c9)
-- Code(Expression(18, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c9 + (((c6 + c7) + c8) - c9))
+- Code(Expression(15, Add)) at (prev + 1, 11) to (start + 0, 17)
+    = ((c6 + c7) + c8)
 - Code(Counter(12)) at (prev + 1, 27) to (start + 0, 29)
-- Code(Expression(31, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(24, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c10 + c11)
-- Code(Expression(30, Add)) at (prev + 2, 8) to (start + 0, 15)
+- Code(Expression(23, Add)) at (prev + 2, 8) to (start + 0, 15)
     = ((c10 + c11) + c12)
 - Code(Counter(13)) at (prev + 0, 16) to (start + 3, 6)
-- Code(Expression(29, Sub)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(20, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (((c10 + c11) + c12) - c13)
-- Code(Expression(28, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c13 + (((c10 + c11) + c12) - c13))
+- Code(Expression(23, Add)) at (prev + 1, 11) to (start + 0, 17)
+    = ((c10 + c11) + c12)
 - Code(Counter(16)) at (prev + 1, 27) to (start + 0, 29)
-- Code(Expression(34, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(27, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c14 + c15)
-- Code(Expression(33, Add)) at (prev + 2, 1) to (start + 0, 2)
+- Code(Expression(26, Add)) at (prev + 2, 1) to (start + 0, 2)
     = ((c14 + c15) + c16)
 
diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map
index 05b6448bbd2..e623f6480b9 100644
--- a/tests/coverage/no_cov_crate.cov-map
+++ b/tests/coverage/no_cov_crate.cov-map
@@ -47,32 +47,28 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 63, 5) to (start + 11, 6)
 
 Function name: no_cov_crate::nested_fns::outer_both_covered::inner
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 67, 9) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
 Function name: no_cov_crate::nested_fns::outer_not_covered::inner
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 38, 9) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map
index 39a5c05f879..cb31f3d1f3e 100644
--- a/tests/coverage/overflow.cov-map
+++ b/tests/coverage/overflow.cov-map
@@ -27,17 +27,15 @@ Number of file 0 mappings: 9
 - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)
 
 Function name: overflow::might_overflow
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 07, 01, 09, 05, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 01, 01, 09, 05, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 5, 1) to (start + 1, 18)
 - Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 5, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2)
 
diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map
index 0a342cb3673..541f7bf8fbd 100644
--- a/tests/coverage/simple_loop.cov-map
+++ b/tests/coverage/simple_loop.cov-map
@@ -1,27 +1,18 @@
 Function name: simple_loop::main
-Raw bytes (57): 0x[01, 01, 09, 01, 05, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 1f, 05, 0d, 02, 0e, 1a, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 1a, 06, 01, 00, 02]
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 07, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 01, 06, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 9
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(8, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 3 operands: lhs = Expression(7, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(8, Add), rhs = Counter(2)
-- expression 5 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(2)
-- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(2)
-- expression 8 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16)
 - Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6)
 - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(7, Add)) at (prev + 5, 13) to (start + 2, 14)
-    = ((c1 + (c0 - c1)) + c2)
-- Code(Expression(6, Sub)) at (prev + 4, 13) to (start + 0, 18)
-    = (((c1 + (c0 - c1)) + c2) - c2)
+- Code(Expression(1, Add)) at (prev + 5, 13) to (start + 2, 14)
+    = (c0 + c2)
+- Code(Counter(0)) at (prev + 4, 13) to (start + 0, 18)
 - Code(Counter(2)) at (prev + 2, 10) to (start + 3, 10)
-- Code(Expression(6, Sub)) at (prev + 6, 1) to (start + 0, 2)
-    = (((c1 + (c0 - c1)) + c2) - c2)
+- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map
index 7c242e2c328..49819b23482 100644
--- a/tests/coverage/simple_match.cov-map
+++ b/tests/coverage/simple_match.cov-map
@@ -1,32 +1,29 @@
 Function name: simple_match::main
-Raw bytes (78): 0x[01, 01, 0c, 01, 05, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 27, 05, 09, 00, 0d, 22, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 22, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02]
+Raw bytes (72): 0x[01, 01, 09, 01, 05, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1f, 05, 09, 00, 0d, 1a, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 1a, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 12
+Number of expressions: 9
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
-- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 4 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 5 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 9 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(8, Add)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(7, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(0), rhs = Expression(8, Add)
+- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4)
+- expression 7 operands: lhs = Counter(0), rhs = Expression(8, Add)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(9, Add)) at (prev + 5, 9) to (start + 0, 13)
-    = ((c1 + (c0 - c1)) + (c2 + c3))
-- Code(Expression(8, Sub)) at (prev + 5, 13) to (start + 0, 22)
-    = (((c1 + (c0 - c1)) + (c2 + c3)) - c4)
+- Code(Expression(7, Add)) at (prev + 5, 9) to (start + 0, 13)
+    = (c0 + (c2 + c3))
+- Code(Expression(6, Sub)) at (prev + 5, 13) to (start + 0, 22)
+    = ((c0 + (c2 + c3)) - c4)
 - Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14)
-- Code(Expression(8, Sub)) at (prev + 2, 17) to (start + 2, 18)
-    = (((c1 + (c0 - c1)) + (c2 + c3)) - c4)
+- Code(Expression(6, Sub)) at (prev + 2, 17) to (start + 2, 18)
+    = ((c0 + (c2 + c3)) - c4)
 - Code(Counter(2)) at (prev + 4, 13) to (start + 7, 14)
 - Code(Counter(3)) at (prev + 10, 13) to (start + 0, 15)
 - Code(Counter(4)) at (prev + 3, 1) to (start + 0, 2)
diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map
index 3cbda6fbe1a..361b70fb74f 100644
--- a/tests/coverage/sort_groups.cov-map
+++ b/tests/coverage/sort_groups.cov-map
@@ -1,77 +1,67 @@
 Function name: sort_groups::generic_fn::<&str>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::generic_fn::<()>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::generic_fn::<char>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::generic_fn::<i32>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 02, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 02, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 6, 1) to (start + 4, 35)
 - Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 2, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2)
 
 Function name: sort_groups::other_fn
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11]
diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map
index 83f1869a31e..49e6c7ceefc 100644
--- a/tests/coverage/try_error_result.cov-map
+++ b/tests/coverage/try_error_result.cov-map
@@ -1,62 +1,54 @@
 Function name: <try_error_result::Thing1>::get_thing_2
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 07, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 41, 5) to (start + 1, 24)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20)
 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: <try_error_result::Thing2>::call
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 07, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 52, 5) to (start + 1, 24)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20)
 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: try_error_result::call
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 4, 1) to (start + 1, 20)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: try_error_result::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 115, 1) to (start + 2, 12)
 - Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: try_error_result::test1
 Raw bytes (75): 0x[01, 01, 08, 01, 07, 00, 09, 03, 0d, 12, 1d, 03, 0d, 1b, 0d, 1f, 00, 11, 00, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 12, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 17, 01, 01, 00, 02]
diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map
index aedfb2071c1..06a2c930498 100644
--- a/tests/coverage/unicode.cov-map
+++ b/tests/coverage/unicode.cov-map
@@ -1,31 +1,27 @@
 Function name: unicode::main
-Raw bytes (67): 0x[01, 01, 09, 01, 05, 03, 05, 1e, 0d, 22, 09, 03, 05, 11, 1b, 1e, 0d, 22, 09, 03, 05, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 22, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 1b, 02, 06, 00, 07, 17, 02, 05, 01, 02]
+Raw bytes (61): 0x[01, 01, 06, 01, 05, 16, 0d, 01, 09, 11, 13, 16, 0d, 01, 09, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 13, 02, 06, 00, 07, 0f, 02, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 9
+Number of expressions: 6
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Expression(7, Sub), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(8, Sub), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(1)
-- expression 5 operands: lhs = Counter(4), rhs = Expression(6, Add)
-- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(3)
-- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(2)
-- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(5, Sub), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(4), rhs = Expression(4, Add)
+- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12)
 - Code(Expression(0, Add)) at (prev + 0, 16) to (start + 0, 27)
     = (c0 + c1)
 - Code(Counter(1)) at (prev + 0, 28) to (start + 0, 40)
-- Code(Expression(8, Sub)) at (prev + 2, 8) to (start + 0, 37)
-    = ((c0 + c1) - c1)
+- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 37)
 - Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70)
 - Code(Counter(4)) at (prev + 0, 71) to (start + 2, 6)
-- Code(Expression(6, Add)) at (prev + 2, 6) to (start + 0, 7)
-    = ((((c0 + c1) - c1) - c2) + c3)
-- Code(Expression(5, Add)) at (prev + 2, 5) to (start + 1, 2)
-    = (c4 + ((((c0 + c1) - c1) - c2) + c3))
+- Code(Expression(4, Add)) at (prev + 2, 6) to (start + 0, 7)
+    = ((c0 - c2) + c3)
+- Code(Expression(3, Add)) at (prev + 2, 5) to (start + 1, 2)
+    = (c4 + ((c0 - c2) + c3))
 
 Function name: unicode::他 (unused)
 Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25]
diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map
index 6b621825c88..55ceb46b060 100644
--- a/tests/coverage/uses_inline_crate.cov-map
+++ b/tests/coverage/uses_inline_crate.cov-map
@@ -7,19 +7,17 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2)
 
 Function name: used_inline_crate::used_inline_function
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 01, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - 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 + 20, 1) to (start + 6, 15)
 - Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
 
 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02]
diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map
index c6557b48e27..4d813a935a0 100644
--- a/tests/coverage/while.cov-map
+++ b/tests/coverage/while.cov-map
@@ -1,15 +1,13 @@
 Function name: while::main
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 03, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 06, 03, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Expression(0, Add), rhs = Zero
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16)
 - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 20)
     = (c0 + Zero)
 - Code(Zero) at (prev + 0, 21) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c0 + Zero) - Zero)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/crashes/124833.rs b/tests/crashes/124833.rs
new file mode 100644
index 00000000000..f1c4847b544
--- /dev/null
+++ b/tests/crashes/124833.rs
@@ -0,0 +1,10 @@
+//@ known-bug: rust-lang/rust#124833
+#![feature(generic_const_items)]
+
+trait Trait {
+    const C<'a>: &'a str;
+}
+
+impl Trait for () {
+    const C<'a>:  = "C";
+}
diff --git a/tests/crashes/124857.rs b/tests/crashes/124857.rs
new file mode 100644
index 00000000000..4b952fd64cc
--- /dev/null
+++ b/tests/crashes/124857.rs
@@ -0,0 +1,11 @@
+//@ known-bug: rust-lang/rust#124857
+//@ compile-flags: -Znext-solver=coherence
+
+#![feature(effects)]
+
+#[const_trait]
+trait Foo {}
+
+impl const Foo for i32 {}
+
+impl<T> const Foo for T where T: ~const Foo {}
diff --git a/tests/crashes/124891.rs b/tests/crashes/124891.rs
new file mode 100644
index 00000000000..9b5892418c8
--- /dev/null
+++ b/tests/crashes/124891.rs
@@ -0,0 +1,22 @@
+//@ known-bug: rust-lang/rust#124891
+
+type Tait = impl FnOnce() -> ();
+
+fn reify_as_tait() -> Thunk<Tait> {
+    Thunk::new(|cont| cont)
+}
+
+struct Thunk<F>(F);
+
+impl<F> Thunk<F> {
+    fn new(f: F)
+    where
+        F: ContFn,
+    {
+        todo!();
+    }
+}
+
+trait ContFn {}
+
+impl<F: FnOnce(Tait) -> ()> ContFn for F {}
diff --git a/tests/crashes/124894.rs b/tests/crashes/124894.rs
new file mode 100644
index 00000000000..230cf4a89c1
--- /dev/null
+++ b/tests/crashes/124894.rs
@@ -0,0 +1,11 @@
+//@ known-bug: rust-lang/rust#124894
+//@ compile-flags: -Znext-solver=coherence
+
+#![feature(generic_const_exprs)]
+
+pub trait IsTrue<const mem: bool> {}
+impl<T> IsZST for T where (): IsTrue<{ std::mem::size_of::<T>() == 0 }> {}
+
+pub trait IsZST {}
+
+impl IsZST for IsZST {}
diff --git a/tests/crashes/125081.rs b/tests/crashes/125081.rs
new file mode 100644
index 00000000000..7139caaa00d
--- /dev/null
+++ b/tests/crashes/125081.rs
@@ -0,0 +1,7 @@
+//@ known-bug: rust-lang/rust#125081
+
+use std::cell::Cell;
+
+fn main() {
+    let _: Cell<&str, "a"> = Cell::new('β);
+}
diff --git a/tests/crashes/125099.rs b/tests/crashes/125099.rs
new file mode 100644
index 00000000000..bfc8c8fdcf6
--- /dev/null
+++ b/tests/crashes/125099.rs
@@ -0,0 +1,24 @@
+//@ known-bug: rust-lang/rust#125099
+
+pub trait ContFn<T>: Fn(T) -> Self::Future {
+    type Future;
+}
+impl<T, F> ContFn<T> for F
+where
+    F: Fn(T),
+{
+    type Future = ();
+}
+
+pub trait SeqHandler {
+    type Requires;
+    fn process<F: ContFn<Self::Requires>>() -> impl Sized;
+}
+
+pub struct ConvertToU64;
+impl SeqHandler for ConvertToU64 {
+    type Requires = u64;
+    fn process<F: ContFn<Self::Requires>>() -> impl Sized {}
+}
+
+fn main() {}
diff --git a/tests/crashes/125155.rs b/tests/crashes/125155.rs
new file mode 100644
index 00000000000..165061d4b52
--- /dev/null
+++ b/tests/crashes/125155.rs
@@ -0,0 +1,17 @@
+//@ known-bug: rust-lang/rust#125155
+
+enum NestedEnum {
+    First,
+    Second,
+    Third
+}
+enum Enum {
+    Variant2(Option<*mut &'a &'b ()>)
+}
+
+
+fn foo(x: Enum) -> isize {
+    match x {
+      Enum::Variant2(NestedEnum::Third) => 4,
+    }
+}
diff --git a/tests/crashes/125185.rs b/tests/crashes/125185.rs
new file mode 100644
index 00000000000..8693d6c7662
--- /dev/null
+++ b/tests/crashes/125185.rs
@@ -0,0 +1,16 @@
+//@ known-bug: rust-lang/rust#125185
+//@ compile-flags: -Zvalidate-mir
+
+type Foo = impl Send;
+
+struct A;
+
+const VALUE: Foo = value();
+
+fn test(foo: Foo<'a>, f: impl for<'b> FnMut()) {
+    match VALUE {
+        0 | 0 => {}
+
+        _ => (),
+    }
+}
diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs
new file mode 100644
index 00000000000..18196d7b34f
--- /dev/null
+++ b/tests/crashes/125249.rs
@@ -0,0 +1,8 @@
+//@ known-bug: rust-lang/rust#125185
+#![feature(return_position_impl_trait_in_trait, return_type_notation)]
+
+trait IntFactory {
+    fn stream(&self) -> impl IntFactory<stream(): IntFactory<stream(): Send> + Send>;
+}
+
+pub fn main() {}
diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs
index 48d40d167ba..4a6adc2fc53 100644
--- a/tests/debuginfo/strings-and-strs.rs
+++ b/tests/debuginfo/strings-and-strs.rs
@@ -7,7 +7,7 @@
 // gdb-command:run
 
 // gdb-command:print plain_string
-// gdbr-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x55555555ab80}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, len: 5}}
+// gdbr-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x[...]}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, len: 5}}
 
 // gdb-command:print plain_str
 // gdbr-check:$2 = "Hello"
@@ -19,7 +19,7 @@
 // gdbr-check:$4 = ("Hello", "World")
 
 // gdb-command:print str_in_rc
-// gdbr-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull<alloc::rc::RcBox<&str>> {pointer: 0x55555555aae0}, phantom: core::marker::PhantomData<alloc::rc::RcBox<&str>>, alloc: alloc::alloc::Global}
+// gdbr-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull<alloc::rc::RcBox<&str>> {pointer: 0x[...]}, phantom: core::marker::PhantomData<alloc::rc::RcBox<&str>>, alloc: alloc::alloc::Global}
 
 
 // === LLDB TESTS ==================================================================================
diff --git a/tests/incremental/foreign.rs b/tests/incremental/foreign.rs
index cb040fe1296..1af203e9b77 100644
--- a/tests/incremental/foreign.rs
+++ b/tests/incremental/foreign.rs
@@ -1,38 +1,21 @@
 // Test what happens we save incremental compilation state that makes
 // use of foreign items. This used to ICE (#34991).
-//@ ignore-sgx no libc
-
 //@ revisions: rpass1
 
-#![feature(rustc_private)]
-
-extern crate libc;
-
 use std::ffi::CString;
 
 mod mlibc {
-    use libc::{c_char, c_long, c_longlong};
-
     extern "C" {
-        pub fn atol(x: *const c_char) -> c_long;
-        pub fn atoll(x: *const c_char) -> c_longlong;
+        // strlen is provided either by an external library or compiler-builtins as a fallback
+        pub fn strlen(x: *const std::ffi::c_char) -> usize;
     }
 }
 
-fn atol(s: String) -> isize {
-    let c = CString::new(s).unwrap();
-    unsafe { mlibc::atol(c.as_ptr()) as isize }
-}
-
-fn atoll(s: String) -> i64 {
+fn strlen(s: String) -> usize {
     let c = CString::new(s).unwrap();
-    unsafe { mlibc::atoll(c.as_ptr()) as i64 }
+    unsafe { mlibc::strlen(c.as_ptr()) }
 }
 
 pub fn main() {
-    assert_eq!(atol("1024".to_string()) * 10, atol("10240".to_string()));
-    assert_eq!(
-        (atoll("11111111111111111".to_string()) * 10),
-        atoll("111111111111111110".to_string())
-    );
+    assert_eq!(strlen("1024".to_string()), strlen("2048".to_string()));
 }
diff --git a/tests/mir-opt/building/custom/operators.f.built.after.mir b/tests/mir-opt/building/custom/operators.f.built.after.mir
index 33eb6b720e8..cac82f7b3ea 100644
--- a/tests/mir-opt/building/custom/operators.f.built.after.mir
+++ b/tests/mir-opt/building/custom/operators.f.built.after.mir
@@ -21,7 +21,7 @@ fn f(_1: i32, _2: bool) -> i32 {
         _2 = Le(_1, _1);
         _2 = Ge(_1, _1);
         _2 = Gt(_1, _1);
-        _3 = CheckedAdd(_1, _1);
+        _3 = AddWithOverflow(_1, _1);
         _2 = (_3.1: bool);
         _1 = (_3.0: i32);
         _0 = _1;
diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
index d5117b2f638..0e93c167ebc 100644
--- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
@@ -11,7 +11,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 1_u32, const 1_u32);
+-         _2 = AddWithOverflow(const 1_u32, const 1_u32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind unreachable];
 +         _2 = const (2_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
index 2118d37672c..589eed5776c 100644
--- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
@@ -11,7 +11,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 1_u32, const 1_u32);
+-         _2 = AddWithOverflow(const 1_u32, const 1_u32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind continue];
 +         _2 = const (2_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
index 8301a4c1aa8..f24b9755eae 100644
--- a/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
@@ -14,7 +14,7 @@
           StorageLive(_1);
           StorageLive(_2);
 -         _2 = const 2_u32 as u8 (IntToInt);
--         _3 = CheckedAdd(_2, const 1_u8);
+-         _3 = AddWithOverflow(_2, const 1_u8);
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind unreachable];
 +         _2 = const 2_u8;
 +         _3 = const (3_u8, false);
diff --git a/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
index 8dcbfd2c2c1..44ff313b532 100644
--- a/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
@@ -14,7 +14,7 @@
           StorageLive(_1);
           StorageLive(_2);
 -         _2 = const 2_u32 as u8 (IntToInt);
--         _3 = CheckedAdd(_2, const 1_u8);
+-         _3 = AddWithOverflow(_2, const 1_u8);
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind continue];
 +         _2 = const 2_u8;
 +         _3 = const (3_u8, false);
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
index 8c5a0df94f4..de9cb7a47a2 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
index 7887a8a9072..1f19a13c1e8 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
index 51f8227c36b..b2d40daa80c 100644
--- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
@@ -6,7 +6,7 @@
       let mut _1: (u32, bool);
   
       bb0: {
--         _1 = CheckedAdd(const 2_u32, const 2_u32);
+-         _1 = AddWithOverflow(const 2_u32, const 2_u32);
 -         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind unreachable];
 +         _1 = const (4_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
index 8174b4edea6..2eafc51cd3d 100644
--- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
@@ -6,7 +6,7 @@
       let mut _1: (u32, bool);
   
       bb0: {
--         _1 = CheckedAdd(const 2_u32, const 2_u32);
+-         _1 = AddWithOverflow(const 2_u32, const 2_u32);
 -         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
 +         _1 = const (4_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index 3606a9e3932..01876b494c5 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -8,12 +8,11 @@
       let mut _3: !;
   
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) };
-+     coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Subtract, rhs: Counter(1) };
 +     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11;
 +     coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:11:5 - 12:17;
-+     coverage Code(Expression(1)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
 +     coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11;
-+     coverage Code(Expression(1)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
@@ -35,7 +34,6 @@
       }
   
       bb4: {
-+         Coverage::ExpressionUsed(1);
           _0 = const ();
           StorageDead(_2);
           return;
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index 34d011540b9..efb1559baf5 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -8,11 +8,10 @@
       coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
   
       coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
-      coverage ExpressionId(1) => Expression { lhs: Counter(1), op: Add, rhs: Expression(0) };
       coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
       coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
       coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
-      coverage Code(Expression(1)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
+      coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
       coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
   
       bb0: {
@@ -44,7 +43,6 @@
       }
   
       bb4: {
-          Coverage::ExpressionUsed(1);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index 6756d5c1e1b..a0fe9a5c05c 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -8,11 +8,10 @@
       coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
   
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
-+     coverage ExpressionId(1) => Expression { lhs: Counter(1), op: Add, rhs: Expression(0) };
 +     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
 +     coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
 +     coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
-+     coverage Code(Expression(1)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
 +     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
 + 
       bb0: {
@@ -41,7 +40,6 @@
       }
   
       bb4: {
-+         Coverage::ExpressionUsed(1);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
index b35538f8972..53663c6476b 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
@@ -40,7 +40,7 @@
 +         _4 = const 1_i32;
           StorageLive(_5);
 -         _5 = _2;
--         _6 = CheckedAdd(_4, _5);
+-         _6 = AddWithOverflow(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind unreachable];
 +         _5 = const 2_i32;
 +         _6 = const (3_i32, false);
@@ -57,7 +57,7 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _9 = _7;
--         _10 = CheckedAdd(_9, const 1_i32);
+-         _10 = AddWithOverflow(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind unreachable];
 +         _9 = const i32::MAX;
 +         _10 = const (i32::MIN, true);
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
index 05c96969233..34feb2a6406 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
@@ -40,7 +40,7 @@
 +         _4 = const 1_i32;
           StorageLive(_5);
 -         _5 = _2;
--         _6 = CheckedAdd(_4, _5);
+-         _6 = AddWithOverflow(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue];
 +         _5 = const 2_i32;
 +         _6 = const (3_i32, false);
@@ -57,7 +57,7 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _9 = _7;
--         _10 = CheckedAdd(_9, const 1_i32);
+-         _10 = AddWithOverflow(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue];
 +         _9 = const i32::MAX;
 +         _10 = const (i32::MIN, true);
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
index ca1bd737caf..8d62de0c821 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
index 0d7fe9360c1..25624851cb3 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
index a45d9920a68..5bf22af6ae8 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
@@ -31,9 +31,9 @@
           StorageLive(_3);
           StorageLive(_4);
           _4 = _1;
--         _5 = CheckedAdd(_4, const 0_u64);
+-         _5 = AddWithOverflow(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind unreachable];
-+         _5 = CheckedAdd(_1, const 0_u64);
++         _5 = AddWithOverflow(_1, const 0_u64);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable];
       }
   
@@ -52,7 +52,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = _1;
--         _9 = CheckedSub(_8, const 0_u64);
+-         _9 = SubWithOverflow(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind unreachable];
 +         _9 = _5;
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable];
@@ -76,7 +76,7 @@
           _12 = _1;
           StorageLive(_13);
           _13 = _1;
--         _14 = CheckedSub(_12, _13);
+-         _14 = SubWithOverflow(_12, _13);
 -         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind unreachable];
 +         _14 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind unreachable];
@@ -99,7 +99,7 @@
           StorageLive(_16);
           StorageLive(_17);
           _17 = _1;
--         _18 = CheckedMul(_17, const 0_u64);
+-         _18 = MulWithOverflow(_17, const 0_u64);
 -         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind unreachable];
 +         _18 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind unreachable];
@@ -120,7 +120,7 @@
           StorageLive(_20);
           StorageLive(_21);
           _21 = _1;
--         _22 = CheckedMul(_21, const 1_u64);
+-         _22 = MulWithOverflow(_21, const 1_u64);
 -         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind unreachable];
 +         _22 = _5;
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind unreachable];
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
index 9033b392bd4..18d2029e445 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
@@ -31,9 +31,9 @@
           StorageLive(_3);
           StorageLive(_4);
           _4 = _1;
--         _5 = CheckedAdd(_4, const 0_u64);
+-         _5 = AddWithOverflow(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind continue];
-+         _5 = CheckedAdd(_1, const 0_u64);
++         _5 = AddWithOverflow(_1, const 0_u64);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue];
       }
   
@@ -52,7 +52,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = _1;
--         _9 = CheckedSub(_8, const 0_u64);
+-         _9 = SubWithOverflow(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind continue];
 +         _9 = _5;
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue];
@@ -76,7 +76,7 @@
           _12 = _1;
           StorageLive(_13);
           _13 = _1;
--         _14 = CheckedSub(_12, _13);
+-         _14 = SubWithOverflow(_12, _13);
 -         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind continue];
 +         _14 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind continue];
@@ -99,7 +99,7 @@
           StorageLive(_16);
           StorageLive(_17);
           _17 = _1;
--         _18 = CheckedMul(_17, const 0_u64);
+-         _18 = MulWithOverflow(_17, const 0_u64);
 -         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind continue];
 +         _18 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind continue];
@@ -120,7 +120,7 @@
           StorageLive(_20);
           StorageLive(_21);
           _21 = _1;
--         _22 = CheckedMul(_21, const 1_u64);
+-         _22 = MulWithOverflow(_21, const 1_u64);
 -         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind continue];
 +         _22 = _5;
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind continue];
diff --git a/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir b/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
index 7dafeabaacc..7d2e97f8d56 100644
--- a/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
+++ b/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
@@ -5,7 +5,7 @@
     let mut _1: (usize, bool);
 
     bb0: {
-        _1 = CheckedAdd(const 1_usize, const 1_usize);
+        _1 = AddWithOverflow(const 1_usize, const 1_usize);
         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2];
     }
 
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 12e526ab074..180bfd0a924 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -184,9 +184,9 @@ pub fn assume() {
 // EMIT_MIR lower_intrinsics.with_overflow.LowerIntrinsics.diff
 pub fn with_overflow(a: i32, b: i32) {
     // CHECK-LABEL: fn with_overflow(
-    // CHECK: CheckedAdd(
-    // CHECK: CheckedSub(
-    // CHECK: CheckedMul(
+    // CHECK: AddWithOverflow(
+    // CHECK: SubWithOverflow(
+    // CHECK: MulWithOverflow(
 
     let _x = core::intrinsics::add_with_overflow(a, b);
     let _y = core::intrinsics::sub_with_overflow(a, b);
diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff
index da84449aaa5..efbbeeeac73 100644
--- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff
@@ -31,7 +31,7 @@
           StorageLive(_5);
           _5 = _2;
 -         _3 = add_with_overflow::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = CheckedAdd(move _4, move _5);
++         _3 = AddWithOverflow(move _4, move _5);
 +         goto -> bb1;
       }
   
@@ -44,7 +44,7 @@
           StorageLive(_8);
           _8 = _2;
 -         _6 = sub_with_overflow::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = CheckedSub(move _7, move _8);
++         _6 = SubWithOverflow(move _7, move _8);
 +         goto -> bb2;
       }
   
@@ -57,7 +57,7 @@
           StorageLive(_11);
           _11 = _2;
 -         _9 = mul_with_overflow::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = CheckedMul(move _10, move _11);
++         _9 = MulWithOverflow(move _10, move _11);
 +         goto -> bb3;
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff
index da84449aaa5..efbbeeeac73 100644
--- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff
@@ -31,7 +31,7 @@
           StorageLive(_5);
           _5 = _2;
 -         _3 = add_with_overflow::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = CheckedAdd(move _4, move _5);
++         _3 = AddWithOverflow(move _4, move _5);
 +         goto -> bb1;
       }
   
@@ -44,7 +44,7 @@
           StorageLive(_8);
           _8 = _2;
 -         _6 = sub_with_overflow::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = CheckedSub(move _7, move _8);
++         _6 = SubWithOverflow(move _7, move _8);
 +         goto -> bb2;
       }
   
@@ -57,7 +57,7 @@
           StorageLive(_11);
           _11 = _2;
 -         _9 = mul_with_overflow::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = CheckedMul(move _10, move _11);
++         _9 = MulWithOverflow(move _10, move _11);
 +         goto -> bb3;
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
index 0e7e1f971ec..2f34a62b3d1 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
index 9071a3339c0..da7add371a5 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
index 0e7e1f971ec..2f34a62b3d1 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
index 9071a3339c0..da7add371a5 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
index 5f2a096bb1f..802bfbbcdc5 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
index a49546f158c..de94a557403 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
index 5f2a096bb1f..802bfbbcdc5 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
index a49546f158c..de94a557403 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp
index af64260d020..4d43db5716e 100644
--- a/tests/pretty/issue-4264.pp
+++ b/tests/pretty/issue-4264.pp
@@ -11,15 +11,15 @@ extern crate std;
 fn foo(_: [i32; (3 as usize)]) ({ } as ())
 
 fn bar() ({
-        const FOO: usize = ((5 as usize) - (4 as usize) as usize);
-        let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
+    const FOO: usize = ((5 as usize) - (4 as usize) as usize);
+    let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
 
-        let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
+    let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
 
-        let _ =
-            (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as
-                        &[i32; 3]) as *const _ as *const [i32; 3]) as
-                *const [i32; (3 as usize)] as *const [i32; 3]);
+    let _ =
+        (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3])
+                as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)]
+            as *const [i32; 3]);
 
 
 
@@ -29,17 +29,17 @@ fn bar() ({
 
 
 
-        ({
-                let res =
-                    ((::alloc::fmt::format as
-                            for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
-                                as
-                                fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
-                                            as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
-                        as String);
-                (res as String)
-            } as String);
-    } as ())
+    ({
+        let res =
+            ((::alloc::fmt::format as
+                    for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
+                        as
+                        fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
+                                    as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
+                as String);
+        (res as String)
+    } as String);
+} as ())
 type Foo = [i32; (3 as usize)];
 struct Bar {
     x: [i32; (3 as usize)],
@@ -48,9 +48,9 @@ struct TupleBar([i32; (4 as usize)]);
 enum Baz { BazVariant([i32; (5 as usize)]), }
 fn id<T>(x: T) -> T ({ (x as T) } as T)
 fn use_id() ({
-        let _ =
-            ((id::<[i32; (3 as usize)]> as
-                    fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
-                        (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
-    } as ())
+    let _ =
+        ((id::<[i32; (3 as usize)]> as
+                fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
+                    (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
+} as ())
 fn main() ({ } as ())
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
index 5830ef033d3..e518579b906 100644
--- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
+++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
@@ -1,10 +1,7 @@
 #![crate_type = "staticlib"]
 #![feature(c_variadic)]
-#![feature(rustc_private)]
 
-extern crate libc;
-
-use libc::{c_char, c_double, c_int, c_long, c_longlong};
+use std::ffi::{c_char, c_double, c_int, c_long, c_longlong};
 use std::ffi::VaList;
 use std::ffi::{CString, CStr};
 
diff --git a/tests/run-make/const_fn_mir/dump.mir b/tests/run-make/const_fn_mir/dump.mir
index ced170bbeee..b1802c990cf 100644
--- a/tests/run-make/const_fn_mir/dump.mir
+++ b/tests/run-make/const_fn_mir/dump.mir
@@ -5,7 +5,7 @@ fn foo() -> i32 {
     let mut _1: (i32, bool);
 
     bb0: {
-        _1 = CheckedAdd(const 5_i32, const 6_i32);
+        _1 = AddWithOverflow(const 5_i32, const 6_i32);
         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> [success: bb1, unwind continue];
     }
 
@@ -21,7 +21,7 @@ fn foo() -> i32 {
     let mut _1: (i32, bool);
 
     bb0: {
-        _1 = CheckedAdd(const 5_i32, const 6_i32);
+        _1 = AddWithOverflow(const 5_i32, const 6_i32);
         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> [success: bb1, unwind continue];
     }
 
diff --git a/tests/run-make/link-path-order/main.rs b/tests/run-make/link-path-order/main.rs
index 8024e343d19..20a517dcda9 100644
--- a/tests/run-make/link-path-order/main.rs
+++ b/tests/run-make/link-path-order/main.rs
@@ -1,10 +1,8 @@
-#![feature(rustc_private)]
-
-extern crate libc;
+use std::ffi::c_int;
 
 #[link(name = "foo", kind = "static")]
 extern "C" {
-    fn should_return_one() -> libc::c_int;
+    fn should_return_one() -> c_int;
 }
 
 fn main() {
diff --git a/tests/run-make/no-intermediate-extras/Makefile b/tests/run-make/no-intermediate-extras/Makefile
deleted file mode 100644
index 83b5cedcf2a..00000000000
--- a/tests/run-make/no-intermediate-extras/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-# Regression test for issue #10973
-
-include ../tools.mk
-
-all:
-	$(RUSTC) --crate-type=rlib --test foo.rs
-	rm $(TMPDIR)/foo.bc && exit 1 || exit 0
diff --git a/tests/run-make/no-intermediate-extras/rmake.rs b/tests/run-make/no-intermediate-extras/rmake.rs
new file mode 100644
index 00000000000..19479e3bd5b
--- /dev/null
+++ b/tests/run-make/no-intermediate-extras/rmake.rs
@@ -0,0 +1,17 @@
+// When using the --test flag with an rlib, this used to generate
+// an unwanted .bc file, which should not exist. This test checks
+// that the bug causing the generation of this file has not returned.
+// See https://github.com/rust-lang/rust/issues/10973
+
+//@ ignore-cross-compile
+
+use run_make_support::{rustc, tmp_dir};
+use std::fs;
+
+fn main() {
+    rustc().crate_type("rlib").arg("--test").input("foo.rs").run();
+    assert!(
+        fs::remove_file(tmp_dir().join("foo.bc")).is_err(),
+        "An unwanted .bc file was created by run-make/no-intermediate-extras."
+    );
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
index 537d3e2d724..e9c54fa3922 100644
--- a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
@@ -2,5 +2,5 @@
 mod scrape;
 
 fn main() {
-    scrape::scrape();
+    scrape::scrape(&[]);
 }
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/Makefile b/tests/run-make/rustdoc-scrape-examples-multiple/Makefile
deleted file mode 100644
index 453a7d4bc8b..00000000000
--- a/tests/run-make/rustdoc-scrape-examples-multiple/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex ex2
-
-include ./scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
new file mode 100644
index 00000000000..e9c54fa3922
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk
deleted file mode 100644
index 57220bc6635..00000000000
--- a/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-include ../tools.mk
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc"
-
-$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
-	$(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \
-	  --extern foobar=$(TMPDIR)/libfoobar.rmeta \
-		-Z unstable-options \
-		--scrape-examples-output-path $@ \
-		--scrape-examples-target-crate foobar \
-		$(extra_flags)
-
-$(TMPDIR)/lib%.rmeta: src/lib.rs
-	$(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
-
-scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls)
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
-		-Z unstable-options \
-		$(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls)
-
-	$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
index 537d3e2d724..e9c54fa3922 100644
--- a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
@@ -2,5 +2,5 @@
 mod scrape;
 
 fn main() {
-    scrape::scrape();
+    scrape::scrape(&[]);
 }
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
index d9deaf279ce..4e3b895aef0 100644
--- a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
@@ -1,5 +1,5 @@
 mod scrape;
 
 fn main() {
-    scrape::scrape();
+    scrape::scrape(&[]);
 }
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
index 709388b5492..563e3aca9ae 100644
--- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
+++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
@@ -2,7 +2,7 @@ use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir};
 use std::fs::read_dir;
 use std::path::Path;
 
-pub fn scrape() {
+pub fn scrape(extra_args: &[&str]) {
     let lib_dir = tmp_dir();
     let out_dir = tmp_dir().join("rustdoc");
     let crate_name = "foobar";
@@ -29,6 +29,7 @@ pub fn scrape() {
             .arg(&out_example)
             .arg("--scrape-examples-target-crate")
             .arg(crate_name)
+            .args(extra_args)
             .run();
         out_deps.push(out_example);
     }
diff --git a/tests/run-make/rustdoc-scrape-examples-test/Makefile b/tests/run-make/rustdoc-scrape-examples-test/Makefile
deleted file mode 100644
index 1235ead6751..00000000000
--- a/tests/run-make/rustdoc-scrape-examples-test/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-extra_flags := --scrape-tests
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-test/rmake.rs b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
new file mode 100644
index 00000000000..f96ba113ff7
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&["--scrape-tests"]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-whitespace/Makefile b/tests/run-make/rustdoc-scrape-examples-whitespace/Makefile
deleted file mode 100644
index 7786ff762cb..00000000000
--- a/tests/run-make/rustdoc-scrape-examples-whitespace/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
new file mode 100644
index 00000000000..e9c54fa3922
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-with-short-out-dir-option/Makefile b/tests/run-make/rustdoc-with-short-out-dir-option/Makefile
deleted file mode 100644
index 1b9327bce22..00000000000
--- a/tests/run-make/rustdoc-with-short-out-dir-option/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc"
-
-all:
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib -o $(OUTPUT_DIR)
-
-	$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs
new file mode 100644
index 00000000000..6206173ecf1
--- /dev/null
+++ b/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs
@@ -0,0 +1,16 @@
+use run_make_support::{htmldocck, rustdoc, tmp_dir};
+
+fn main() {
+    let out_dir = tmp_dir().join("rustdoc");
+
+    rustdoc()
+        .input("src/lib.rs")
+        .crate_name("foobar")
+        .crate_type("lib")
+        // This is intentionally using `-o` option flag and not the `output()` method.
+        .arg("-o")
+        .arg(&out_dir)
+        .run();
+
+    assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
+}
diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
index f4e020b3b95..d85129a69fc 100644
--- a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
+++ b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
@@ -3,3 +3,8 @@ pub struct InlineOne<A> {
 }
 
 pub type InlineU64 = InlineOne<u64>;
+
+pub enum GenericEnum<T> {
+   Variant(T),
+   Variant2(T, T),
+}
diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs
index d87a1cb6fac..0e65fdaf2af 100644
--- a/tests/rustdoc/typedef-inner-variants.rs
+++ b/tests/rustdoc/typedef-inner-variants.rs
@@ -117,3 +117,10 @@ pub type HighlyGenericAABB<A, B> = HighlyGenericStruct<A, A, B, B>;
 // @count - '//*[@id="variants"]' 0
 // @count - '//*[@id="fields"]' 1
 pub use cross_crate_generic_typedef::InlineU64;
+
+// @has 'inner_variants/type.InlineEnum.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 1
+// @count - '//*[@id="fields"]' 0
+// @count - '//*[@class="variant"]' 2
+pub type InlineEnum = cross_crate_generic_typedef::GenericEnum<i32>;
diff --git a/tests/ui/empty_global_asm.rs b/tests/ui/asm/empty_global_asm.rs
index 2517796ad10..2517796ad10 100644
--- a/tests/ui/empty_global_asm.rs
+++ b/tests/ui/asm/empty_global_asm.rs
diff --git a/tests/ui/simple_global_asm.rs b/tests/ui/asm/simple_global_asm.rs
index 9b193b3e44c..9b193b3e44c 100644
--- a/tests/ui/simple_global_asm.rs
+++ b/tests/ui/asm/simple_global_asm.rs
diff --git a/tests/ui/associated-types/associated-types-eq-2.rs b/tests/ui/associated-types/associated-types-eq-2.rs
index d71697e9a83..43b0208461e 100644
--- a/tests/ui/associated-types/associated-types-eq-2.rs
+++ b/tests/ui/associated-types/associated-types-eq-2.rs
@@ -4,7 +4,7 @@
 struct Bar;
 struct Qux;
 
-// Tests for a a non generic trait
+// Tests for a non generic trait
 pub trait Tr1 {
     type A;
     fn boo(&self) -> <Self as Tr1>::A;
diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
index 70cd9f924ac..649a868faa5 100644
--- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
+++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
@@ -11,6 +11,9 @@ LL | |         }
 error[E0308]: mismatched types
   --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9
    |
+LL |     call(|| -> Option<()> {
+   |                ---------- expected `Option<()>` because of return type
+...
 LL |         true
    |         ^^^^ expected `Option<()>`, found `bool`
    |
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
index 45d571f435c..f4b6947ccd9 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.stderr
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -26,6 +26,14 @@ error[E0599]: no method named `push` found for struct `VecDeque` in the current
 LL |     x.push(1);
    |       ^^^^ method not found in `VecDeque<_>`
    |
+note: there's an earlier shadowed binding `x` of type `Vec<_>` that has method `push` available
+  --> $DIR/rustc_confusables_std_cases.rs:8:9
+   |
+LL |     let mut x = Vec::new();
+   |         ^^^^^ `x` of type `Vec<_>` that has method `push` defined earlier here
+...
+LL |     let mut x = VecDeque::new();
+   |         ----- earlier `x` shadowed here with type `VecDeque`
 help: you might have meant to use `push_back`
    |
 LL |     x.push_back(1);
diff --git a/tests/ui/backtrace-apple-no-dsymutil.rs b/tests/ui/backtrace/apple-no-dsymutil.rs
index 9924cd13b0a..9924cd13b0a 100644
--- a/tests/ui/backtrace-apple-no-dsymutil.rs
+++ b/tests/ui/backtrace/apple-no-dsymutil.rs
diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs b/tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs
index d45e0bcd3b4..d45e0bcd3b4 100644
--- a/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs
+++ b/tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs
diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs b/tests/ui/backtrace/auxiliary/dylib-dep-helper.rs
index 565d8b65de0..565d8b65de0 100644
--- a/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs
+++ b/tests/ui/backtrace/auxiliary/dylib-dep-helper.rs
diff --git a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs b/tests/ui/backtrace/auxiliary/line-tables-only-helper.rs
index 65da2c3f5c7..65da2c3f5c7 100644
--- a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs
+++ b/tests/ui/backtrace/auxiliary/line-tables-only-helper.rs
diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace/backtrace.rs
index 2579ff5203b..2579ff5203b 100644
--- a/tests/ui/backtrace.rs
+++ b/tests/ui/backtrace/backtrace.rs
diff --git a/tests/ui/debuginfo/backtrace-dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs
index fcd1f92e28e..fcd1f92e28e 100644
--- a/tests/ui/debuginfo/backtrace-dylib-dep.rs
+++ b/tests/ui/backtrace/dylib-dep.rs
diff --git a/tests/ui/debuginfo/backtrace-line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs
index 044f59e483a..044f59e483a 100644
--- a/tests/ui/debuginfo/backtrace-line-tables-only.rs
+++ b/tests/ui/backtrace/line-tables-only.rs
diff --git a/tests/ui/std-backtrace.rs b/tests/ui/backtrace/std-backtrace.rs
index b4806457877..b4806457877 100644
--- a/tests/ui/std-backtrace.rs
+++ b/tests/ui/backtrace/std-backtrace.rs
diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
index 75df314e0ba..82b2d7d1b1d 100644
--- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
+++ b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
@@ -1,4 +1,4 @@
-error: `crate_type` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_type` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18
    |
 LL | #![cfg_attr(foo, crate_type="bin")]
@@ -8,7 +8,7 @@ LL | #![cfg_attr(foo, crate_type="bin")]
    = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
    = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` on by default
 
-error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_name` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18
    |
 LL | #![cfg_attr(foo, crate_name="bar")]
@@ -17,7 +17,7 @@ LL | #![cfg_attr(foo, crate_name="bar")]
    = 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 #91632 <https://github.com/rust-lang/rust/issues/91632>
 
-error: `crate_type` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_type` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18
    |
 LL | #![cfg_attr(foo, crate_type="bin")]
@@ -27,7 +27,7 @@ LL | #![cfg_attr(foo, crate_type="bin")]
    = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_name` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18
    |
 LL | #![cfg_attr(foo, crate_name="bar")]
diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr
index ae4c1605f01..b311a80c8fd 100644
--- a/tests/ui/check-cfg/allow-same-level.stderr
+++ b/tests/ui/check-cfg/allow-same-level.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `FALSE`
 LL | #[cfg(FALSE)]
    |       ^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(FALSE)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr
index 627f03ddf55..9d3117ed54d 100644
--- a/tests/ui/check-cfg/cargo-feature.none.stderr
+++ b/tests/ui/check-cfg/cargo-feature.none.stderr
@@ -6,7 +6,7 @@ LL | #[cfg(feature = "serde")]
    |
    = note: no expected values for `feature`
    = help: consider adding `serde` as a feature in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
@@ -17,7 +17,7 @@ LL | #[cfg(feature)]
    |
    = note: no expected values for `feature`
    = help: consider defining some features in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `tokio_unstable`
   --> $DIR/cargo-feature.rs:22:7
@@ -25,9 +25,13 @@ warning: unexpected `cfg` condition name: `tokio_unstable`
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `CONFIG_NVME`
   --> $DIR/cargo-feature.rs:26:7
@@ -35,8 +39,12 @@ warning: unexpected `cfg` condition name: `CONFIG_NVME`
 LL | #[cfg(CONFIG_NVME = "m")]
    |       ^^^^^^^^^^^^^^^^^
    |
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CONFIG_NVME, values("m"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr
index 9cc5fb6aca0..14e24cb1429 100644
--- a/tests/ui/check-cfg/cargo-feature.some.stderr
+++ b/tests/ui/check-cfg/cargo-feature.some.stderr
@@ -6,7 +6,7 @@ LL | #[cfg(feature = "serde")]
    |
    = note: expected values for `feature` are: `bitcode`
    = help: consider adding `serde` as a feature in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
@@ -17,7 +17,7 @@ LL | #[cfg(feature)]
    |
    = note: expected values for `feature` are: `bitcode`
    = help: consider defining some features in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `tokio_unstable`
   --> $DIR/cargo-feature.rs:22:7
@@ -25,9 +25,13 @@ warning: unexpected `cfg` condition name: `tokio_unstable`
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `m`
   --> $DIR/cargo-feature.rs:26:7
@@ -38,8 +42,12 @@ LL | #[cfg(CONFIG_NVME = "m")]
    |                     help: there is a expected value with a similar name: `"y"`
    |
    = note: expected values for `CONFIG_NVME` are: `y`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CONFIG_NVME, values("m"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
index 4975129802b..08bd43832ea 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `value`
 LL | #[cfg(value)]
    |       ^^^^^
    |
-   = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(value)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
index 6404556f46c..6db1144eada 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_value`
 LL | #[cfg(my_value)]
    |       ^^^^^^^^
    |
-   = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(my_value)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
index bda1a601410..a5f8176343a 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `linux`
 LL | #[cfg(linux)]
    |       ^^^^^ help: found config with similar value: `target_os = "linux"`
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(linux)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr
index 079be8d08c2..6fecdb52362 100644
--- a/tests/ui/check-cfg/compact-names.stderr
+++ b/tests/ui/check-cfg/compact-names.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `target_architecture`
 LL | #[cfg(target(os = "linux", architecture = "arm"))]
    |                            ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr
index 4fe921dd24b..c8d14f8c02a 100644
--- a/tests/ui/check-cfg/compact-values.stderr
+++ b/tests/ui/check-cfg/compact-values.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value: `X`
 LL | #[cfg(target(os = "linux", pointer_width = "X"))]
    |                            ^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_pointer_width` are: `16`, `32`, `64`
+   = note: expected values for `target_pointer_width` are: `16`, `32`, and `64`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr
index a508c397661..ec740952f57 100644
--- a/tests/ui/check-cfg/concat-values.stderr
+++ b/tests/ui/check-cfg/concat-values.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value: (none)
 LL | #[cfg(my_cfg)]
    |       ^^^^^^
    |
-   = note: expected values for `my_cfg` are: `bar`, `foo`
+   = note: expected values for `my_cfg` are: `bar` and `foo`
    = help: to expect this configuration use `--check-cfg=cfg(my_cfg)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `unk`
 LL | #[cfg(my_cfg = "unk")]
    |       ^^^^^^^^^^^^^^
    |
-   = note: expected values for `my_cfg` are: `bar`, `foo`
+   = note: expected values for `my_cfg` are: `bar` and `foo`
    = help: to expect this configuration use `--check-cfg=cfg(my_cfg, values("unk"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/diagnotics.cargo.stderr b/tests/ui/check-cfg/diagnotics.cargo.stderr
index 1b7505682da..a440ccaaf58 100644
--- a/tests/ui/check-cfg/diagnotics.cargo.stderr
+++ b/tests/ui/check-cfg/diagnotics.cargo.stderr
@@ -1,62 +1,70 @@
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:8:7
+  --> $DIR/diagnotics.rs:9:7
    |
 LL | #[cfg(featur)]
    |       ^^^^^^ help: there is a config with a similar name: `feature`
    |
    = help: expected values for `feature` are: `foo`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:12:7
+  --> $DIR/diagnotics.rs:13:7
    |
 LL | #[cfg(featur = "foo")]
    |       ^^^^^^^^^^^^^^
    |
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 help: there is a config with a similar name and value
    |
 LL | #[cfg(feature = "foo")]
    |       ~~~~~~~
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:16:7
+  --> $DIR/diagnotics.rs:17:7
    |
 LL | #[cfg(featur = "fo")]
    |       ^^^^^^^^^^^^^
    |
    = help: expected values for `feature` are: `foo`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 help: there is a config with a similar name and different values
    |
 LL | #[cfg(feature = "foo")]
    |       ~~~~~~~~~~~~~~~
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:23:7
+  --> $DIR/diagnotics.rs:24:7
    |
 LL | #[cfg(no_value)]
    |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
    |
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(no_value)");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_value)'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(no_value)");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:27:7
+  --> $DIR/diagnotics.rs:28:7
    |
 LL | #[cfg(no_value = "foo")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(no_value, values(\"foo\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_value, values("foo"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(no_value, values(\"foo\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 help: there is a config with a similar name and no value
    |
 LL | #[cfg(no_values)]
    |       ~~~~~~~~~
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/diagnotics.rs:31:7
+  --> $DIR/diagnotics.rs:32:7
    |
 LL | #[cfg(no_values = "bar")]
    |       ^^^^^^^^^--------
@@ -64,8 +72,28 @@ LL | #[cfg(no_values = "bar")]
    |                help: remove the value
    |
    = note: no expected value for `no_values`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(no_values, values(\"bar\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_values, values("bar"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(no_values, values(\"bar\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
-warning: 6 warnings emitted
+warning: unexpected `cfg` condition value: `quote"`
+  --> $DIR/diagnotics.rs:36:7
+   |
+LL | #[cfg(quote = "quote\"")]
+   |       ^^^^^^^^---------
+   |               |
+   |               help: there is a expected value with a similar name: `"quote"`
+   |
+   = note: expected values for `quote` are: `quote`
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(quote, values("quote\""))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(quote, values(\"quote\\\"\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
+
+warning: 7 warnings emitted
 
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
index b8268ec5606..7155d7c81b9 100644
--- a/tests/ui/check-cfg/diagnotics.rs
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -4,6 +4,7 @@
 //@ [rustc]unset-rustc-env:CARGO_CRATE_NAME
 //@ [cargo]rustc-env:CARGO_CRATE_NAME=foo
 //@ compile-flags: --check-cfg=cfg(feature,values("foo")) --check-cfg=cfg(no_values)
+//@ compile-flags: --check-cfg=cfg(quote,values("quote"))
 
 #[cfg(featur)]
 //~^ WARNING unexpected `cfg` condition name
@@ -32,4 +33,8 @@ fn no_values() {}
 //~^ WARNING unexpected `cfg` condition value
 fn no_values() {}
 
+#[cfg(quote = "quote\"")]
+//~^ WARNING unexpected `cfg` condition value
+fn no_values() {}
+
 fn main() {}
diff --git a/tests/ui/check-cfg/diagnotics.rustc.stderr b/tests/ui/check-cfg/diagnotics.rustc.stderr
index 0bd6ce156bb..6868be482d8 100644
--- a/tests/ui/check-cfg/diagnotics.rustc.stderr
+++ b/tests/ui/check-cfg/diagnotics.rustc.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:8:7
+  --> $DIR/diagnotics.rs:9:7
    |
 LL | #[cfg(featur)]
    |       ^^^^^^ help: there is a config with a similar name: `feature`
@@ -10,7 +10,7 @@ LL | #[cfg(featur)]
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:12:7
+  --> $DIR/diagnotics.rs:13:7
    |
 LL | #[cfg(featur = "foo")]
    |       ^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[cfg(feature = "foo")]
    |       ~~~~~~~
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:16:7
+  --> $DIR/diagnotics.rs:17:7
    |
 LL | #[cfg(featur = "fo")]
    |       ^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL | #[cfg(feature = "foo")]
    |       ~~~~~~~~~~~~~~~
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:23:7
+  --> $DIR/diagnotics.rs:24:7
    |
 LL | #[cfg(no_value)]
    |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
@@ -46,7 +46,7 @@ LL | #[cfg(no_value)]
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:27:7
+  --> $DIR/diagnotics.rs:28:7
    |
 LL | #[cfg(no_value = "foo")]
    |       ^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL | #[cfg(no_values)]
    |       ~~~~~~~~~
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/diagnotics.rs:31:7
+  --> $DIR/diagnotics.rs:32:7
    |
 LL | #[cfg(no_values = "bar")]
    |       ^^^^^^^^^--------
@@ -70,5 +70,17 @@ LL | #[cfg(no_values = "bar")]
    = help: to expect this configuration use `--check-cfg=cfg(no_values, values("bar"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
-warning: 6 warnings emitted
+warning: unexpected `cfg` condition value: `quote"`
+  --> $DIR/diagnotics.rs:36:7
+   |
+LL | #[cfg(quote = "quote\"")]
+   |       ^^^^^^^^---------
+   |               |
+   |               help: there is a expected value with a similar name: `"quote"`
+   |
+   = note: expected values for `quote` are: `quote`
+   = help: to expect this configuration use `--check-cfg=cfg(quote, values("quote\""))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+
+warning: 7 warnings emitted
 
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
index 755373d7b77..2497864e87e 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key`
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
index 6344739ae76..a7d4c6d4df6 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key`
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
index 6344739ae76..a7d4c6d4df6 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key`
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr
index 605825cd4e5..7ac3241db5f 100644
--- a/tests/ui/check-cfg/exhaustive-names.stderr
+++ b/tests/ui/check-cfg/exhaustive-names.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key`
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 54591699145..8c1bf5a1160 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -44,7 +44,7 @@ warning: unexpected `cfg` condition name: `uu`
 LL | #[cfg_attr(uu, test)]
    |            ^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(uu)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2` and 188 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, and `bmi2` and 188 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr
index ab0deae428d..e8b61d808fe 100644
--- a/tests/ui/check-cfg/stmt-no-ice.stderr
+++ b/tests/ui/check-cfg/stmt-no-ice.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `crossbeam_loom`
 LL |     #[cfg(crossbeam_loom)]
    |           ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(crossbeam_loom)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.stderr b/tests/ui/check-cfg/unexpected-cfg-value.stderr
index efcf65bb707..0fa0dde41b6 100644
--- a/tests/ui/check-cfg/unexpected-cfg-value.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-value.stderr
@@ -6,7 +6,7 @@ LL | #[cfg(feature = "sedre")]
    |                 |
    |                 help: there is a expected value with a similar name: `"serde"`
    |
-   = note: expected values for `feature` are: `full`, `serde`
+   = note: expected values for `feature` are: `full` and `serde`
    = help: to expect this configuration use `--check-cfg=cfg(feature, values("sedre"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
@@ -17,7 +17,7 @@ warning: unexpected `cfg` condition value: `rand`
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: `full`, `serde`
+   = note: expected values for `feature` are: `full` and `serde`
    = help: to expect this configuration use `--check-cfg=cfg(feature, values("rand"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index 2ce6fe80ef2..41130210df1 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -18,7 +18,7 @@ warning: unexpected `cfg` condition name: `features`
 LL | #[cfg(features = "foo")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(features, values("foo"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index db4a5fd49e6..c13446bb9f8 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -71,7 +71,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     panic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `panic` are: `abort`, `unwind`
+   = note: expected values for `panic` are: `abort` and `unwind`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -91,7 +91,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     relocation_model = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, `static`
+   = note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, and `static`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -111,7 +111,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     sanitize = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
+   = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, and `thread`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -120,7 +120,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, `x32`
+   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_arch = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
+   = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, and `x86_64`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -138,7 +138,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_endian = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_endian` are: `big`, `little`
+   = note: expected values for `target_endian` are: `big` and `little`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -147,7 +147,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_env = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p2`, `psx`, `relibc`, `sgx`, `uclibc`
+   = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p2`, `psx`, `relibc`, `sgx`, and `uclibc`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_family = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_family` are: `unix`, `wasm`, `windows`
+   = note: expected values for `target_family` are: `unix`, `wasm`, and `windows`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
+   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -183,7 +183,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
+   = note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -192,7 +192,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
+   = note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -210,7 +210,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_pointer_width` are: `16`, `32`, `64`
+   = note: expected values for `target_pointer_width` are: `16`, `32`, and `64`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -230,7 +230,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_vendor = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, `wrs`
+   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -285,7 +285,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    |                   |
    |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 29 warnings emitted
diff --git a/tests/ui/closures/closure-return-type-mismatch.stderr b/tests/ui/closures/closure-return-type-mismatch.stderr
index 3a89d30a05d..3a2f098d1ef 100644
--- a/tests/ui/closures/closure-return-type-mismatch.stderr
+++ b/tests/ui/closures/closure-return-type-mismatch.stderr
@@ -13,6 +13,9 @@ LL |             return "test";
 error[E0308]: mismatched types
   --> $DIR/closure-return-type-mismatch.rs:12:20
    |
+LL |     || -> bool {
+   |           ---- expected `bool` because of return type
+LL |         if false {
 LL |             return "hello"
    |                    ^^^^^^^ expected `bool`, found `&str`
 
diff --git a/tests/ui/coherence/associated-type2.rs b/tests/ui/coherence/associated-type2.rs
index 2aadfb04af0..68e98b62953 100644
--- a/tests/ui/coherence/associated-type2.rs
+++ b/tests/ui/coherence/associated-type2.rs
@@ -1,6 +1,6 @@
 //! A regression test for #120343. The overlap error was previously
 //! silenced in coherence because projecting `<() as ToUnit>::Unit`
-//! failed. Then then silenced the missing items error in the `ToUnit`
+//! failed. Then silenced the missing items error in the `ToUnit`
 //! impl, causing us to not emit any errors and ICEing due to a
 //! `span_delay_bug`.
 
diff --git a/tests/ui/auxiliary/orphan-check-diagnostics.rs b/tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs
index 6b2c42b69b9..6b2c42b69b9 100644
--- a/tests/ui/auxiliary/orphan-check-diagnostics.rs
+++ b/tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs
diff --git a/tests/ui/orphan-check-diagnostics.rs b/tests/ui/coherence/orphan-check-diagnostics.rs
index 4b6557fc9c8..4b6557fc9c8 100644
--- a/tests/ui/orphan-check-diagnostics.rs
+++ b/tests/ui/coherence/orphan-check-diagnostics.rs
diff --git a/tests/ui/orphan-check-diagnostics.stderr b/tests/ui/coherence/orphan-check-diagnostics.stderr
index b9fa7baf4c2..b9fa7baf4c2 100644
--- a/tests/ui/orphan-check-diagnostics.stderr
+++ b/tests/ui/coherence/orphan-check-diagnostics.stderr
diff --git a/tests/ui/coroutine/static-move-suggestion.fixed b/tests/ui/coroutine/static-move-suggestion.fixed
new file mode 100644
index 00000000000..56445be4715
--- /dev/null
+++ b/tests/ui/coroutine/static-move-suggestion.fixed
@@ -0,0 +1,19 @@
+//@ run-rustfix
+
+// check to make sure that we suggest adding `move` after `static`
+
+#![feature(coroutines)]
+
+fn check() -> impl Sized {
+    let x = 0;
+    #[coroutine]
+    static move || {
+        //~^ ERROR E0373
+        yield;
+        x
+    }
+}
+
+fn main() {
+    check();
+}
diff --git a/tests/ui/coroutine/static-move-suggestion.rs b/tests/ui/coroutine/static-move-suggestion.rs
new file mode 100644
index 00000000000..1d6e4a62883
--- /dev/null
+++ b/tests/ui/coroutine/static-move-suggestion.rs
@@ -0,0 +1,19 @@
+//@ run-rustfix
+
+// check to make sure that we suggest adding `move` after `static`
+
+#![feature(coroutines)]
+
+fn check() -> impl Sized {
+    let x = 0;
+    #[coroutine]
+    static || {
+        //~^ ERROR E0373
+        yield;
+        x
+    }
+}
+
+fn main() {
+    check();
+}
diff --git a/tests/ui/coroutine/static-move-suggestion.stderr b/tests/ui/coroutine/static-move-suggestion.stderr
new file mode 100644
index 00000000000..6d890468b32
--- /dev/null
+++ b/tests/ui/coroutine/static-move-suggestion.stderr
@@ -0,0 +1,26 @@
+error[E0373]: coroutine may outlive the current function, but it borrows `x`, which is owned by the current function
+  --> $DIR/static-move-suggestion.rs:10:5
+   |
+LL |     static || {
+   |     ^^^^^^^^^ may outlive borrowed value `x`
+...
+LL |         x
+   |         - `x` is borrowed here
+   |
+note: coroutine is returned here
+  --> $DIR/static-move-suggestion.rs:10:5
+   |
+LL | /     static || {
+LL | |
+LL | |         yield;
+LL | |         x
+LL | |     }
+   | |_____^
+help: to force the coroutine to take ownership of `x` (and any other referenced variables), use the `move` keyword
+   |
+LL |     static move || {
+   |            ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/tests/ui/cross-crate/xcrate-address-insignificant.rs b/tests/ui/cross-crate/address-insignificant.rs
index 891fe14d9a0..891fe14d9a0 100644
--- a/tests/ui/cross-crate/xcrate-address-insignificant.rs
+++ b/tests/ui/cross-crate/address-insignificant.rs
diff --git a/tests/ui/cross-crate/xcrate-associated-type-defaults.rs b/tests/ui/cross-crate/associated-type-defaults.rs
index 04eb90afae9..04eb90afae9 100644
--- a/tests/ui/cross-crate/xcrate-associated-type-defaults.rs
+++ b/tests/ui/cross-crate/associated-type-defaults.rs
diff --git a/tests/ui/xcrate/auxiliary/static_priv_by_default.rs b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs
index 39f912066ec..39f912066ec 100644
--- a/tests/ui/xcrate/auxiliary/static_priv_by_default.rs
+++ b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs
diff --git a/tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs b/tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs
index 4f8b3508398..4f8b3508398 100644
--- a/tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs
+++ b/tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs
diff --git a/tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs b/tests/ui/cross-crate/generic_fn_nested_return.rs
index dbfcdf8197a..dbfcdf8197a 100644
--- a/tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs
+++ b/tests/ui/cross-crate/generic_fn_nested_return.rs
diff --git a/tests/ui/xcrate/xcrate-private-by-default.rs b/tests/ui/cross-crate/private-by-default.rs
index 3a5d8131344..3a5d8131344 100644
--- a/tests/ui/xcrate/xcrate-private-by-default.rs
+++ b/tests/ui/cross-crate/private-by-default.rs
diff --git a/tests/ui/xcrate/xcrate-private-by-default.stderr b/tests/ui/cross-crate/private-by-default.stderr
index 25bbbf5f62a..398c9088aae 100644
--- a/tests/ui/xcrate/xcrate-private-by-default.stderr
+++ b/tests/ui/cross-crate/private-by-default.stderr
@@ -1,5 +1,5 @@
 error[E0603]: static `j` is private
-  --> $DIR/xcrate-private-by-default.rs:23:29
+  --> $DIR/private-by-default.rs:23:29
    |
 LL |     static_priv_by_default::j;
    |                             ^ private static
@@ -11,7 +11,7 @@ LL | static j: isize = 0;
    | ^^^^^^^^^^^^^^^
 
 error[E0603]: function `k` is private
-  --> $DIR/xcrate-private-by-default.rs:25:29
+  --> $DIR/private-by-default.rs:25:29
    |
 LL |     static_priv_by_default::k;
    |                             ^ private function
@@ -23,7 +23,7 @@ LL | fn k() {}
    | ^^^^^^
 
 error[E0603]: unit struct `l` is private
-  --> $DIR/xcrate-private-by-default.rs:27:29
+  --> $DIR/private-by-default.rs:27:29
    |
 LL |     static_priv_by_default::l;
    |                             ^ private unit struct
@@ -35,7 +35,7 @@ LL | struct l;
    | ^^^^^^^^
 
 error[E0603]: enum `m` is private
-  --> $DIR/xcrate-private-by-default.rs:29:35
+  --> $DIR/private-by-default.rs:29:35
    |
 LL |     foo::<static_priv_by_default::m>();
    |                                   ^ private enum
@@ -47,7 +47,7 @@ LL | enum m {}
    | ^^^^^^
 
 error[E0603]: type alias `n` is private
-  --> $DIR/xcrate-private-by-default.rs:31:35
+  --> $DIR/private-by-default.rs:31:35
    |
 LL |     foo::<static_priv_by_default::n>();
    |                                   ^ private type alias
@@ -59,7 +59,7 @@ LL | type n = isize;
    | ^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:35:29
+  --> $DIR/private-by-default.rs:35:29
    |
 LL |     static_priv_by_default::foo::a;
    |                             ^^^  - static `a` is not publicly re-exported
@@ -73,7 +73,7 @@ LL | mod foo {
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:37:29
+  --> $DIR/private-by-default.rs:37:29
    |
 LL |     static_priv_by_default::foo::b;
    |                             ^^^  - function `b` is not publicly re-exported
@@ -87,7 +87,7 @@ LL | mod foo {
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:39:29
+  --> $DIR/private-by-default.rs:39:29
    |
 LL |     static_priv_by_default::foo::c;
    |                             ^^^  - unit struct `c` is not publicly re-exported
@@ -101,7 +101,7 @@ LL | mod foo {
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:41:35
+  --> $DIR/private-by-default.rs:41:35
    |
 LL |     foo::<static_priv_by_default::foo::d>();
    |                                   ^^^  - enum `d` is not publicly re-exported
@@ -115,7 +115,7 @@ LL | mod foo {
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:43:35
+  --> $DIR/private-by-default.rs:43:35
    |
 LL |     foo::<static_priv_by_default::foo::e>();
    |                                   ^^^  - type alias `e` is not publicly re-exported
diff --git a/tests/ui/cross-crate/xcrate-static-addresses.rs b/tests/ui/cross-crate/static-addresses.rs
index 66ac467e9ac..66ac467e9ac 100644
--- a/tests/ui/cross-crate/xcrate-static-addresses.rs
+++ b/tests/ui/cross-crate/static-addresses.rs
diff --git a/tests/ui/cross-crate/xcrate-trait-lifetime-param.rs b/tests/ui/cross-crate/trait-lifetime-param.rs
index 28955e62d95..28955e62d95 100644
--- a/tests/ui/cross-crate/xcrate-trait-lifetime-param.rs
+++ b/tests/ui/cross-crate/trait-lifetime-param.rs
diff --git a/tests/ui/xcrate/xcrate-unit-struct-2.rs b/tests/ui/cross-crate/unit-struct-2.rs
index c2e3a761129..c2e3a761129 100644
--- a/tests/ui/xcrate/xcrate-unit-struct-2.rs
+++ b/tests/ui/cross-crate/unit-struct-2.rs
diff --git a/tests/ui/xcrate/xcrate-unit-struct.rs b/tests/ui/cross-crate/unit-struct.rs
index 1517f843eff..1517f843eff 100644
--- a/tests/ui/xcrate/xcrate-unit-struct.rs
+++ b/tests/ui/cross-crate/unit-struct.rs
diff --git a/tests/ui/xcrate/xcrate-unit-struct.stderr b/tests/ui/cross-crate/unit-struct.stderr
index 7365170b69e..a7e3e4685a9 100644
--- a/tests/ui/xcrate/xcrate-unit-struct.stderr
+++ b/tests/ui/cross-crate/unit-struct.stderr
@@ -1,5 +1,5 @@
 error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields`
-  --> $DIR/xcrate-unit-struct.rs:9:13
+  --> $DIR/unit-struct.rs:9:13
    |
 LL |     let _ = xcrate_unit_struct::StructWithFields;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }`
@@ -10,7 +10,7 @@ LL | pub struct StructWithFields {
    | --------------------------- `xcrate_unit_struct::StructWithFields` defined here
 
 error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithPrivFields`
-  --> $DIR/xcrate-unit-struct.rs:11:13
+  --> $DIR/unit-struct.rs:11:13
    |
 LL |     let _ = xcrate_unit_struct::StructWithPrivFields;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr
index 96f51a4e7a2..b62c67d9a9d 100644
--- a/tests/ui/derives/deriving-with-repr-packed-2.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr
@@ -10,6 +10,14 @@ LL | struct NonCopy;
 LL |     _ = x.clone();
    |           ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds
    |
+note: there's an earlier shadowed binding `x` of type `Foo<u32>` that has method `clone` available
+  --> $DIR/deriving-with-repr-packed-2.rs:13:9
+   |
+LL |     let x: Foo<u32> = Foo(1, 2, 3);
+   |         ^ `x` of type `Foo<u32>` that has method `clone` defined earlier here
+...
+LL |     let x: Foo<NonCopy> = Foo(NonCopy, NonCopy, NonCopy);
+   |         - earlier `x` shadowed here with type `Foo<NonCopy>`
 note: the following trait bounds were not satisfied:
       `NonCopy: Clone`
       `NonCopy: Copy`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
new file mode 100644
index 00000000000..41f222e46a7
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
+  --> $DIR/as_expression.rs:57:15
+   |
+LL |     SelectInt.check("bar");
+   |               ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
+   |
+   = help: the trait `AsExpression<Text>` is implemented for `&str`
+   = help: for that trait implementation, expected `Text`, found `Integer`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
new file mode 100644
index 00000000000..47acf5b968b
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+  --> $DIR/as_expression.rs:57:21
+   |
+LL |     SelectInt.check("bar");
+   |               ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
+   |               |
+   |               required by a bound introduced by this call
+   |
+   = help: the trait `AsExpression<Text>` is implemented for `&str`
+note: required by a bound in `Foo::check`
+  --> $DIR/as_expression.rs:48:12
+   |
+LL |     fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
+   |        ----- required by a bound in this associated function
+LL |     where
+LL |         T: AsExpression<Self::SqlType>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
new file mode 100644
index 00000000000..5fd5cc54400
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -0,0 +1,60 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(do_not_recommend)]
+
+pub trait Expression {
+    type SqlType;
+}
+
+pub trait AsExpression<ST> {
+    type Expression: Expression<SqlType = ST>;
+}
+
+pub struct Text;
+pub struct Integer;
+
+pub struct Bound<T>(T);
+pub struct SelectInt;
+
+impl Expression for SelectInt {
+    type SqlType = Integer;
+}
+
+impl<T> Expression for Bound<T> {
+    type SqlType = T;
+}
+
+#[diagnostic::do_not_recommend]
+impl<T, ST> AsExpression<ST> for T
+where
+    T: Expression<SqlType = ST>,
+{
+    type Expression = T;
+}
+
+impl AsExpression<Integer> for i32 {
+    type Expression = Bound<Integer>;
+}
+
+impl AsExpression<Text> for &'_ str {
+    type Expression = Bound<Text>;
+}
+
+trait Foo: Expression + Sized {
+    fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
+    where
+        T: AsExpression<Self::SqlType>,
+    {
+        todo!()
+    }
+}
+
+impl<T> Foo for T where T: Expression {}
+
+fn main() {
+    SelectInt.check("bar");
+    //[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+    //[current]~^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
+}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs
index c9dc1c6e649..5a26d28188c 100644
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs
@@ -1,17 +1,13 @@
 #![feature(do_not_recommend)]
 
-pub trait Foo {
-}
+pub trait Foo {}
 
-impl Foo for i32 {
-}
+impl Foo for i32 {}
 
-pub trait Bar {
-}
+pub trait Bar {}
 
-#[do_not_recommend]
-impl<T: Foo> Bar for T {
-}
+#[diagnostic::do_not_recommend]
+impl<T: Foo> Bar for T {}
 
 fn stuff<T: Bar>(_: T) {}
 
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr
new file mode 100644
index 00000000000..3951231fa2e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `u8: Bar` is not satisfied
+  --> $DIR/feature-gate-do_not_recommend.rs:15:11
+   |
+LL |     stuff(1u8);
+   |           ^^^ the trait `Bar` is not implemented for `u8`
+   |
+note: required by a bound in `stuff`
+  --> $DIR/feature-gate-do_not_recommend.rs:12:13
+   |
+LL | fn stuff<T: Bar>(_: T) {}
+   |             ^^^ required by this bound in `stuff`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
new file mode 100644
index 00000000000..400ef83873e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
@@ -0,0 +1,39 @@
+//@ check-pass
+#![feature(do_not_recommend)]
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+const CONST: () = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+static STATIC: () = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+type Type = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+enum Enum {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+extern "C" {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+fn fun() {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+struct Struct {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+trait Trait {}
+
+#[diagnostic::do_not_recommend]
+impl Trait for i32 {}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr
new file mode 100644
index 00000000000..c83fd46db58
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr
@@ -0,0 +1,52 @@
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:4:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:8:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:12:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:16:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:20:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:24:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:28:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:32:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 8 warnings emitted
+
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
index a4d4b7b359e..729cb5694e2 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
@@ -1,16 +1,11 @@
 error[E0277]: the trait bound `*mut (): Foo` is not satisfied
-  --> $DIR/simple.rs:19:17
+  --> $DIR/simple.rs:17:17
    |
 LL |     needs_foo::<*mut ()>();
-   |                 ^^^^^^^ the trait `Send` is not implemented for `*mut ()`, which is required by `*mut (): Foo`
+   |                 ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
    |
-note: required for `*mut ()` to implement `Foo`
-  --> $DIR/simple.rs:10:9
-   |
-LL | impl<T> Foo for T where T: Send {}
-   |         ^^^     ^          ---- unsatisfied trait bound introduced here
 note: required by a bound in `needs_foo`
-  --> $DIR/simple.rs:14:17
+  --> $DIR/simple.rs:12:17
    |
 LL | fn needs_foo<T: Foo>() {}
    |                 ^^^ required by this bound in `needs_foo`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
index 1341ca8175a..729cb5694e2 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `*mut (): Foo` is not satisfied
-  --> $DIR/simple.rs:19:17
+  --> $DIR/simple.rs:17:17
    |
 LL |     needs_foo::<*mut ()>();
    |                 ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
    |
 note: required by a bound in `needs_foo`
-  --> $DIR/simple.rs:14:17
+  --> $DIR/simple.rs:12:17
    |
 LL | fn needs_foo<T: Foo>() {}
    |                 ^^^ required by this bound in `needs_foo`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
index 15ff80ae4d9..780649b009c 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
@@ -6,10 +6,8 @@
 
 trait Foo {}
 
-#[do_not_recommend]
+#[diagnostic::do_not_recommend]
 impl<T> Foo for T where T: Send {}
-//[current]~^ NOTE required for `*mut ()` to implement `Foo`
-//[current]~| NOTE unsatisfied trait bound introduced here
 
 fn needs_foo<T: Foo>() {}
 //~^ NOTE required by a bound in `needs_foo`
@@ -18,6 +16,5 @@ fn needs_foo<T: Foo>() {}
 fn main() {
     needs_foo::<*mut ()>();
     //~^ ERROR the trait bound `*mut (): Foo` is not satisfied
-    //[current]~| NOTE the trait `Send` is not implemented for `*mut ()`
-    //[next]~| NOTE the trait `Foo` is not implemented for `*mut ()`
+    //~| NOTE the trait `Foo` is not implemented for `*mut ()`
 }
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
new file mode 100644
index 00000000000..41a10a61e1d
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): Root` is not satisfied
+  --> $DIR/stacked.rs:19:18
+   |
+LL |     needs_root::<()>();
+   |                  ^^ the trait `Root` is not implemented for `()`
+   |
+note: required by a bound in `needs_root`
+  --> $DIR/stacked.rs:16:18
+   |
+LL | fn needs_root<T: Root>() {}
+   |                  ^^^^ required by this bound in `needs_root`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
new file mode 100644
index 00000000000..41a10a61e1d
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): Root` is not satisfied
+  --> $DIR/stacked.rs:19:18
+   |
+LL |     needs_root::<()>();
+   |                  ^^ the trait `Root` is not implemented for `()`
+   |
+note: required by a bound in `needs_root`
+  --> $DIR/stacked.rs:16:18
+   |
+LL | fn needs_root<T: Root>() {}
+   |                  ^^^^ required by this bound in `needs_root`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
new file mode 100644
index 00000000000..fc355bdc4e2
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
@@ -0,0 +1,21 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(do_not_recommend)]
+
+trait Root {}
+trait DontRecommend {}
+trait Other {}
+
+#[diagnostic::do_not_recommend]
+impl<T> Root for T where T: DontRecommend {}
+
+impl<T> DontRecommend for T where T: Other {}
+
+fn needs_root<T: Root>() {}
+
+fn main() {
+    needs_root::<()>();
+    //~^ ERROR the trait bound `(): Root` is not satisfied
+}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs
new file mode 100644
index 00000000000..ccc687aa5b3
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs
@@ -0,0 +1,8 @@
+#![deny(unknown_or_malformed_diagnostic_attributes)]
+trait Foo {}
+
+#[diagnostic::do_not_recommend]
+//~^ ERROR unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes]
+impl Foo for i32 {}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr
new file mode 100644
index 00000000000..d8332229d4f
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr
@@ -0,0 +1,14 @@
+error: unknown diagnostic attribute
+  --> $DIR/unstable-feature.rs:4:15
+   |
+LL | #[diagnostic::do_not_recommend]
+   |               ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unstable-feature.rs:1:9
+   |
+LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/error-codes/E0259.rs b/tests/ui/error-codes/E0259.rs
index e7e94d58635..78e56deccb4 100644
--- a/tests/ui/error-codes/E0259.rs
+++ b/tests/ui/error-codes/E0259.rs
@@ -1,8 +1,8 @@
-#![feature(rustc_private)]
+#![feature(test)]
 
 extern crate alloc;
 
-extern crate libc as alloc;
+extern crate test as alloc;
 //~^ ERROR E0259
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0259.stderr b/tests/ui/error-codes/E0259.stderr
index 6e086268fc6..975d1a161a0 100644
--- a/tests/ui/error-codes/E0259.stderr
+++ b/tests/ui/error-codes/E0259.stderr
@@ -4,13 +4,13 @@ error[E0259]: the name `alloc` is defined multiple times
 LL | extern crate alloc;
    | ------------------- previous import of the extern crate `alloc` here
 LL |
-LL | extern crate libc as alloc;
+LL | extern crate test as alloc;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `alloc` reimported here
    |
    = note: `alloc` must be defined only once in the type namespace of this module
 help: you can use `as` to change the binding name of the import
    |
-LL | extern crate libc as other_alloc;
+LL | extern crate test as other_alloc;
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/expr-block-fn.rs b/tests/ui/expr/block-fn.rs
index 1d3689eb4f3..1d3689eb4f3 100644
--- a/tests/ui/expr-block-fn.rs
+++ b/tests/ui/expr/block-fn.rs
diff --git a/tests/ui/expr-block-generic.rs b/tests/ui/expr/block-generic.rs
index b36bda917d6..b36bda917d6 100644
--- a/tests/ui/expr-block-generic.rs
+++ b/tests/ui/expr/block-generic.rs
diff --git a/tests/ui/expr-block.rs b/tests/ui/expr/block.rs
index bf626c9ead3..bf626c9ead3 100644
--- a/tests/ui/expr-block.rs
+++ b/tests/ui/expr/block.rs
diff --git a/tests/ui/expr-copy.rs b/tests/ui/expr/copy.rs
index cfe47ff6d93..cfe47ff6d93 100644
--- a/tests/ui/expr-copy.rs
+++ b/tests/ui/expr/copy.rs
diff --git a/tests/ui/expr-if-generic.rs b/tests/ui/expr/if-generic.rs
index ed99ee63a51..ed99ee63a51 100644
--- a/tests/ui/expr-if-generic.rs
+++ b/tests/ui/expr/if-generic.rs
diff --git a/tests/ui/expr-if-panic-all.rs b/tests/ui/expr/if-panic-all.rs
index 2ba2a36d165..2ba2a36d165 100644
--- a/tests/ui/expr-if-panic-all.rs
+++ b/tests/ui/expr/if-panic-all.rs
diff --git a/tests/ui/expr-scope.rs b/tests/ui/expr/scope.rs
index 57321ce2aa0..57321ce2aa0 100644
--- a/tests/ui/expr-scope.rs
+++ b/tests/ui/expr/scope.rs
diff --git a/tests/ui/feature-gates/feature-gate-global-registration.rs b/tests/ui/feature-gates/feature-gate-global-registration.rs
new file mode 100644
index 00000000000..6ac36712090
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-global-registration.rs
@@ -0,0 +1,3 @@
+todo!(); //~ ERROR
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-global-registration.stderr b/tests/ui/feature-gates/feature-gate-global-registration.stderr
new file mode 100644
index 00000000000..70538ae6f31
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-global-registration.stderr
@@ -0,0 +1,13 @@
+error: expected one of `!` or `::`, found `(`
+  --> $DIR/feature-gate-global-registration.rs:1:1
+   |
+LL | todo!();
+   | ^^^^^^^
+   | |
+   | expected one of `!` or `::`
+   | in this macro invocation
+   |
+   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index bd3b69c2b4a..ca60bc62b51 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -45,7 +45,7 @@ mod inline {
     //~| NOTE not a function or closure
 
     #[inline = "2100"] fn f() { }
-    //~^ ERROR attribute must be of the form
+    //~^ ERROR valid forms for the attribute are
     //~| WARN this was previously accepted
     //~| NOTE #[deny(ill_formed_attribute_input)]` on by default
     //~| NOTE for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 89fa2abffc2..ac2bf78157d 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -7,7 +7,7 @@ LL | #![rustc_main]
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
+error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5
    |
 LL |     #[inline = "2100"] fn f() { }
diff --git a/tests/ui/feature-gates/rustc-private.rs b/tests/ui/feature-gates/rustc-private.rs
index 7b8944bb0a0..aa44f790c8a 100644
--- a/tests/ui/feature-gates/rustc-private.rs
+++ b/tests/ui/feature-gates/rustc-private.rs
@@ -1,5 +1,5 @@
 // gate-test-rustc_private
 
-extern crate libc; //~ ERROR  use of unstable library feature 'rustc_private'
+extern crate cfg_if; //~ ERROR  use of unstable library feature 'rustc_private'
 
 fn main() {}
diff --git a/tests/ui/feature-gates/rustc-private.stderr b/tests/ui/feature-gates/rustc-private.stderr
index 03397cba763..96cc98619fd 100644
--- a/tests/ui/feature-gates/rustc-private.stderr
+++ b/tests/ui/feature-gates/rustc-private.stderr
@@ -1,8 +1,8 @@
 error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
   --> $DIR/rustc-private.rs:3:1
    |
-LL | extern crate libc;
-   | ^^^^^^^^^^^^^^^^^^
+LL | extern crate cfg_if;
+   | ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
    = help: add `#![feature(rustc_private)]` to the crate attributes to enable
diff --git a/tests/ui/stmt_expr_attrs_no_feature.rs b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
index a160a9bb082..a160a9bb082 100644
--- a/tests/ui/stmt_expr_attrs_no_feature.rs
+++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
diff --git a/tests/ui/stmt_expr_attrs_no_feature.stderr b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr
index c801268c652..c801268c652 100644
--- a/tests/ui/stmt_expr_attrs_no_feature.stderr
+++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr
diff --git a/tests/ui/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs
index aa20a4d4c65..aa20a4d4c65 100644
--- a/tests/ui/ffi_const.rs
+++ b/tests/ui/ffi-attrs/ffi_const.rs
diff --git a/tests/ui/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr
index 394b98f8971..394b98f8971 100644
--- a/tests/ui/ffi_const.stderr
+++ b/tests/ui/ffi-attrs/ffi_const.stderr
diff --git a/tests/ui/ffi_const2.rs b/tests/ui/ffi-attrs/ffi_const2.rs
index 82fe8a9c91d..82fe8a9c91d 100644
--- a/tests/ui/ffi_const2.rs
+++ b/tests/ui/ffi-attrs/ffi_const2.rs
diff --git a/tests/ui/ffi_const2.stderr b/tests/ui/ffi-attrs/ffi_const2.stderr
index b8cbc296370..b8cbc296370 100644
--- a/tests/ui/ffi_const2.stderr
+++ b/tests/ui/ffi-attrs/ffi_const2.stderr
diff --git a/tests/ui/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs
index 6d2f3a614ec..6d2f3a614ec 100644
--- a/tests/ui/ffi_pure.rs
+++ b/tests/ui/ffi-attrs/ffi_pure.rs
diff --git a/tests/ui/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr
index 8b61a4b609f..8b61a4b609f 100644
--- a/tests/ui/ffi_pure.stderr
+++ b/tests/ui/ffi-attrs/ffi_pure.stderr
diff --git a/tests/ui/main-wrong-location.rs b/tests/ui/fn-main/wrong-location.rs
index d7deeaed99d..d7deeaed99d 100644
--- a/tests/ui/main-wrong-location.rs
+++ b/tests/ui/fn-main/wrong-location.rs
diff --git a/tests/ui/main-wrong-location.stderr b/tests/ui/fn-main/wrong-location.stderr
index 9486a940562..c47092bc47e 100644
--- a/tests/ui/main-wrong-location.stderr
+++ b/tests/ui/fn-main/wrong-location.stderr
@@ -1,11 +1,11 @@
-error[E0601]: `main` function not found in crate `main_wrong_location`
-  --> $DIR/main-wrong-location.rs:5:2
+error[E0601]: `main` function not found in crate `wrong_location`
+  --> $DIR/wrong-location.rs:5:2
    |
 LL | }
-   |  ^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
+   |  ^ the main function must be defined at the crate level (in `$DIR/wrong-location.rs`)
    |
 note: here is a function named `main`
-  --> $DIR/main-wrong-location.rs:4:5
+  --> $DIR/wrong-location.rs:4:5
    |
 LL |     fn main() { }
    |     ^^^^^^^^^
diff --git a/tests/ui/main-wrong-type.rs b/tests/ui/fn-main/wrong-type.rs
index 31deba72af4..31deba72af4 100644
--- a/tests/ui/main-wrong-type.rs
+++ b/tests/ui/fn-main/wrong-type.rs
diff --git a/tests/ui/main-wrong-type.stderr b/tests/ui/fn-main/wrong-type.stderr
index d07fc09064f..2b0096431db 100644
--- a/tests/ui/main-wrong-type.stderr
+++ b/tests/ui/fn-main/wrong-type.stderr
@@ -1,5 +1,5 @@
 error[E0580]: `main` function has wrong type
-  --> $DIR/main-wrong-type.rs:6:1
+  --> $DIR/wrong-type.rs:6:1
    |
 LL | fn main(foo: S) {
    | ^^^^^^^^^^^^^^^ incorrect number of function parameters
diff --git a/tests/ui/foreign/foreign-fn-linkname.rs b/tests/ui/foreign/foreign-fn-linkname.rs
index 47edf6fc7bb..7ced34e73fa 100644
--- a/tests/ui/foreign/foreign-fn-linkname.rs
+++ b/tests/ui/foreign/foreign-fn-linkname.rs
@@ -1,20 +1,14 @@
 //@ run-pass
 //@ ignore-sgx no libc
 
-// Ensure no false positive on "unused extern crate" lint
-#![deny(unused_extern_crates)]
-
-#![feature(rustc_private)]
-
-extern crate libc;
 use std::ffi::CString;
 
 mod mlibc {
-    use libc::{c_char, size_t};
+    use std::ffi::c_char;
 
     extern "C" {
         #[link_name = "strlen"]
-        pub fn my_strlen(str: *const c_char) -> size_t;
+        pub fn my_strlen(str: *const c_char) -> usize;
     }
 }
 
diff --git a/tests/ui/foreign-fn-return-lifetime.rs b/tests/ui/foreign/foreign-fn-return-lifetime.rs
index 35595bab36d..35595bab36d 100644
--- a/tests/ui/foreign-fn-return-lifetime.rs
+++ b/tests/ui/foreign/foreign-fn-return-lifetime.rs
diff --git a/tests/ui/foreign-fn-return-lifetime.stderr b/tests/ui/foreign/foreign-fn-return-lifetime.stderr
index e24c0f23c35..e24c0f23c35 100644
--- a/tests/ui/foreign-fn-return-lifetime.stderr
+++ b/tests/ui/foreign/foreign-fn-return-lifetime.stderr
diff --git a/tests/ui/foreign/foreign2.rs b/tests/ui/foreign/foreign2.rs
index eb24df35033..178a04255cc 100644
--- a/tests/ui/foreign/foreign2.rs
+++ b/tests/ui/foreign/foreign2.rs
@@ -1,9 +1,8 @@
 //@ run-pass
-#![allow(dead_code)]
 //@ pretty-expanded FIXME #23616
-#![feature(rustc_private)]
 
-extern crate libc;
+#![allow(dead_code)]
+#![feature(rustc_private)]
 
 mod bar {
     extern "C" {}
@@ -13,14 +12,37 @@ mod zed {
     extern "C" {}
 }
 
+#[cfg(not(windows))]
 mod mlibc {
-    use libc::{c_int, c_void, size_t, ssize_t};
+    extern crate libc;
+    use self::libc::{c_int, c_void, size_t, ssize_t};
 
     extern "C" {
         pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t;
     }
 }
 
+#[cfg(windows)]
+mod mlibc {
+    #![allow(non_snake_case)]
+
+    use std::ffi::c_void;
+
+    pub type BOOL = i32;
+    pub type HANDLE = *mut c_void;
+
+    #[link(name = "ntdll")]
+    extern "system" {
+        pub fn WriteFile(
+            hfile: HANDLE,
+            lpbuffer: *const u8,
+            nnumberofbytestowrite: u32,
+            lpnumberofbyteswritten: *mut u32,
+            lpoverlapped: *mut c_void,
+        ) -> BOOL;
+    }
+}
+
 mod baz {
     extern "C" {}
 }
diff --git a/tests/ui/optimization-fuel-0.rs b/tests/ui/fuel/optimization-fuel-0.rs
index cbcb1d329a3..cbcb1d329a3 100644
--- a/tests/ui/optimization-fuel-0.rs
+++ b/tests/ui/fuel/optimization-fuel-0.rs
diff --git a/tests/ui/optimization-fuel-0.stderr b/tests/ui/fuel/optimization-fuel-0.stderr
index f0e2ebfc37a..f0e2ebfc37a 100644
--- a/tests/ui/optimization-fuel-0.stderr
+++ b/tests/ui/fuel/optimization-fuel-0.stderr
diff --git a/tests/ui/optimization-fuel-1.rs b/tests/ui/fuel/optimization-fuel-1.rs
index 97edb0bd259..97edb0bd259 100644
--- a/tests/ui/optimization-fuel-1.rs
+++ b/tests/ui/fuel/optimization-fuel-1.rs
diff --git a/tests/ui/optimization-fuel-1.stderr b/tests/ui/fuel/optimization-fuel-1.stderr
index 53eafb05830..53eafb05830 100644
--- a/tests/ui/optimization-fuel-1.stderr
+++ b/tests/ui/fuel/optimization-fuel-1.stderr
diff --git a/tests/ui/print-fuel/print-fuel.rs b/tests/ui/fuel/print-fuel.rs
index fd7e568bea7..fd7e568bea7 100644
--- a/tests/ui/print-fuel/print-fuel.rs
+++ b/tests/ui/fuel/print-fuel.rs
diff --git a/tests/ui/print-fuel/print-fuel.stderr b/tests/ui/fuel/print-fuel.stderr
index cc88cc077bb..cc88cc077bb 100644
--- a/tests/ui/print-fuel/print-fuel.stderr
+++ b/tests/ui/fuel/print-fuel.stderr
diff --git a/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs
new file mode 100644
index 00000000000..b2ac332b4f0
--- /dev/null
+++ b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+
+trait Trait1<T>
+  where T: for<'a> Trait1<T> + 'b { } //~ ERROR use of undeclared lifetime name `'b`
+
+trait Trait2<T>
+where
+    T: B<'b> + for<'a> A<'a>, //~ ERROR use of undeclared lifetime name `'b`
+{
+}
+
+trait Trait3<T>
+where
+    T: B<'b> + for<'a> A<'a> + 'c {}
+    //~^ ERROR use of undeclared lifetime name `'b`
+    //~| ERROR use of undeclared lifetime name `'c`
+
+trait Trait4<T>
+where
+    T: for<'a> A<'a> + 'x + for<'b> B<'b>, //~ ERROR use of undeclared lifetime name `'x`
+{
+}
+
+trait A<'a> {}
+trait B<'a> {}
+
+
+fn main() {}
diff --git a/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr
new file mode 100644
index 00000000000..40f0769964f
--- /dev/null
+++ b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr
@@ -0,0 +1,92 @@
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:4:32
+   |
+LL |   where T: for<'a> Trait1<T> + 'b { }
+   |                                ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL -   where T: for<'a> Trait1<T> + 'b { }
+LL +   where for<'b, 'a> T: Trait1<T> + 'b { }
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Trait1<'b, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:8:10
+   |
+LL |     T: B<'b> + for<'a> A<'a>,
+   |          ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     T: for<'b> B<'b> + for<'a> A<'a>,
+   |        +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL -     T: B<'b> + for<'a> A<'a>,
+LL +     for<'b, 'a> T: B<'b> + A<'a>,
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Trait2<'b, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:10
+   |
+LL |     T: B<'b> + for<'a> A<'a> + 'c {}
+   |          ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     T: for<'b> B<'b> + for<'a> A<'a> + 'c {}
+   |        +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL -     T: B<'b> + for<'a> A<'a> + 'c {}
+LL +     for<'b, 'a> T: B<'b> + A<'a> + 'c {}
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Trait3<'b, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'c`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:32
+   |
+LL |     T: B<'b> + for<'a> A<'a> + 'c {}
+   |                                ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'c` lifetime
+   |
+LL -     T: B<'b> + for<'a> A<'a> + 'c {}
+LL +     for<'c, 'a> T: B<'b> + A<'a> + 'c {}
+   |
+help: consider introducing lifetime `'c` here
+   |
+LL | trait Trait3<'c, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'x`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:20:24
+   |
+LL |     T: for<'a> A<'a> + 'x + for<'b> B<'b>,
+   |                        ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'x` lifetime
+   |
+LL -     T: for<'a> A<'a> + 'x + for<'b> B<'b>,
+LL +     for<'x, 'a, 'b> T: A<'a> + 'x + B<'b>,
+   |
+help: consider introducing lifetime `'x` here
+   |
+LL | trait Trait4<'x, T>
+   |              +++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
index 2f53bd019b7..e0d2e44e6e7 100644
--- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
@@ -49,7 +49,7 @@ fn function3<T: Trait<'static, Assoc = usize>>() {
     // Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)`
     // only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already
     // instantiated, causing us to prefer the where-bound over the impl
-    // resulting in a placeholder error. Even if were were to also use the
+    // resulting in a placeholder error. Even if we were to also use the
     // leak check during candidate selection for normalization, this
     // case would still not compile.
     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
diff --git a/tests/ui/impl-trait/issue-99914.stderr b/tests/ui/impl-trait/issue-99914.stderr
index 06e85e521d2..8adb211745a 100644
--- a/tests/ui/impl-trait/issue-99914.stderr
+++ b/tests/ui/impl-trait/issue-99914.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/issue-99914.rs:9:27
    |
 LL |     t.and_then(|t| -> _ { bar(t) });
-   |                           ^^^^^^ expected `Result<_, Error>`, found future
+   |                       -   ^^^^^^ expected `Result<_, Error>`, found future
+   |                       |
+   |                       expected `Result<_, Error>` because of return type
    |
 help: try wrapping the expression in `Ok`
    |
diff --git a/tests/ui/imports/issue-37887.rs b/tests/ui/imports/issue-37887.rs
index 58f0c6b651a..919f46d34c6 100644
--- a/tests/ui/imports/issue-37887.rs
+++ b/tests/ui/imports/issue-37887.rs
@@ -1,4 +1,4 @@
 fn main() {
-    extern crate libc; //~ ERROR use of unstable
-    use libc::*; //~ ERROR unresolved import
+    extern crate test; //~ ERROR use of unstable
+    use test::*; //~ ERROR unresolved import
 }
diff --git a/tests/ui/imports/issue-37887.stderr b/tests/ui/imports/issue-37887.stderr
index 6117fd21af1..e7792ac0d15 100644
--- a/tests/ui/imports/issue-37887.stderr
+++ b/tests/ui/imports/issue-37887.stderr
@@ -1,19 +1,19 @@
-error[E0432]: unresolved import `libc`
+error[E0432]: unresolved import `test`
   --> $DIR/issue-37887.rs:3:9
    |
-LL |     use libc::*;
-   |         ^^^^ maybe a missing crate `libc`?
+LL |     use test::*;
+   |         ^^^^ maybe a missing crate `test`?
    |
-   = help: consider adding `extern crate libc` to use the `libc` crate
+   = help: consider adding `extern crate test` to use the `test` crate
 
-error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
+error[E0658]: use of unstable library feature 'test'
   --> $DIR/issue-37887.rs:2:5
    |
-LL |     extern crate libc;
+LL |     extern crate test;
    |     ^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
-   = help: add `#![feature(rustc_private)]` to the crate attributes to enable
+   = note: see issue #50297 <https://github.com/rust-lang/rust/issues/50297> for more information
+   = help: add `#![feature(test)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/infer-fn-tail-expr.rs b/tests/ui/inference/infer-fn-tail-expr.rs
index 31b71e49bd6..31b71e49bd6 100644
--- a/tests/ui/infer-fn-tail-expr.rs
+++ b/tests/ui/inference/infer-fn-tail-expr.rs
diff --git a/tests/ui/lambda-infer-unresolved.rs b/tests/ui/inference/lambda-infer-unresolved.rs
index f30832044dc..f30832044dc 100644
--- a/tests/ui/lambda-infer-unresolved.rs
+++ b/tests/ui/inference/lambda-infer-unresolved.rs
diff --git a/tests/ui/order-dependent-cast-inference.rs b/tests/ui/inference/order-dependent-cast-inference.rs
index e666209b912..e666209b912 100644
--- a/tests/ui/order-dependent-cast-inference.rs
+++ b/tests/ui/inference/order-dependent-cast-inference.rs
diff --git a/tests/ui/order-dependent-cast-inference.stderr b/tests/ui/inference/order-dependent-cast-inference.stderr
index ab33b703a05..ab33b703a05 100644
--- a/tests/ui/order-dependent-cast-inference.stderr
+++ b/tests/ui/inference/order-dependent-cast-inference.stderr
diff --git a/tests/ui/intrinsics-always-extern.rs b/tests/ui/intrinsics/always-extern.rs
index 0afd8353455..0afd8353455 100644
--- a/tests/ui/intrinsics-always-extern.rs
+++ b/tests/ui/intrinsics/always-extern.rs
diff --git a/tests/ui/intrinsics-always-extern.stderr b/tests/ui/intrinsics/always-extern.stderr
index 1f7bb5a3b0d..44b889c6faa 100644
--- a/tests/ui/intrinsics-always-extern.stderr
+++ b/tests/ui/intrinsics/always-extern.stderr
@@ -1,11 +1,11 @@
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/intrinsics-always-extern.rs:4:32
+  --> $DIR/always-extern.rs:4:32
    |
 LL |     extern "rust-intrinsic" fn foo(&self);
    |                                ^^^
 
 error[E0093]: unrecognized intrinsic function: `hello`
-  --> $DIR/intrinsics-always-extern.rs:12:28
+  --> $DIR/always-extern.rs:12:28
    |
 LL | extern "rust-intrinsic" fn hello() {
    |                            ^^^^^ unrecognized intrinsic
@@ -13,7 +13,7 @@ LL | extern "rust-intrinsic" fn hello() {
    = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/intrinsics-always-extern.rs:8:43
+  --> $DIR/always-extern.rs:8:43
    |
 LL |       extern "rust-intrinsic" fn foo(&self) {
    |  ___________________________________________^
@@ -21,7 +21,7 @@ LL | |     }
    | |_____^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/intrinsics-always-extern.rs:12:36
+  --> $DIR/always-extern.rs:12:36
    |
 LL |   extern "rust-intrinsic" fn hello() {
    |  ____________________________________^
diff --git a/tests/ui/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs
index 6c52651f060..6c52651f060 100644
--- a/tests/ui/reify-intrinsic.rs
+++ b/tests/ui/intrinsics/reify-intrinsic.rs
diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr
index 0119a1a6650..0119a1a6650 100644
--- a/tests/ui/reify-intrinsic.stderr
+++ b/tests/ui/intrinsics/reify-intrinsic.stderr
diff --git a/tests/ui/iterators/into-iter-on-arrays-2018.stderr b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
index 2378476e5d0..9d6bbf06c36 100644
--- a/tests/ui/iterators/into-iter-on-arrays-2018.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
@@ -1,4 +1,4 @@
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:14:34
    |
 LL |     let _: Iter<'_, i32> = array.into_iter();
@@ -16,7 +16,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit
 LL |     let _: Iter<'_, i32> = IntoIterator::into_iter(array);
    |                            ++++++++++++++++++++++++     ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:18:44
    |
 LL |     let _: Iter<'_, i32> = Box::new(array).into_iter();
@@ -25,7 +25,7 @@ LL |     let _: Iter<'_, i32> = Box::new(array).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:22:43
    |
 LL |     let _: Iter<'_, i32> = Rc::new(array).into_iter();
@@ -34,7 +34,7 @@ LL |     let _: Iter<'_, i32> = Rc::new(array).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:25:41
    |
 LL |     let _: Iter<'_, i32> = Array(array).into_iter();
@@ -43,7 +43,7 @@ LL |     let _: Iter<'_, i32> = Array(array).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:32:24
    |
 LL |     for _ in [1, 2, 3].into_iter() {}
diff --git a/tests/ui/iterators/into-iter-on-arrays-lint.stderr b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
index 2fde276faa3..da388d6b848 100644
--- a/tests/ui/iterators/into-iter-on-arrays-lint.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
@@ -1,4 +1,4 @@
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:11:11
    |
 LL |     small.into_iter();
@@ -16,7 +16,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit
 LL |     IntoIterator::into_iter(small);
    |     ++++++++++++++++++++++++     ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:14:12
    |
 LL |     [1, 2].into_iter();
@@ -33,7 +33,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit
 LL |     IntoIterator::into_iter([1, 2]);
    |     ++++++++++++++++++++++++      ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:17:9
    |
 LL |     big.into_iter();
@@ -50,7 +50,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit
 LL |     IntoIterator::into_iter(big);
    |     ++++++++++++++++++++++++   ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:20:15
    |
 LL |     [0u8; 33].into_iter();
@@ -67,7 +67,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit
 LL |     IntoIterator::into_iter([0u8; 33]);
    |     ++++++++++++++++++++++++         ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:24:21
    |
 LL |     Box::new(small).into_iter();
@@ -76,7 +76,7 @@ LL |     Box::new(small).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:27:22
    |
 LL |     Box::new([1, 2]).into_iter();
@@ -85,7 +85,7 @@ LL |     Box::new([1, 2]).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:30:19
    |
 LL |     Box::new(big).into_iter();
@@ -94,7 +94,7 @@ LL |     Box::new(big).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:33:25
    |
 LL |     Box::new([0u8; 33]).into_iter();
@@ -103,7 +103,7 @@ LL |     Box::new([0u8; 33]).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:37:31
    |
 LL |     Box::new(Box::new(small)).into_iter();
@@ -112,7 +112,7 @@ LL |     Box::new(Box::new(small)).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:40:32
    |
 LL |     Box::new(Box::new([1, 2])).into_iter();
@@ -121,7 +121,7 @@ LL |     Box::new(Box::new([1, 2])).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:43:29
    |
 LL |     Box::new(Box::new(big)).into_iter();
@@ -130,7 +130,7 @@ LL |     Box::new(Box::new(big)).into_iter();
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:46:35
    |
 LL |     Box::new(Box::new([0u8; 33])).into_iter();
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs
new file mode 100644
index 00000000000..3d9d131e59c
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs
@@ -0,0 +1,46 @@
+//@ check-pass
+//@ edition:2018
+
+use std::ops::Deref;
+use std::rc::Rc;
+use std::slice::Iter;
+use std::vec::IntoIter;
+
+fn main() {
+    let boxed_slice = vec![0; 10].into_boxed_slice();
+
+    // Before 2024, the method dispatched to `IntoIterator for Box<[T]>`,
+    // which we continue to support for compatibility.
+    let _: Iter<'_, i32> = boxed_slice.into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    let _: Iter<'_, i32> = Box::new(boxed_slice.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    let _: Iter<'_, i32> = Rc::new(boxed_slice.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    let _: Iter<'_, i32> = Array(boxed_slice.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    // But you can always use the trait method explicitly as an boxed_slice.
+    let _: IntoIter<i32> = IntoIterator::into_iter(boxed_slice);
+
+    for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+}
+
+/// User type that dereferences to a boxed slice.
+struct Array(Box<[i32]>);
+
+impl Deref for Array {
+    type Target = Box<[i32]>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
new file mode 100644
index 00000000000..d7f38a23725
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
@@ -0,0 +1,60 @@
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:14:40
+   |
+LL |     let _: Iter<'_, i32> = boxed_slice.into_iter();
+   |                                        ^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: `#[warn(boxed_slice_into_iter)]` on by default
+help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+   |
+LL |     let _: Iter<'_, i32> = boxed_slice.iter();
+   |                                        ~~~~
+help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+   |
+LL |     let _: Iter<'_, i32> = IntoIterator::into_iter(boxed_slice);
+   |                            ++++++++++++++++++++++++           ~
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:18:58
+   |
+LL |     let _: Iter<'_, i32> = Box::new(boxed_slice.clone()).into_iter();
+   |                                                          ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:22:57
+   |
+LL |     let _: Iter<'_, i32> = Rc::new(boxed_slice.clone()).into_iter();
+   |                                                         ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:25:55
+   |
+LL |     let _: Iter<'_, i32> = Array(boxed_slice.clone()).into_iter();
+   |                                                       ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:32:48
+   |
+LL |     for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
+   |                                                ^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+   |
+LL |     for _ in (Box::new([1, 2, 3]) as Box<[_]>).iter() {}
+   |                                                ~~~~
+help: or remove `.into_iter()` to iterate by value
+   |
+LL -     for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
+LL +     for _ in (Box::new([1, 2, 3]) as Box<[_]>) {}
+   |
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
new file mode 100644
index 00000000000..ffd6f022bc6
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+//@ edition:2024
+//@ compile-flags: -Zunstable-options
+
+use std::ops::Deref;
+use std::rc::Rc;
+use std::vec::IntoIter;
+
+fn main() {
+    let boxed_slice = vec![0; 10].into_boxed_slice();
+
+    // In 2021, the method dispatches to `IntoIterator for [T; N]`.
+    let _: IntoIter<i32> = boxed_slice.clone().into_iter();
+
+    // And through other boxes.
+    let _: IntoIter<i32> = Box::new(boxed_slice.clone()).into_iter();
+
+    // You can always use the trait method explicitly as a boxed_slice.
+    let _: IntoIter<i32> = IntoIterator::into_iter(boxed_slice.clone());
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed b/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed
new file mode 100644
index 00000000000..265a6c764d2
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed
@@ -0,0 +1,30 @@
+//@ run-pass
+//@ run-rustfix
+//@ rustfix-only-machine-applicable
+
+#[allow(unused_must_use, unused_allocation)]
+fn main() {
+    let boxed = vec![1, 2].into_boxed_slice();
+
+    // Expressions that should trigger the lint
+    boxed.iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(boxed.clone()).iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(Box::new(boxed.clone())).iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    // Expressions that should not
+    (&boxed).into_iter();
+
+    for _ in &boxed {}
+    (&boxed as &[_]).into_iter();
+    boxed[..].into_iter();
+    std::iter::IntoIterator::into_iter(&boxed);
+
+    #[allow(boxed_slice_into_iter)]
+    boxed.into_iter();
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs b/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs
new file mode 100644
index 00000000000..dd78e481e0e
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+//@ run-rustfix
+//@ rustfix-only-machine-applicable
+
+#[allow(unused_must_use, unused_allocation)]
+fn main() {
+    let boxed = vec![1, 2].into_boxed_slice();
+
+    // Expressions that should trigger the lint
+    boxed.into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(boxed.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(Box::new(boxed.clone())).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    // Expressions that should not
+    (&boxed).into_iter();
+
+    for _ in &boxed {}
+    (&boxed as &[_]).into_iter();
+    boxed[..].into_iter();
+    std::iter::IntoIterator::into_iter(&boxed);
+
+    #[allow(boxed_slice_into_iter)]
+    boxed.into_iter();
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
new file mode 100644
index 00000000000..b73faf0dbd3
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
@@ -0,0 +1,35 @@
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-lint.rs:10:11
+   |
+LL |     boxed.into_iter();
+   |           ^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: `#[warn(boxed_slice_into_iter)]` on by default
+help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+   |
+LL |     boxed.iter();
+   |           ~~~~
+help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+   |
+LL |     IntoIterator::into_iter(boxed);
+   |     ++++++++++++++++++++++++     ~
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-lint.rs:13:29
+   |
+LL |     Box::new(boxed.clone()).into_iter();
+   |                             ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-lint.rs:16:39
+   |
+LL |     Box::new(Box::new(boxed.clone())).into_iter();
+   |                                       ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/lifetimes/issue-17728.stderr b/tests/ui/lifetimes/issue-17728.stderr
index 23547f722a1..eb4381ea99e 100644
--- a/tests/ui/lifetimes/issue-17728.stderr
+++ b/tests/ui/lifetimes/issue-17728.stderr
@@ -29,8 +29,8 @@ LL |             Some(entry) => Ok(entry),
    |
 help: consider introducing a named lifetime parameter
    |
-LL |     fn attemptTraverse<'a>(&'a self, room: &'a Room, directionStr: &str) -> Result<&Room, &str> {
-   |                       ++++  ++              ++
+LL |     fn attemptTraverse<'a>(&self, room: &'a Room, directionStr: &str) -> Result<&'a Room, &'a str> {
+   |                       ++++               ++                                      ++        ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr b/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
index 48fb3fb4a22..82511d07b0e 100644
--- a/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
+++ b/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
@@ -35,7 +35,7 @@ LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
    |                                               |        let's call the lifetime of this reference `'1`
    |                                               let's call the lifetime of this reference `'2`
    |
-help: consider introducing a named lifetime parameter
+help: consider reusing a named lifetime parameter
    |
 LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
    |                                                ++          ++
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr
index 5827b2fe695..2caab3df6b8 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr
@@ -8,6 +8,11 @@ LL |     fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
 LL |
 LL |         if x > y { x } else { y }
    |                    ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+   |                    ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed
new file mode 100644
index 00000000000..40eee22fc32
--- /dev/null
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed
@@ -0,0 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
+struct Foo {
+    field: i32,
+}
+
+impl Foo {
+    fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
index 49993aca3ca..c8dd958b37c 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
@@ -1,15 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
 struct Foo {
-  field: i32
+    field: i32,
 }
 
 impl Foo {
-  fn foo<'a>(&self, x: &'a i32) -> &i32 {
-
-    x
-    //~^ ERROR lifetime may not live long enough
-
-  }
-
+    fn foo<'a>(&self, x: &'a i32) -> &i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
index da454b8fd86..c743351a670 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
@@ -1,13 +1,17 @@
 error: lifetime may not live long enough
-  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:8:5
+  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:9:9
    |
-LL |   fn foo<'a>(&self, x: &'a i32) -> &i32 {
-   |          --  - let's call the lifetime of this reference `'1`
-   |          |
-   |          lifetime `'a` defined here
-LL |
-LL |     x
-   |     ^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+LL |     fn foo<'a>(&self, x: &'a i32) -> &i32 {
+   |            --  - let's call the lifetime of this reference `'1`
+   |            |
+   |            lifetime `'a` defined here
+LL |         x
+   |         ^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+   |                                       ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr
index a1dfff883a0..4ed6c3bc92d 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr
@@ -8,6 +8,11 @@ LL |     fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
 LL |
 LL |         if true { x } else { self }
    |                              ^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(&'a self, x: &'a Foo) -> &'a Foo {
+   |                 ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr
index df1d03d5170..6f7127d4c4c 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr
@@ -7,6 +7,11 @@ LL | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
    |        has type `&mut Vec<Ref<'2, i32>>`
 LL |     x.push(y);
    |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<'a, i32>) {
+   |       ++++                 +++               +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
index 4f1cb1e7972..f8ad923cce8 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Ref, y: Ref) {
    |        has type `Ref<'_, '2>`
 LL |     x.b = y.b;
    |     ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: Ref<'a, 'a>) {
+   |       ++++           ++++++++        ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
index 3a1947973b5..a1149779d2c 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
@@ -8,6 +8,11 @@ LL | fn foo(mut x: Ref) {
    |        has type `Ref<'2, '_>`
 LL |     x.a = x.b;
    |     ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>) {
+   |       ++++           ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
index c778f77366a..017bfa71463 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Vec<Ref>, y: Ref) {
    |        has type `Vec<Ref<'2>>`
 LL |     x.push(y);
    |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Vec<Ref<'a>>, y: Ref<'a>) {
+   |       ++++               ++++         ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
index bbd62902d9f..0980de92d35 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Ref, y: &u32) {
    |        has type `Ref<'_, '1>`
 LL |     y = x.b;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error[E0384]: cannot assign to immutable argument `y`
   --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
index 60ca4168455..d9c7530b64c 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
@@ -7,6 +7,11 @@ LL | fn foo(mut y: Ref, x: &u32) {
    |        has type `Ref<'_, '2>`
 LL |     y.b = x;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut y: Ref<'a, 'a>, x: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
index 98e490c3827..d07b821444c 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
@@ -7,6 +7,11 @@ LL | fn foo(mut y: Ref, x: &u32) {
    |        has type `Ref<'_, '2>`
 LL |     y.b = x;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut y: Ref<'a, 'a>, x: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
index ea1cc1f18a4..ef28ddeacc5 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
@@ -7,6 +7,11 @@ LL | fn foo(mut x: Ref, y: &u32) {
    |        has type `Ref<'_, '2>`
 LL |     x.b = y;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed
new file mode 100644
index 00000000000..40eee22fc32
--- /dev/null
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed
@@ -0,0 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
+struct Foo {
+    field: i32,
+}
+
+impl Foo {
+    fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
index 3ffd7be4e73..0225d8c7961 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
@@ -1,12 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
 struct Foo {
-  field: i32
+    field: i32,
 }
 
 impl Foo {
-  fn foo<'a>(&self, x: &i32) -> &i32 {
-    x
-    //~^ ERROR lifetime may not live long enough
-  }
+    fn foo<'a>(&self, x: &i32) -> &i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
index e934ce7c040..673a87a4537 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
@@ -1,17 +1,17 @@
 error: lifetime may not live long enough
-  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:7:5
+  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:9:9
    |
-LL |   fn foo<'a>(&self, x: &i32) -> &i32 {
-   |              -         - let's call the lifetime of this reference `'1`
-   |              |
-   |              let's call the lifetime of this reference `'2`
-LL |     x
-   |     ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+LL |     fn foo<'a>(&self, x: &i32) -> &i32 {
+   |                -         - let's call the lifetime of this reference `'1`
+   |                |
+   |                let's call the lifetime of this reference `'2`
+LL |         x
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
-help: consider introducing a named lifetime parameter and update trait if needed
+help: consider reusing a named lifetime parameter and update trait if needed
    |
-LL |   fn foo<'a>(&'a self, x: &'a i32) -> &i32 {
-   |               ++           ++
+LL |     fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+   |                           ++          ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
index dde271d100c..64bd448a074 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
@@ -8,10 +8,10 @@ LL |     fn foo<'a>(&self, x: &Foo) -> &Foo {
 LL |         if true { x } else { self }
    |                   ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
-help: consider introducing a named lifetime parameter and update trait if needed
+help: consider reusing a named lifetime parameter and update trait if needed
    |
-LL |     fn foo<'a>(&'a self, x: &'a Foo) -> &Foo {
-   |                 ++           ++
+LL |     fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
+   |                           ++          ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr
index e3854a5459e..c4ee18fe8da 100644
--- a/tests/ui/lint/anonymous-reexport.stderr
+++ b/tests/ui/lint/anonymous-reexport.stderr
@@ -34,7 +34,7 @@ error: unused import: `Bar as _`
 LL | pub use self::my_mod::{Bar as _, Foo as _};
    |                        ^^^^^^^^
 
-error: unused imports: `Bar as _`, `TyBar as _`
+error: unused imports: `Bar as _` and `TyBar as _`
   --> $DIR/anonymous-reexport.rs:17:24
    |
 LL | pub use self::my_mod::{Bar as _, TyBar as _};
diff --git a/tests/ui/lint-group-denied-lint-allowed.rs b/tests/ui/lint/group-denied-lint-allowed.rs
index 86b63bb31e3..86b63bb31e3 100644
--- a/tests/ui/lint-group-denied-lint-allowed.rs
+++ b/tests/ui/lint/group-denied-lint-allowed.rs
diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.rs b/tests/ui/lint/group-forbid-always-trumps-cli.rs
index 4b63452bf5d..4b63452bf5d 100644
--- a/tests/ui/lint-group-forbid-always-trumps-cli.rs
+++ b/tests/ui/lint/group-forbid-always-trumps-cli.rs
diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.stderr b/tests/ui/lint/group-forbid-always-trumps-cli.stderr
index 04a0f56c163..21674ebae9c 100644
--- a/tests/ui/lint-group-forbid-always-trumps-cli.stderr
+++ b/tests/ui/lint/group-forbid-always-trumps-cli.stderr
@@ -1,5 +1,5 @@
 error: unused variable: `x`
-  --> $DIR/lint-group-forbid-always-trumps-cli.rs:4:9
+  --> $DIR/group-forbid-always-trumps-cli.rs:4:9
    |
 LL |     let x = 1;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
diff --git a/tests/ui/lint-unknown-lints-at-crate-level.rs b/tests/ui/lint/unknown-lints-at-crate-level.rs
index c8cf65ce93a..c8cf65ce93a 100644
--- a/tests/ui/lint-unknown-lints-at-crate-level.rs
+++ b/tests/ui/lint/unknown-lints-at-crate-level.rs
diff --git a/tests/ui/lint/unnecessary-extern-crate.rs b/tests/ui/lint/unnecessary-extern-crate.rs
index 6ca3b96758f..7f97a4c469e 100644
--- a/tests/ui/lint/unnecessary-extern-crate.rs
+++ b/tests/ui/lint/unnecessary-extern-crate.rs
@@ -1,12 +1,12 @@
 //@ edition:2018
 
 #![deny(unused_extern_crates)]
-#![feature(test, rustc_private)]
+#![feature(test)]
 
-extern crate libc;
+extern crate core;
 //~^ ERROR unused extern crate
 //~| HELP remove
-extern crate libc as x;
+extern crate core as x;
 //~^ ERROR unused extern crate
 //~| HELP remove
 
@@ -28,11 +28,11 @@ mod foo {
 
     pub(super) extern crate alloc as d;
 
-    extern crate libc;
+    extern crate core;
     //~^ ERROR unused extern crate
     //~| HELP remove
 
-    extern crate libc as x;
+    extern crate core as x;
     //~^ ERROR unused extern crate
     //~| HELP remove
 
@@ -41,11 +41,11 @@ mod foo {
     pub extern crate test as y;
 
     mod bar {
-        extern crate libc;
+        extern crate core;
         //~^ ERROR unused extern crate
         //~| HELP remove
 
-        extern crate libc as x;
+        extern crate core as x;
         //~^ ERROR unused extern crate
         //~| HELP remove
 
diff --git a/tests/ui/lint/unnecessary-extern-crate.stderr b/tests/ui/lint/unnecessary-extern-crate.stderr
index 14ba9d052f4..1fa4aa9c9a9 100644
--- a/tests/ui/lint/unnecessary-extern-crate.stderr
+++ b/tests/ui/lint/unnecessary-extern-crate.stderr
@@ -1,7 +1,7 @@
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:6:1
    |
-LL | extern crate libc;
+LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ help: remove it
    |
 note: the lint level is defined here
@@ -13,31 +13,31 @@ LL | #![deny(unused_extern_crates)]
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:9:1
    |
-LL | extern crate libc as x;
+LL | extern crate core as x;
    | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:31:5
    |
-LL |     extern crate libc;
+LL |     extern crate core;
    |     ^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:35:5
    |
-LL |     extern crate libc as x;
+LL |     extern crate core as x;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:44:9
    |
-LL |         extern crate libc;
+LL |         extern crate core;
    |         ^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:48:9
    |
-LL |         extern crate libc as x;
+LL |         extern crate core as x;
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/lint/unused/import_remove_line.stderr b/tests/ui/lint/unused/import_remove_line.stderr
index 0e8c5de3558..b2a16669a93 100644
--- a/tests/ui/lint/unused/import_remove_line.stderr
+++ b/tests/ui/lint/unused/import_remove_line.stderr
@@ -1,4 +1,4 @@
-warning: unused imports: `Duration`, `Instant`
+warning: unused imports: `Duration` and `Instant`
   --> $DIR/import_remove_line.rs:7:17
    |
 LL | use std::time::{Duration, Instant};
diff --git a/tests/ui/lint/unused/lint-unused-imports.rs b/tests/ui/lint/unused/lint-unused-imports.rs
index 88f2baa5da9..710fb7a5ed1 100644
--- a/tests/ui/lint/unused/lint-unused-imports.rs
+++ b/tests/ui/lint/unused/lint-unused-imports.rs
@@ -10,7 +10,7 @@ use std::fmt::{};
 
 // Should get errors for both 'Some' and 'None'
 use std::option::Option::{Some, None};
-//~^ ERROR unused imports: `None`, `Some`
+//~^ ERROR unused imports: `None` and `Some`
 
 use test::A;       //~ ERROR unused import: `test::A`
 // Be sure that if we just bring some methods into scope that they're also
diff --git a/tests/ui/lint/unused/lint-unused-imports.stderr b/tests/ui/lint/unused/lint-unused-imports.stderr
index 07684a84a64..a848fb31eba 100644
--- a/tests/ui/lint/unused/lint-unused-imports.stderr
+++ b/tests/ui/lint/unused/lint-unused-imports.stderr
@@ -10,7 +10,7 @@ note: the lint level is defined here
 LL | #![deny(unused_imports)]
    |         ^^^^^^^^^^^^^^
 
-error: unused imports: `None`, `Some`
+error: unused imports: `None` and `Some`
   --> $DIR/lint-unused-imports.rs:12:27
    |
 LL | use std::option::Option::{Some, None};
diff --git a/tests/ui/compile_error_macro.rs b/tests/ui/macros/compile_error_macro.rs
index 3f7b57cd078..3f7b57cd078 100644
--- a/tests/ui/compile_error_macro.rs
+++ b/tests/ui/macros/compile_error_macro.rs
diff --git a/tests/ui/compile_error_macro.stderr b/tests/ui/macros/compile_error_macro.stderr
index 92d5564e8a7..92d5564e8a7 100644
--- a/tests/ui/compile_error_macro.stderr
+++ b/tests/ui/macros/compile_error_macro.stderr
diff --git a/tests/ui/module-macro_use-arguments.rs b/tests/ui/macros/module-macro_use-arguments.rs
index 121b492e254..121b492e254 100644
--- a/tests/ui/module-macro_use-arguments.rs
+++ b/tests/ui/macros/module-macro_use-arguments.rs
diff --git a/tests/ui/module-macro_use-arguments.stderr b/tests/ui/macros/module-macro_use-arguments.stderr
index 3ac645ad3a9..3ac645ad3a9 100644
--- a/tests/ui/module-macro_use-arguments.stderr
+++ b/tests/ui/macros/module-macro_use-arguments.stderr
diff --git a/tests/ui/no-patterns-in-args-macro.rs b/tests/ui/macros/no-patterns-in-args-macro.rs
index b5109f9c286..b5109f9c286 100644
--- a/tests/ui/no-patterns-in-args-macro.rs
+++ b/tests/ui/macros/no-patterns-in-args-macro.rs
diff --git a/tests/ui/no-patterns-in-args-macro.stderr b/tests/ui/macros/no-patterns-in-args-macro.stderr
index 0016c7953f3..0016c7953f3 100644
--- a/tests/ui/no-patterns-in-args-macro.stderr
+++ b/tests/ui/macros/no-patterns-in-args-macro.stderr
diff --git a/tests/ui/malformed/malformed-regressions.rs b/tests/ui/malformed/malformed-regressions.rs
index ac1444bbaef..f0a7aac59c1 100644
--- a/tests/ui/malformed/malformed-regressions.rs
+++ b/tests/ui/malformed/malformed-regressions.rs
@@ -1,8 +1,8 @@
-#[doc] //~ ERROR attribute must be of the form
+#[doc] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
-#[ignore()] //~ ERROR attribute must be of the form
+#[ignore()] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
-#[inline = ""] //~ ERROR attribute must be of the form
+#[inline = ""] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
 #[link] //~ ERROR attribute must be of the form
 //~^ WARN this was previously accepted
diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr
index 9bfbe7ebafd..e1dbdb9ab3c 100644
--- a/tests/ui/malformed/malformed-regressions.stderr
+++ b/tests/ui/malformed/malformed-regressions.stderr
@@ -1,4 +1,4 @@
-error: attribute must be of the form `#[doc(hidden|inline|...)]` or `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
   --> $DIR/malformed-regressions.rs:1:1
    |
 LL | #[doc]
@@ -8,7 +8,7 @@ LL | #[doc]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: attribute must be of the form `#[ignore]` or `#[ignore = "reason"]`
+error: valid forms for the attribute are `#[ignore]` and `#[ignore = "reason"]`
   --> $DIR/malformed-regressions.rs:3:1
    |
 LL | #[ignore()]
@@ -17,7 +17,7 @@ LL | #[ignore()]
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
+error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
   --> $DIR/malformed-regressions.rs:5:1
    |
 LL | #[inline = ""]
diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout
index 8a23d906757..8949611ac12 100644
--- a/tests/ui/match/issue-82392.stdout
+++ b/tests/ui/match/issue-82392.stdout
@@ -7,10 +7,10 @@ extern crate std;
 //@ check-pass
 
 fn main() ({
-        (if (true as bool)
-                ({ } as
-                    ()) else if (let Some(a) =
-                       ((Some as
-                               fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
-                           Option<i32>) as bool) ({ } as ()) as ())
-               } as ())
+    (if (true as bool)
+            ({ } as
+                ()) else if (let Some(a) =
+                   ((Some as
+                           fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
+                       Option<i32>) as bool) ({ } as ()) as ())
+           } as ())
diff --git a/tests/ui/meta/no_std-extern-libc.rs b/tests/ui/meta/no_std-extern-libc.rs
index 919caf9428f..8b89e14382d 100644
--- a/tests/ui/meta/no_std-extern-libc.rs
+++ b/tests/ui/meta/no_std-extern-libc.rs
@@ -1,5 +1,6 @@
 // Test that `download-rustc` doesn't put duplicate copies of libc in the sysroot.
 //@ check-pass
+//@ ignore-windows doesn't necessarily have the libc crate
 #![crate_type = "lib"]
 #![no_std]
 #![feature(rustc_private)]
diff --git a/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs
new file mode 100644
index 00000000000..a08bbf1fdbe
--- /dev/null
+++ b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let x = Some(3);
+    let y = vec![1, 2];
+    if let Some(y) = x {
+        y.push(y); //~ ERROR E0599
+    }
+}
diff --git a/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr
new file mode 100644
index 00000000000..aecad201c7b
--- /dev/null
+++ b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr
@@ -0,0 +1,17 @@
+error[E0599]: no method named `push` found for type `{integer}` in the current scope
+  --> $DIR/account-for-shadowed-bindings-issue-123558.rs:5:11
+   |
+LL |         y.push(y);
+   |           ^^^^ method not found in `{integer}`
+   |
+note: there's an earlier shadowed binding `y` of type `Vec<{integer}>` that has method `push` available
+  --> $DIR/account-for-shadowed-bindings-issue-123558.rs:3:9
+   |
+LL |     let y = vec![1, 2];
+   |         ^ `y` of type `Vec<{integer}>` that has method `push` defined earlier here
+LL |     if let Some(y) = x {
+   |                 - earlier `y` shadowed here with type `{integer}`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
index 0ae498c134f..d65bfee843e 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
@@ -7,6 +7,7 @@ fn _zero() {
     if false {
         unsafe { mem::zeroed() }
         //~^ warn: never type fallback affects this call to an `unsafe` function
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -21,6 +22,7 @@ fn _trans() {
             struct Zst;
             core::mem::transmute(Zst)
             //~^ warn: never type fallback affects this call to an `unsafe` function
+            //~| warn: this will change its meaning in a future release!
         }
     } else {
         return;
@@ -36,6 +38,7 @@ fn _union() {
 
         unsafe { Union { a: () }.b }
         //~^ warn: never type fallback affects this union access
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -45,6 +48,7 @@ fn _deref() {
     if false {
         unsafe { *ptr::from_ref(&()).cast() }
         //~^ warn: never type fallback affects this raw pointer dereference
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -62,6 +66,7 @@ fn _only_generics() {
 
         unsafe { internally_create(x) }
         //~^ warn: never type fallback affects this call to an `unsafe` function
+        //~| warn: this will change its meaning in a future release!
 
         x.unwrap()
     } else {
@@ -73,9 +78,11 @@ fn _stored_function() {
     if false {
         let zeroed = mem::zeroed;
         //~^ warn: never type fallback affects this `unsafe` function
+        //~| warn: this will change its meaning in a future release!
 
         unsafe { zeroed() }
         //~^ warn: never type fallback affects this call to an `unsafe` function
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -90,6 +97,7 @@ fn _only_generics_stored_function() {
         let x = None;
         let f = internally_create;
         //~^ warn: never type fallback affects this `unsafe` function
+        //~| warn: this will change its meaning in a future release!
 
         unsafe { f(x) }
 
@@ -113,6 +121,7 @@ fn _method() {
         unsafe {
             S(marker::PhantomData).create_out_of_thin_air()
             //~^ warn: never type fallback affects this call to an `unsafe` method
+            //~| warn: this will change its meaning in a future release!
         }
     } else {
         return;
@@ -129,6 +138,7 @@ fn _objc() {
         () => {
             match send_message::<_ /* ?0 */>() {
                 //~^ warn: never type fallback affects this call to an `unsafe` function
+                //~| warn: this will change its meaning in a future release!
                 Ok(x) => x,
                 Err(_) => loop {},
             }
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
index 84c9385fd13..fbd92f8f662 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
@@ -4,75 +4,93 @@ warning: never type fallback affects this call to an `unsafe` function
 LL |         unsafe { mem::zeroed() }
    |                  ^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:22:13
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:23:13
    |
 LL |             core::mem::transmute(Zst)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this union access
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:37:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:39:18
    |
 LL |         unsafe { Union { a: () }.b }
    |                  ^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this raw pointer dereference
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:46:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:49:18
    |
 LL |         unsafe { *ptr::from_ref(&()).cast() }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:63:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:67:18
    |
 LL |         unsafe { internally_create(x) }
    |                  ^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:77:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:83:18
    |
 LL |         unsafe { zeroed() }
    |                  ^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:74:22
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:22
    |
 LL |         let zeroed = mem::zeroed;
    |                      ^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:91:17
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:98:17
    |
 LL |         let f = internally_create;
    |                 ^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` method
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:114:13
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:122:13
    |
 LL |             S(marker::PhantomData).create_out_of_thin_air()
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:130:19
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:139:19
    |
 LL |             match send_message::<_ /* ?0 */>() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,6 +98,8 @@ LL |             match send_message::<_ /* ?0 */>() {
 LL |         msg_send!();
    |         ----------- in this macro invocation
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
new file mode 100644
index 00000000000..3c0059ba3e3
--- /dev/null
+++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
@@ -0,0 +1,6 @@
+// Regression test for issue #124935
+// Tests that we do not erroneously emit an error about
+// missing main function when the mod starts with a `;`
+
+; //~ ERROR expected item, found `;`
+fn main() { }
diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
new file mode 100644
index 00000000000..9776677589f
--- /dev/null
+++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
@@ -0,0 +1,8 @@
+error: expected item, found `;`
+  --> $DIR/fn-no-semicolon-issue-124935-semi-after-item.rs:5:1
+   |
+LL | ;
+   | ^ help: remove this semicolon
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/issues/issue-49040.rs b/tests/ui/parser/issues/issue-49040.rs
index b7a541dd664..68e7cc9f80e 100644
--- a/tests/ui/parser/issues/issue-49040.rs
+++ b/tests/ui/parser/issues/issue-49040.rs
@@ -1,3 +1,3 @@
 #![allow(unused_variables)]; //~ ERROR expected item, found `;`
-//~^ ERROR `main` function
 fn foo() {}
+//~^ ERROR `main` function
diff --git a/tests/ui/parser/issues/issue-49040.stderr b/tests/ui/parser/issues/issue-49040.stderr
index 8af7838c791..11ef5e1aadf 100644
--- a/tests/ui/parser/issues/issue-49040.stderr
+++ b/tests/ui/parser/issues/issue-49040.stderr
@@ -5,10 +5,10 @@ LL | #![allow(unused_variables)];
    |                            ^ help: remove this semicolon
 
 error[E0601]: `main` function not found in crate `issue_49040`
-  --> $DIR/issue-49040.rs:1:29
+  --> $DIR/issue-49040.rs:2:12
    |
-LL | #![allow(unused_variables)];
-   |                             ^ consider adding a `main` function to `$DIR/issue-49040.rs`
+LL | fn foo() {}
+   |            ^ consider adding a `main` function to `$DIR/issue-49040.rs`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
new file mode 100644
index 00000000000..3fbac5fae23
--- /dev/null
+++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
@@ -0,0 +1,5 @@
+// Regression test for issue #124935
+// Tests that we still emit an error after an item.
+
+fn main() { }
+; //~ ERROR expected item, found `;`
diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
new file mode 100644
index 00000000000..2d7f540443d
--- /dev/null
+++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
@@ -0,0 +1,10 @@
+error: expected item, found `;`
+  --> $DIR/missing-main-issue-124935-semi-after-item.rs:5:1
+   |
+LL | ;
+   | ^ help: remove this semicolon
+   |
+   = help: function declarations are not followed by a semicolon
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/label-is-actually-char.rs b/tests/ui/parser/label-is-actually-char.rs
index 74df898d191..915ce86d269 100644
--- a/tests/ui/parser/label-is-actually-char.rs
+++ b/tests/ui/parser/label-is-actually-char.rs
@@ -1,4 +1,4 @@
-// Note: it's ok to interpret 'a as 'a', but but not ok to interpret 'abc as
+// Note: it's ok to interpret 'a as 'a', but not ok to interpret 'abc as
 // 'abc' because 'abc' is not a valid char literal.
 
 fn main() {
diff --git a/tests/ui/super-fast-paren-parsing.rs b/tests/ui/parser/super-fast-paren-parsing.rs
index ce7283eee03..5b7cd6fe47d 100644
--- a/tests/ui/super-fast-paren-parsing.rs
+++ b/tests/ui/parser/super-fast-paren-parsing.rs
@@ -3,10 +3,7 @@
 #![allow(unused_parens)]
 #![allow(non_upper_case_globals)]
 #![allow(dead_code)]
-//@ exec-env:RUST_MIN_STACK=16000000
-//@ rustc-env:RUST_MIN_STACK=16000000
-//
-// Big stack is needed for pretty printing, a little sad...
+#![cfg_attr(rustfmt, rustfmt::skip)]
 
 static a: isize =
 (((((((((((((((((((((((((((((((((((((((((((((((((((
diff --git a/tests/ui/by-move-pattern-binding.rs b/tests/ui/pattern/by-move-pattern-binding.rs
index f68d181291d..f68d181291d 100644
--- a/tests/ui/by-move-pattern-binding.rs
+++ b/tests/ui/pattern/by-move-pattern-binding.rs
diff --git a/tests/ui/by-move-pattern-binding.stderr b/tests/ui/pattern/by-move-pattern-binding.stderr
index 203e37dc387..203e37dc387 100644
--- a/tests/ui/by-move-pattern-binding.stderr
+++ b/tests/ui/pattern/by-move-pattern-binding.stderr
diff --git a/tests/ui/fn-in-pat.rs b/tests/ui/pattern/fn-in-pat.rs
index 2d7c86b8666..2d7c86b8666 100644
--- a/tests/ui/fn-in-pat.rs
+++ b/tests/ui/pattern/fn-in-pat.rs
diff --git a/tests/ui/fn-in-pat.stderr b/tests/ui/pattern/fn-in-pat.stderr
index 41ea4df72a2..41ea4df72a2 100644
--- a/tests/ui/fn-in-pat.stderr
+++ b/tests/ui/pattern/fn-in-pat.stderr
diff --git a/tests/ui/inc-range-pat.rs b/tests/ui/pattern/inc-range-pat.rs
index 189dac4feed..189dac4feed 100644
--- a/tests/ui/inc-range-pat.rs
+++ b/tests/ui/pattern/inc-range-pat.rs
diff --git a/tests/ui/no-patterns-in-args-2.rs b/tests/ui/pattern/no-patterns-in-args-2.rs
index 85b7fc5cdba..85b7fc5cdba 100644
--- a/tests/ui/no-patterns-in-args-2.rs
+++ b/tests/ui/pattern/no-patterns-in-args-2.rs
diff --git a/tests/ui/no-patterns-in-args-2.stderr b/tests/ui/pattern/no-patterns-in-args-2.stderr
index 6adcbb9dccd..6adcbb9dccd 100644
--- a/tests/ui/no-patterns-in-args-2.stderr
+++ b/tests/ui/pattern/no-patterns-in-args-2.stderr
diff --git a/tests/ui/no-patterns-in-args.rs b/tests/ui/pattern/no-patterns-in-args.rs
index 54836b0a3f5..54836b0a3f5 100644
--- a/tests/ui/no-patterns-in-args.rs
+++ b/tests/ui/pattern/no-patterns-in-args.rs
diff --git a/tests/ui/no-patterns-in-args.stderr b/tests/ui/pattern/no-patterns-in-args.stderr
index 1c2ce866467..1c2ce866467 100644
--- a/tests/ui/no-patterns-in-args.stderr
+++ b/tests/ui/pattern/no-patterns-in-args.stderr
diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs
index 653dcab5771..796ba4d2332 100644
--- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs
+++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs
@@ -6,7 +6,7 @@ mod rank {
     pub use self::Lieutenant::{JuniorGrade, Full};
     //~^ ERROR `JuniorGrade` is private, and cannot be re-exported
     //~| ERROR `Full` is private, and cannot be re-exported
-    //~| ERROR unused imports: `Full`, `JuniorGrade`
+    //~| ERROR unused imports: `Full` and `JuniorGrade`
     pub use self::PettyOfficer::*;
     //~^ ERROR glob import doesn't reexport anything
     //~| ERROR unused import: `self::PettyOfficer::*`
diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
index 93a39edbb82..f1701d547a6 100644
--- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
+++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
@@ -46,7 +46,7 @@ error: unused import: `self::Professor::*`
 LL |     pub use self::Professor::*;
    |             ^^^^^^^^^^^^^^^^^^
 
-error: unused imports: `Full`, `JuniorGrade`
+error: unused imports: `Full` and `JuniorGrade`
   --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32
    |
 LL |     pub use self::Lieutenant::{JuniorGrade, Full};
diff --git a/tests/ui/env-args-reverse-iterator.rs b/tests/ui/process/env-args-reverse-iterator.rs
index 830e9535466..830e9535466 100644
--- a/tests/ui/env-args-reverse-iterator.rs
+++ b/tests/ui/process/env-args-reverse-iterator.rs
diff --git a/tests/ui/env-funky-keys.rs b/tests/ui/process/env-funky-keys.rs
index 314ccaea015..314ccaea015 100644
--- a/tests/ui/env-funky-keys.rs
+++ b/tests/ui/process/env-funky-keys.rs
diff --git a/tests/ui/env-null-vars.rs b/tests/ui/process/env-null-vars.rs
index bb86fd353c4..24d783553d1 100644
--- a/tests/ui/env-null-vars.rs
+++ b/tests/ui/process/env-null-vars.rs
@@ -1,21 +1,15 @@
+// Ensure that env::vars() does not panic if environ is null.
+// Regression test for rust-lang/rust#53200
 //@ run-pass
 
-#![allow(unused_imports)]
-
-//@ ignore-windows
-
-// issue-53200
-
 #![feature(rustc_private)]
-extern crate libc;
-
-use std::env;
 
 // FIXME: more platforms?
 #[cfg(target_os = "linux")]
 fn main() {
+    extern crate libc;
     unsafe { libc::clearenv(); }
-    assert_eq!(env::vars().count(), 0);
+    assert_eq!(std::env::vars().count(), 0);
 }
 
 #[cfg(not(target_os = "linux"))]
diff --git a/tests/ui/env-vars.rs b/tests/ui/process/env-vars.rs
index 73068b5dfb8..73068b5dfb8 100644
--- a/tests/ui/env-vars.rs
+++ b/tests/ui/process/env-vars.rs
diff --git a/tests/ui/exec-env.rs b/tests/ui/process/exec-env.rs
index 9054b378f56..9054b378f56 100644
--- a/tests/ui/exec-env.rs
+++ b/tests/ui/process/exec-env.rs
diff --git a/tests/ui/inherit-env.rs b/tests/ui/process/inherit-env.rs
index 0eb61fcdd53..0eb61fcdd53 100644
--- a/tests/ui/inherit-env.rs
+++ b/tests/ui/process/inherit-env.rs
diff --git a/tests/ui/process/no-stdio.rs b/tests/ui/process/no-stdio.rs
index 05b1e52b799..8eebf6dbc7d 100644
--- a/tests/ui/process/no-stdio.rs
+++ b/tests/ui/process/no-stdio.rs
@@ -5,11 +5,13 @@
 
 #![feature(rustc_private)]
 
+#[cfg(unix)]
 extern crate libc;
 
-use std::process::{Command, Stdio};
 use std::env;
+use std::ffi::c_int;
 use std::io::{self, Read, Write};
+use std::process::{Command, Stdio};
 
 #[cfg(unix)]
 unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
@@ -36,14 +38,14 @@ unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
 }
 
 #[cfg(unix)]
-fn assert_fd_is_valid(fd: libc::c_int) {
+fn assert_fd_is_valid(fd: c_int) {
     if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } {
         panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error());
     }
 }
 
 #[cfg(windows)]
-fn assert_fd_is_valid(_fd: libc::c_int) {}
+fn assert_fd_is_valid(_fd: c_int) {}
 
 #[cfg(windows)]
 unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
diff --git a/tests/ui/impossible_range.fixed b/tests/ui/range/impossible_range.fixed
index 423dde94f4f..423dde94f4f 100644
--- a/tests/ui/impossible_range.fixed
+++ b/tests/ui/range/impossible_range.fixed
diff --git a/tests/ui/impossible_range.rs b/tests/ui/range/impossible_range.rs
index 002ea792fbf..002ea792fbf 100644
--- a/tests/ui/impossible_range.rs
+++ b/tests/ui/range/impossible_range.rs
diff --git a/tests/ui/impossible_range.stderr b/tests/ui/range/impossible_range.stderr
index 53c56065c2a..53c56065c2a 100644
--- a/tests/ui/impossible_range.stderr
+++ b/tests/ui/range/impossible_range.stderr
diff --git a/tests/ui/range_inclusive.rs b/tests/ui/range/range_inclusive.rs
index 6e77f0d7767..6e77f0d7767 100644
--- a/tests/ui/range_inclusive.rs
+++ b/tests/ui/range/range_inclusive.rs
diff --git a/tests/ui/conflicting-repr-hints.rs b/tests/ui/repr/conflicting-repr-hints.rs
index ed82b6a742c..ed82b6a742c 100644
--- a/tests/ui/conflicting-repr-hints.rs
+++ b/tests/ui/repr/conflicting-repr-hints.rs
diff --git a/tests/ui/conflicting-repr-hints.stderr b/tests/ui/repr/conflicting-repr-hints.stderr
index 4dcd8f4fc28..4dcd8f4fc28 100644
--- a/tests/ui/conflicting-repr-hints.stderr
+++ b/tests/ui/repr/conflicting-repr-hints.stderr
diff --git a/tests/ui/ret-bang.rs b/tests/ui/return/ret-bang.rs
index f0d529ad6a6..f0d529ad6a6 100644
--- a/tests/ui/ret-bang.rs
+++ b/tests/ui/return/ret-bang.rs
diff --git a/tests/ui/ret-non-nil.rs b/tests/ui/return/ret-non-nil.rs
index 1d039ffe18c..1d039ffe18c 100644
--- a/tests/ui/ret-non-nil.rs
+++ b/tests/ui/return/ret-non-nil.rs
diff --git a/tests/ui/ret-non-nil.stderr b/tests/ui/return/ret-non-nil.stderr
index 802900e61a3..802900e61a3 100644
--- a/tests/ui/ret-non-nil.stderr
+++ b/tests/ui/return/ret-non-nil.stderr
diff --git a/tests/ui/return-disjoint-regions.rs b/tests/ui/return/return-disjoint-regions.rs
index d0feb3b65e1..d0feb3b65e1 100644
--- a/tests/ui/return-disjoint-regions.rs
+++ b/tests/ui/return/return-disjoint-regions.rs
diff --git a/tests/ui/return-disjoint-regions.stderr b/tests/ui/return/return-disjoint-regions.stderr
index 7b5b032579a..7b5b032579a 100644
--- a/tests/ui/return-disjoint-regions.stderr
+++ b/tests/ui/return/return-disjoint-regions.stderr
diff --git a/tests/ui/return-nil.rs b/tests/ui/return/return-nil.rs
index 403eae260dc..403eae260dc 100644
--- a/tests/ui/return-nil.rs
+++ b/tests/ui/return/return-nil.rs
diff --git a/tests/ui/return/tail-expr-if-as-return.rs b/tests/ui/return/tail-expr-if-as-return.rs
new file mode 100644
index 00000000000..119ffccc6a9
--- /dev/null
+++ b/tests/ui/return/tail-expr-if-as-return.rs
@@ -0,0 +1,5 @@
+fn main() {
+    if true {
+        "" //~ ERROR mismatched types [E0308]
+    }
+}
diff --git a/tests/ui/return/tail-expr-if-as-return.stderr b/tests/ui/return/tail-expr-if-as-return.stderr
new file mode 100644
index 00000000000..2631f1e426d
--- /dev/null
+++ b/tests/ui/return/tail-expr-if-as-return.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/tail-expr-if-as-return.rs:3:9
+   |
+LL | /     if true {
+LL | |         ""
+   | |         ^^ expected `()`, found `&str`
+LL | |     }
+   | |_____- expected this to be `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr
deleted file mode 100644
index 284dacf7000..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: the trait bound `u8: Bar` is not satisfied
-  --> $DIR/feature-gate-do_not_recommend.rs:19:11
-   |
-LL |     stuff(1u8);
-   |     ----- ^^^ the trait `Foo` is not implemented for `u8`, which is required by `u8: Bar`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Foo` is implemented for `i32`
-note: required for `u8` to implement `Bar`
-  --> $DIR/feature-gate-do_not_recommend.rs:13:14
-   |
-LL | impl<T: Foo> Bar for T {
-   |         ---  ^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required by a bound in `stuff`
-  --> $DIR/feature-gate-do_not_recommend.rs:16:13
-   |
-LL | fn stuff<T: Bar>(_: T) {}
-   |             ^^^ required by this bound in `stuff`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs
deleted file mode 100644
index 91863f5e497..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![feature(do_not_recommend)]
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-const CONST: () = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-static Static: () = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-type Type = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-enum Enum {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-extern {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-fn fun() {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-struct Struct {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-trait Trait {
-}
-
-#[do_not_recommend]
-impl Trait for i32 {
-}
-
-fn main() {
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr
deleted file mode 100644
index 01ebc23c86e..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:3:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:7:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:11:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:15:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:20:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:25:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:30:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:35:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs
deleted file mode 100644
index f0c5c222e78..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-trait Foo {
-}
-
-#[do_not_recommend]
-//~^ ERROR the `#[do_not_recommend]` attribute is an experimental feature
-impl Foo for i32 {
-}
-
-fn main() {
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr
deleted file mode 100644
index 02bc51ccd3f..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[do_not_recommend]` attribute is an experimental feature
-  --> $DIR/unstable-feature.rs:4:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51992 <https://github.com/rust-lang/rust/issues/51992> for more information
-   = help: add `#![feature(do_not_recommend)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/runtime/on-broken-pipe/error.rs b/tests/ui/runtime/on-broken-pipe/error.rs
index ab2036c2f41..0a020873df0 100644
--- a/tests/ui/runtime/on-broken-pipe/error.rs
+++ b/tests/ui/runtime/on-broken-pipe/error.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 //@ compile-flags: -Zon-broken-pipe=error
+//@ only-unix because SIGPIPE is a unix thing
 
 fn main() {
     extern crate sigpipe_utils;
diff --git a/tests/ui/runtime/on-broken-pipe/inherit.rs b/tests/ui/runtime/on-broken-pipe/inherit.rs
index 64909b73528..f3c8140eaae 100644
--- a/tests/ui/runtime/on-broken-pipe/inherit.rs
+++ b/tests/ui/runtime/on-broken-pipe/inherit.rs
@@ -4,6 +4,7 @@
 //@ aux-bin: assert-inherit-sig_ign.rs
 //@ run-pass
 //@ compile-flags: -Zon-broken-pipe=kill
+//@ only-unix because SIGPIPE is a unix thing
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/runtime/on-broken-pipe/kill.rs b/tests/ui/runtime/on-broken-pipe/kill.rs
index 5dace6f1c6f..748e53ffcdb 100644
--- a/tests/ui/runtime/on-broken-pipe/kill.rs
+++ b/tests/ui/runtime/on-broken-pipe/kill.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 //@ compile-flags: -Zon-broken-pipe=kill
+//@ only-unix because SIGPIPE is a unix thing
 
 fn main() {
     extern crate sigpipe_utils;
diff --git a/tests/ui/runtime/on-broken-pipe/not-used.rs b/tests/ui/runtime/on-broken-pipe/not-used.rs
index e31236f2b3d..22a26047874 100644
--- a/tests/ui/runtime/on-broken-pipe/not-used.rs
+++ b/tests/ui/runtime/on-broken-pipe/not-used.rs
@@ -1,5 +1,6 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
+//@ only-unix because SIGPIPE is a unix thing
 
 fn main() {
     extern crate sigpipe_utils;
diff --git a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
index c1731200038..c40590ad87f 100644
--- a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
+++ b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 //@ compile-flags: -Zon-broken-pipe=kill
+//@ only-unix because SIGPIPE is a unix thing
 
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs
index ab2b50b293c..a62398df8b8 100644
--- a/tests/ui/runtime/out-of-stack.rs
+++ b/tests/ui/runtime/out-of-stack.rs
@@ -8,21 +8,16 @@
 //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590)
 //@ ignore-nto no stack overflow handler used (no alternate stack available)
 
-#![feature(core_intrinsics)]
 #![feature(rustc_private)]
 
 #[cfg(unix)]
 extern crate libc;
 
 use std::env;
+use std::hint::black_box;
 use std::process::Command;
 use std::thread;
 
-// Inlining to avoid llvm turning the recursive functions into tail calls,
-// which doesn't consume stack.
-#[inline(always)]
-pub fn black_box<T>(dummy: T) { std::intrinsics::black_box(dummy); }
-
 fn silent_recurse() {
     let buf = [0u8; 1000];
     black_box(buf);
diff --git a/tests/ui/runtime/stdout-during-shutdown.rs b/tests/ui/runtime/stdout-during-shutdown-unix.rs
index 8549f5d8eb6..8e0f1d371ae 100644
--- a/tests/ui/runtime/stdout-during-shutdown.rs
+++ b/tests/ui/runtime/stdout-during-shutdown-unix.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-emscripten
+//@ only-unix
 
 // Emscripten doesn't flush its own stdout buffers on exit, which would fail
 // this test. So this test is disabled on this platform.
diff --git a/tests/ui/runtime/stdout-during-shutdown.run.stdout b/tests/ui/runtime/stdout-during-shutdown-unix.run.stdout
index 30f51a3fba5..30f51a3fba5 100644
--- a/tests/ui/runtime/stdout-during-shutdown.run.stdout
+++ b/tests/ui/runtime/stdout-during-shutdown-unix.run.stdout
diff --git a/tests/ui/runtime/stdout-during-shutdown-windows.rs b/tests/ui/runtime/stdout-during-shutdown-windows.rs
new file mode 100644
index 00000000000..4644965b154
--- /dev/null
+++ b/tests/ui/runtime/stdout-during-shutdown-windows.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+//@ check-run-results
+//@ only-windows
+
+struct Bye;
+
+impl Drop for Bye {
+    fn drop(&mut self) {
+        print!(", world!");
+    }
+}
+
+fn main() {
+    thread_local!{
+        static BYE: Bye = Bye;
+    }
+    BYE.with(|_| {
+        print!("hello");
+    });
+}
diff --git a/tests/ui/runtime/stdout-during-shutdown-windows.run.stdout b/tests/ui/runtime/stdout-during-shutdown-windows.run.stdout
new file mode 100644
index 00000000000..30f51a3fba5
--- /dev/null
+++ b/tests/ui/runtime/stdout-during-shutdown-windows.run.stdout
@@ -0,0 +1 @@
+hello, world!
\ No newline at end of file
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed
new file mode 100644
index 00000000000..d49fee55a05
--- /dev/null
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed
@@ -0,0 +1,27 @@
+// See https://github.com/rust-lang/rust/issues/88475
+//@ run-rustfix
+//@ edition:2021
+//@ check-pass
+#![warn(boxed_slice_into_iter)]
+#![allow(unused)]
+
+struct FooIter;
+
+trait MyIntoIter {
+    fn into_iter(self) -> FooIter;
+}
+
+impl<T> MyIntoIter for Box<[T]> {
+    fn into_iter(self) -> FooIter {
+        FooIter
+    }
+}
+
+struct Point;
+
+pub fn main() {
+    let points: Box<[_]> = vec![Point].into_boxed_slice();
+    let y = MyIntoIter::into_iter(points);
+    //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2024
+    //~| WARNING this changes meaning in Rust 2024
+}
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs
new file mode 100644
index 00000000000..e78f550d226
--- /dev/null
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs
@@ -0,0 +1,27 @@
+// See https://github.com/rust-lang/rust/issues/88475
+//@ run-rustfix
+//@ edition:2021
+//@ check-pass
+#![warn(boxed_slice_into_iter)]
+#![allow(unused)]
+
+struct FooIter;
+
+trait MyIntoIter {
+    fn into_iter(self) -> FooIter;
+}
+
+impl<T> MyIntoIter for Box<[T]> {
+    fn into_iter(self) -> FooIter {
+        FooIter
+    }
+}
+
+struct Point;
+
+pub fn main() {
+    let points: Box<[_]> = vec![Point].into_boxed_slice();
+    let y = points.into_iter();
+    //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2024
+    //~| WARNING this changes meaning in Rust 2024
+}
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
new file mode 100644
index 00000000000..9cc79a7b129
--- /dev/null
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
@@ -0,0 +1,15 @@
+warning: trait method `into_iter` will become ambiguous in Rust 2024
+  --> $DIR/box-slice-into-iter-ambiguous.rs:24:13
+   |
+LL |     let y = points.into_iter();
+   |             ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyIntoIter::into_iter(points)`
+   |
+   = warning: this changes meaning in Rust 2024
+note: the lint level is defined here
+  --> $DIR/box-slice-into-iter-ambiguous.rs:5:9
+   |
+LL | #![warn(boxed_slice_into_iter)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rustc-env/README.md b/tests/ui/rustc-env/README.md
new file mode 100644
index 00000000000..ff674f3e6cc
--- /dev/null
+++ b/tests/ui/rustc-env/README.md
@@ -0,0 +1,6 @@
+Some environment variables affect rustc's behavior not because they are major compiler interfaces
+but rather because rustc is, ultimately, a Rust program, with debug logging, stack control, etc.
+
+Prefer to group tests that use environment variables to control something about rustc's core UX,
+like "can we parse this number of parens if we raise RUST_MIN_STACK?" with related code for that
+compiler feature.
diff --git a/tests/ui/auxiliary/rustc-rust-log-aux.rs b/tests/ui/rustc-env/auxiliary/rust-log-aux.rs
index 8080428d563..8080428d563 100644
--- a/tests/ui/auxiliary/rustc-rust-log-aux.rs
+++ b/tests/ui/rustc-env/auxiliary/rust-log-aux.rs
diff --git a/tests/ui/rustc-env/min-stack-banana.rs b/tests/ui/rustc-env/min-stack-banana.rs
new file mode 100644
index 00000000000..abbb6843710
--- /dev/null
+++ b/tests/ui/rustc-env/min-stack-banana.rs
@@ -0,0 +1,2 @@
+//@ rustc-env:RUST_MIN_STACK=banana
+fn main() {}
diff --git a/tests/ui/rustc-env/min-stack-banana.stderr b/tests/ui/rustc-env/min-stack-banana.stderr
new file mode 100644
index 00000000000..d379367ab4f
--- /dev/null
+++ b/tests/ui/rustc-env/min-stack-banana.stderr
@@ -0,0 +1,4 @@
+error: `RUST_MIN_STACK` should be a number of bytes, but was "banana"
+  |
+  = note: you can also unset `RUST_MIN_STACK` to use the default stack size
+
diff --git a/tests/ui/rustc-rust-log.rs b/tests/ui/rustc-env/rust-log.rs
index 299b6c40a56..10040754593 100644
--- a/tests/ui/rustc-rust-log.rs
+++ b/tests/ui/rustc-env/rust-log.rs
@@ -5,7 +5,7 @@
 //@ dont-check-compiler-stdout
 //@ dont-check-compiler-stderr
 //@ compile-flags: --error-format human
-//@ aux-build: rustc-rust-log-aux.rs
+//@ aux-build: rust-log-aux.rs
 //@ rustc-env:RUSTC_LOG=debug
 
 fn main() {}
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
index 1006c3bc17e..7f596a19104 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
+++ b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
@@ -2,9 +2,5 @@ error: cfi sanitizer is not supported for this target
 
 error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
 
-error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
index 1006c3bc17e..7f596a19104 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
+++ b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
@@ -2,9 +2,5 @@ error: cfi sanitizer is not supported for this target
 
 error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
 
-error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
index 0b4c0a7fece..b00260fa0ef 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
@@ -34,6 +34,11 @@ LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
    |                  |               |
    |                  |               let's call the lifetime of this reference `'1`
    |                  lifetime `'a` defined here
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn bar<'a>(self: Alias<&'a Self>, arg: &'a ()) -> &() { arg }
+   |                                   ++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
index f1a3fb0185d..784afa8b40f 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
@@ -3,17 +3,23 @@ use std::pin::Pin;
 struct Foo;
 
 impl Foo {
-    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-    //~^ lifetime may not live long enough
+    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo {
+        f //~ ERROR lifetime may not live long enough
+    }
 
-    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-    //~^ lifetime may not live long enough
+    // For this suggestion to be right, we'd need to also suggest `self: Pin<&'a Self>`, which we
+    // don't, but we provide a follow up suggestion to do so, so I condider that good at least for
+    // now.
+    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) {
+        (self, f) //~ ERROR lifetime may not live long enough
+    }
 }
 
 type Alias<T> = Pin<T>;
 impl Foo {
-    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-    //~^ lifetime may not live long enough
+    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() {
+        arg //~ ERROR lifetime may not live long enough
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
index 209dae9c1b3..57527dd31df 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
@@ -1,38 +1,47 @@
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:7:9
    |
-LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                    -         -               ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
-   |                    |         |
-   |                    |         let's call the lifetime of this reference `'1`
+LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo {
+   |                    -         - let's call the lifetime of this reference `'1`
+   |                    |
    |                    let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
-   |         ++++            ++           ++
+LL |     fn a<'a>(self: Pin<&Foo>, f: &'a Foo) -> &'a Foo {
+   |         ++++                      ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:9:69
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:9
    |
-LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                    -          -                                     ^^^^^^^^^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
-   |                    |          |
-   |                    |          let's call the lifetime of this reference `'1`
+LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) {
+   |                    -          - let's call the lifetime of this reference `'1`
+   |                    |
    |                    let's call the lifetime of this reference `'2`
+LL |         (self, f)
+   |         ^^^^^^^^^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |         ++++            ++            ++
+LL |     fn c<'a>(self: Pin<&Self>, f: &'a Foo, g: &Foo) -> (Pin<&'a Foo>, &'a Foo) {
+   |         ++++                       ++                        ++        ++
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:9
    |
-LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |            --  ---- has type `Pin<&'1 Foo>`              ^^^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() {
+   |            --  ---- has type `Pin<&'1 Foo>`
    |            |
    |            lifetime `'a` defined here
+LL |         arg
+   |         ^^^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &'a () {
+   |                                                     ++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed
new file mode 100644
index 00000000000..aa1d62012da
--- /dev/null
+++ b/tests/ui/self/elision/lt-ref-self-async.fixed
@@ -0,0 +1,47 @@
+//@ edition:2018
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct<'a> {
+    data: &'a u32,
+}
+
+impl<'a> Struct<'a> {
+    // Test using `&self` sugar:
+
+    async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&Self` explicitly:
+
+    async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self-async.rs b/tests/ui/self/elision/lt-ref-self-async.rs
index 8eb4a48a9c9..38de0fd39f0 100644
--- a/tests/ui/self/elision/lt-ref-self-async.rs
+++ b/tests/ui/self/elision/lt-ref-self-async.rs
@@ -1,10 +1,12 @@
 //@ edition:2018
-
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct<'a> { data: &'a u32 }
+struct Struct<'a> {
+    data: &'a u32,
+}
 
 impl<'a> Struct<'a> {
     // Test using `&self` sugar:
@@ -42,4 +44,4 @@ impl<'a> Struct<'a> {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self-async.stderr b/tests/ui/self/elision/lt-ref-self-async.stderr
index 29d60ed6635..b84044f7548 100644
--- a/tests/ui/self/elision/lt-ref-self-async.stderr
+++ b/tests/ui/self/elision/lt-ref-self-async.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:13:9
+  --> $DIR/lt-ref-self-async.rs:15:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+LL |     async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
    |                      ++++  ++           ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:20:9
+  --> $DIR/lt-ref-self-async.rs:22:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             -         - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+LL |     async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
    |                      ++++        ++           ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:25:9
+  --> $DIR/lt-ref-self-async.rs:27:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+LL |     async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
    |                          ++++            ++            ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:30:9
+  --> $DIR/lt-ref-self-async.rs:32:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+LL |     async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
    |                          ++++            ++            ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:35:9
+  --> $DIR/lt-ref-self-async.rs:37:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             -           - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+LL |     async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
    |                              ++++                ++             ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:40:9
+  --> $DIR/lt-ref-self-async.rs:42:9
    |
 LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                         -           - let's call the lifetime of this reference `'1`
@@ -85,7 +85,7 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+LL |     async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
    |                          ++++                ++             ++
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/self/elision/lt-ref-self.fixed b/tests/ui/self/elision/lt-ref-self.fixed
new file mode 100644
index 00000000000..1d90eacea50
--- /dev/null
+++ b/tests/ui/self/elision/lt-ref-self.fixed
@@ -0,0 +1,46 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct<'a> {
+    data: &'a u32,
+}
+
+impl<'a> Struct<'a> {
+    // Test using `&self` sugar:
+
+    fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&Self` explicitly:
+
+    fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self.rs b/tests/ui/self/elision/lt-ref-self.rs
index d37ed5acbcb..4cd97c5b729 100644
--- a/tests/ui/self/elision/lt-ref-self.rs
+++ b/tests/ui/self/elision/lt-ref-self.rs
@@ -1,8 +1,11 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct<'a> { data: &'a u32 }
+struct Struct<'a> {
+    data: &'a u32,
+}
 
 impl<'a> Struct<'a> {
     // Test using `&self` sugar:
@@ -40,4 +43,4 @@ impl<'a> Struct<'a> {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self.stderr b/tests/ui/self/elision/lt-ref-self.stderr
index 216737a2c73..5c8e0a7a742 100644
--- a/tests/ui/self/elision/lt-ref-self.stderr
+++ b/tests/ui/self/elision/lt-ref-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:11:9
+  --> $DIR/lt-ref-self.rs:14:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                ++++  ++           ++
+LL |     fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 {
+   |                ++++            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:18:9
+  --> $DIR/lt-ref-self.rs:21:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                ++++        ++           ++
+LL |     fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 {
+   |                ++++                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:23:9
+  --> $DIR/lt-ref-self.rs:26:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:28:9
+  --> $DIR/lt-ref-self.rs:31:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:33:9
+  --> $DIR/lt-ref-self.rs:36:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
+LL |     fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 {
+   |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:38:9
+  --> $DIR/lt-ref-self.rs:41:9
    |
 LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                   -           - let's call the lifetime of this reference `'1`
@@ -85,8 +85,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                    ++++                ++             ++
+LL |     fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 {
+   |                    ++++                            ++          ++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/self/elision/ref-mut-self.fixed b/tests/ui/self/elision/ref-mut-self.fixed
new file mode 100644
index 00000000000..42e8050f65e
--- /dev/null
+++ b/tests/ui/self/elision/ref-mut-self.fixed
@@ -0,0 +1,44 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct {}
+
+impl Struct {
+    // Test using `&mut self` sugar:
+
+    fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&mut Self` explicitly:
+
+    fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Self<'a>(self: Box<Box<&mut Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_ref_Self<'a>(self: Box<Pin<&mut Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-self.rs b/tests/ui/self/elision/ref-mut-self.rs
index bb82e6be748..87dab2a9ab4 100644
--- a/tests/ui/self/elision/ref-mut-self.rs
+++ b/tests/ui/self/elision/ref-mut-self.rs
@@ -1,8 +1,9 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 impl Struct {
     // Test using `&mut self` sugar:
@@ -40,4 +41,4 @@ impl Struct {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-self.stderr b/tests/ui/self/elision/ref-mut-self.stderr
index 12b64a3f6dc..620706fdbdb 100644
--- a/tests/ui/self/elision/ref-mut-self.stderr
+++ b/tests/ui/self/elision/ref-mut-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:11:9
+  --> $DIR/ref-mut-self.rs:12:9
    |
 LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
    |                 -             - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
-   |                ++++  ++               ++
+LL |     fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 {
+   |                ++++                ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:18:9
+  --> $DIR/ref-mut-self.rs:19:9
    |
 LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                       -             - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
-   |                ++++        ++               ++
+LL |     fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 {
+   |                ++++                      ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:23:9
+  --> $DIR/ref-mut-self.rs:24:9
    |
 LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                               -              - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++                ++
+LL |     fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                           ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:28:9
+  --> $DIR/ref-mut-self.rs:29:9
    |
 LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                               -              - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++                ++
+LL |     fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                           ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:33:9
+  --> $DIR/ref-mut-self.rs:34:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                       -               - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++                 ++
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&mut Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                                ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:38:9
+  --> $DIR/ref-mut-self.rs:39:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                       -               - let's call the lifetime of this reference `'1`
@@ -85,8 +85,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++                 ++
+LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&mut Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                                ++          ++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/self/elision/ref-mut-struct.fixed b/tests/ui/self/elision/ref-mut-struct.fixed
new file mode 100644
index 00000000000..f7a84d4a45c
--- /dev/null
+++ b/tests/ui/self/elision/ref-mut-struct.fixed
@@ -0,0 +1,37 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct {}
+
+impl Struct {
+    // Test using `&mut Struct` explicitly:
+
+    fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Struct<'a>(self: Box<Box<&mut Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_ref_Struct<'a>(self: Box<Pin<&mut Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-struct.rs b/tests/ui/self/elision/ref-mut-struct.rs
index ca8bd8da133..c227fa8bbfc 100644
--- a/tests/ui/self/elision/ref-mut-struct.rs
+++ b/tests/ui/self/elision/ref-mut-struct.rs
@@ -1,8 +1,9 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 impl Struct {
     // Test using `&mut Struct` explicitly:
@@ -33,4 +34,4 @@ impl Struct {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-struct.stderr b/tests/ui/self/elision/ref-mut-struct.stderr
index cde16ce8ba4..cce07f82718 100644
--- a/tests/ui/self/elision/ref-mut-struct.stderr
+++ b/tests/ui/self/elision/ref-mut-struct.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:11:9
+  --> $DIR/ref-mut-struct.rs:12:9
    |
 LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                         -               - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
-   |                  ++++        ++                 ++
+LL |     fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 {
+   |                  ++++                        ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:16:9
+  --> $DIR/ref-mut-struct.rs:17:9
    |
 LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                 -                - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++                  ++
+LL |     fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                             ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:21:9
+  --> $DIR/ref-mut-struct.rs:22:9
    |
 LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                 -                - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++                  ++
+LL |     fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                             ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:26:9
+  --> $DIR/ref-mut-struct.rs:27:9
    |
 LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
    |                                         -                 - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++                   ++
+LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&mut Struct>>, f: &'a u32) -> &'a u32 {
+   |                          ++++                                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:31:9
+  --> $DIR/ref-mut-struct.rs:32:9
    |
 LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
    |                                         -                 - let's call the lifetime of this reference `'1`
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++                   ++
+LL |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&mut Struct>>, f: &'a u32) -> &'a u32 {
+   |                          ++++                                  ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/self/elision/ref-self.fixed b/tests/ui/self/elision/ref-self.fixed
new file mode 100644
index 00000000000..8bf5a0bb223
--- /dev/null
+++ b/tests/ui/self/elision/ref-self.fixed
@@ -0,0 +1,61 @@
+//@ run-rustfix
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case, dead_code)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::pin::Pin;
+
+struct Struct {}
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        &self.0
+    }
+}
+
+impl Struct {
+    // Test using `&self` sugar:
+
+    fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&Self` explicitly:
+
+    fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-self.rs b/tests/ui/self/elision/ref-self.rs
index dd07fe1b00b..4b4b8aa5b51 100644
--- a/tests/ui/self/elision/ref-self.rs
+++ b/tests/ui/self/elision/ref-self.rs
@@ -1,17 +1,20 @@
+//@ run-rustfix
 #![feature(arbitrary_self_types)]
-#![allow(non_snake_case)]
+#![allow(non_snake_case, dead_code)]
 
 use std::marker::PhantomData;
 use std::ops::Deref;
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 struct Wrap<T, P>(T, PhantomData<P>);
 
 impl<T, P> Deref for Wrap<T, P> {
     type Target = T;
-    fn deref(&self) -> &T { &self.0 }
+    fn deref(&self) -> &T {
+        &self.0
+    }
 }
 
 impl Struct {
@@ -55,4 +58,4 @@ impl Struct {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-self.stderr b/tests/ui/self/elision/ref-self.stderr
index 35693257c99..c4ec8c55a00 100644
--- a/tests/ui/self/elision/ref-self.stderr
+++ b/tests/ui/self/elision/ref-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:21:9
+  --> $DIR/ref-self.rs:24:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                ++++  ++           ++
+LL |     fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
+   |                ++++            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:28:9
+  --> $DIR/ref-self.rs:31:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                ++++        ++           ++
+LL |     fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
+   |                ++++                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:33:9
+  --> $DIR/ref-self.rs:36:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:38:9
+  --> $DIR/ref-self.rs:41:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:43:9
+  --> $DIR/ref-self.rs:46:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:48:9
+  --> $DIR/ref-self.rs:51:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -85,11 +85,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
+LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:53:9
+  --> $DIR/ref-self.rs:56:9
    |
 LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                      -                - let's call the lifetime of this reference `'1`
@@ -100,8 +100,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
-   |                          ++++             ++                  ++
+LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
+   |                          ++++                              ++         ++
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/self/elision/ref-struct.fixed b/tests/ui/self/elision/ref-struct.fixed
new file mode 100644
index 00000000000..411f6013195
--- /dev/null
+++ b/tests/ui/self/elision/ref-struct.fixed
@@ -0,0 +1,37 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct {}
+
+impl Struct {
+    // Test using `&Struct` explicitly:
+
+    fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Struct<'a>(self: Box<Box<&Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_Struct<'a>(self: Box<Pin<&Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-struct.rs b/tests/ui/self/elision/ref-struct.rs
index 13a42cd1aed..733a175e7a1 100644
--- a/tests/ui/self/elision/ref-struct.rs
+++ b/tests/ui/self/elision/ref-struct.rs
@@ -1,8 +1,9 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 impl Struct {
     // Test using `&Struct` explicitly:
@@ -33,4 +34,4 @@ impl Struct {
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-struct.stderr b/tests/ui/self/elision/ref-struct.stderr
index a3d3cebeba9..860186c8353 100644
--- a/tests/ui/self/elision/ref-struct.stderr
+++ b/tests/ui/self/elision/ref-struct.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:11:9
+  --> $DIR/ref-struct.rs:12:9
    |
 LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                         -           - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
-   |                  ++++        ++             ++
+LL |     fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 {
+   |                  ++++                    ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:16:9
+  --> $DIR/ref-struct.rs:17:9
    |
 LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                 -            - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++              ++
+LL |     fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                         ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:21:9
+  --> $DIR/ref-struct.rs:22:9
    |
 LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                 -            - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++              ++
+LL |     fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                         ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:26:9
+  --> $DIR/ref-struct.rs:27:9
    |
 LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                         -             - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++               ++
+LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&Struct>>, f: &'a u32) -> &'a u32 {
+   |                          ++++                              ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:31:9
+  --> $DIR/ref-struct.rs:32:9
    |
 LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                     -             - let's call the lifetime of this reference `'1`
@@ -70,8 +70,8 @@ LL |         f
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                      ++++                ++               ++
+LL |     fn box_pin_Struct<'a>(self: Box<Pin<&Struct>>, f: &'a u32) -> &'a u32 {
+   |                      ++++                              ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
index 4ad98d56711..fc3087cbf75 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
@@ -30,6 +30,7 @@ extern "rust-intrinsic" {
     fn simd_bswap<T>(x: T) -> T;
     fn simd_bitreverse<T>(x: T) -> T;
     fn simd_ctlz<T>(x: T) -> T;
+    fn simd_ctpop<T>(x: T) -> T;
     fn simd_cttz<T>(x: T) -> T;
 }
 
@@ -77,7 +78,6 @@ fn main() {
         simd_cttz(x);
         simd_cttz(y);
 
-
         simd_add(0, 0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
         simd_sub(0, 0);
@@ -108,24 +108,25 @@ fn main() {
         simd_cttz(0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
-
         simd_shl(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_shr(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_and(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_or(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_xor(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_bswap(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_bitreverse(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_ctlz(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
+        simd_ctpop(z);
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_cttz(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
     }
 }
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
index db26f3417c9..6f5f86d7d37 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
@@ -83,59 +83,65 @@ LL |         simd_cttz(0);
    |         ^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:112:9
+  --> $DIR/generic-arithmetic-2.rs:111:9
    |
 LL |         simd_shl(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:114:9
+  --> $DIR/generic-arithmetic-2.rs:113:9
    |
 LL |         simd_shr(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:116:9
+  --> $DIR/generic-arithmetic-2.rs:115:9
    |
 LL |         simd_and(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:118:9
+  --> $DIR/generic-arithmetic-2.rs:117:9
    |
 LL |         simd_or(z, z);
    |         ^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:120:9
+  --> $DIR/generic-arithmetic-2.rs:119:9
    |
 LL |         simd_xor(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:122:9
+  --> $DIR/generic-arithmetic-2.rs:121:9
    |
 LL |         simd_bswap(z);
    |         ^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:124:9
+  --> $DIR/generic-arithmetic-2.rs:123:9
    |
 LL |         simd_bitreverse(z);
    |         ^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:126:9
+  --> $DIR/generic-arithmetic-2.rs:125:9
    |
 LL |         simd_ctlz(z);
    |         ^^^^^^^^^^^^
 
+error[E0511]: invalid monomorphization of `simd_ctpop` intrinsic: unsupported operation on `f32x4` with element `f32`
+  --> $DIR/generic-arithmetic-2.rs:127:9
+   |
+LL |         simd_ctpop(z);
+   |         ^^^^^^^^^^^^^
+
 error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:128:9
+  --> $DIR/generic-arithmetic-2.rs:129:9
    |
 LL |         simd_cttz(z);
    |         ^^^^^^^^^^^^
 
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
index 33143b1f7b5..60dfa627414 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
@@ -47,6 +47,7 @@ extern "rust-intrinsic" {
     fn simd_bswap<T>(x: T) -> T;
     fn simd_bitreverse<T>(x: T) -> T;
     fn simd_ctlz<T>(x: T) -> T;
+    fn simd_ctpop<T>(x: T) -> T;
     fn simd_cttz<T>(x: T) -> T;
 }
 
@@ -57,6 +58,8 @@ fn main() {
     let x2 = i32x4(2, 3, 4, 5);
     let y2 = U32::<4>([2, 3, 4, 5]);
     let z2 = f32x4(2.0, 3.0, 4.0, 5.0);
+    let x3 = i32x4(0, i32::MAX, i32::MIN, -1_i32);
+    let y3 = U32::<4>([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]);
 
     unsafe {
         all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9));
@@ -147,6 +150,13 @@ fn main() {
         all_eq!(simd_ctlz(x1), i32x4(31, 30, 30, 29));
         all_eq_!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29]));
 
+        all_eq!(simd_ctpop(x1), i32x4(1, 1, 2, 1));
+        all_eq_!(simd_ctpop(y1), U32::<4>([1, 1, 2, 1]));
+        all_eq!(simd_ctpop(x2), i32x4(1, 2, 1, 2));
+        all_eq_!(simd_ctpop(y2), U32::<4>([1, 2, 1, 2]));
+        all_eq!(simd_ctpop(x3), i32x4(0, 31, 1, 32));
+        all_eq_!(simd_ctpop(y3), U32::<4>([0, 31, 1, 32]));
+
         all_eq!(simd_cttz(x1), i32x4(0, 1, 0, 2));
         all_eq_!(simd_cttz(y1), U32::<4>([0, 1, 0, 2]));
     }
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
index 8df0613695b..99f8dbd9a6c 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
@@ -25,8 +25,8 @@ LL +     let str::as_bytes;
    |
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `str<{
-                      fn str() { let (/*ERROR*/); }
-                  }, T>::as_bytes`
+                  fn str() { let (/*ERROR*/); }
+              }, T>::as_bytes`
   --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:9
    |
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
diff --git a/tests/ui/span/multispan-import-lint.stderr b/tests/ui/span/multispan-import-lint.stderr
index 4a955d1b31f..a4ea1af237b 100644
--- a/tests/ui/span/multispan-import-lint.stderr
+++ b/tests/ui/span/multispan-import-lint.stderr
@@ -1,4 +1,4 @@
-warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd`
+warning: unused imports: `Eq`, `Ord`, `PartialEq`, and `PartialOrd`
   --> $DIR/multispan-import-lint.rs:5:16
    |
 LL | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd};
diff --git a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs b/tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs
index bcab5f238c3..bcab5f238c3 100644
--- a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs
+++ b/tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs
diff --git a/tests/ui/check-static-immutable-mut-slices.rs b/tests/ui/statics/check-immutable-mut-slices.rs
index 8f9680778aa..8f9680778aa 100644
--- a/tests/ui/check-static-immutable-mut-slices.rs
+++ b/tests/ui/statics/check-immutable-mut-slices.rs
diff --git a/tests/ui/check-static-immutable-mut-slices.stderr b/tests/ui/statics/check-immutable-mut-slices.stderr
index 402f9032b64..5cb35a7c21e 100644
--- a/tests/ui/check-static-immutable-mut-slices.stderr
+++ b/tests/ui/statics/check-immutable-mut-slices.stderr
@@ -1,5 +1,5 @@
 error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/check-static-immutable-mut-slices.rs:3:37
+  --> $DIR/check-immutable-mut-slices.rs:3:37
    |
 LL | static TEST: &'static mut [isize] = &mut [];
    |                                     ^^^^^^^
diff --git a/tests/ui/check-static-recursion-foreign.rs b/tests/ui/statics/check-recursion-foreign.rs
index 5a0ff7b5962..5a0ff7b5962 100644
--- a/tests/ui/check-static-recursion-foreign.rs
+++ b/tests/ui/statics/check-recursion-foreign.rs
diff --git a/tests/ui/check-static-values-constraints.rs b/tests/ui/statics/check-values-constraints.rs
index 005a7798895..005a7798895 100644
--- a/tests/ui/check-static-values-constraints.rs
+++ b/tests/ui/statics/check-values-constraints.rs
diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr
index fe5f2a34272..45a699f575f 100644
--- a/tests/ui/check-static-values-constraints.stderr
+++ b/tests/ui/statics/check-values-constraints.stderr
@@ -1,5 +1,5 @@
 error[E0493]: destructor of `SafeStruct` cannot be evaluated at compile-time
-  --> $DIR/check-static-values-constraints.rs:64:7
+  --> $DIR/check-values-constraints.rs:64:7
    |
 LL |       ..SafeStruct {
    |  _______^
@@ -12,7 +12,7 @@ LL |   };
    |   - value is dropped here
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:81:33
+  --> $DIR/check-values-constraints.rs:81:33
    |
 LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
    |                                 ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -20,7 +20,7 @@ LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:81:33
+  --> $DIR/check-values-constraints.rs:81:33
    |
 LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
    |                                 ^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `<str as ToString>::to_string` in statics
-  --> $DIR/check-static-values-constraints.rs:92:38
+  --> $DIR/check-values-constraints.rs:92:38
    |
 LL |     field2: SafeEnum::Variant4("str".to_string()),
    |                                      ^^^^^^^^^^^
@@ -43,7 +43,7 @@ LL + #![feature(const_trait_impl)]
    |
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:96:5
+  --> $DIR/check-values-constraints.rs:96:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -51,7 +51,7 @@ LL |     vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:96:5
+  --> $DIR/check-values-constraints.rs:96:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL |     vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:98:5
+  --> $DIR/check-values-constraints.rs:98:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -69,7 +69,7 @@ LL |     vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:98:5
+  --> $DIR/check-values-constraints.rs:98:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^
@@ -79,7 +79,7 @@ LL |     vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:103:6
+  --> $DIR/check-values-constraints.rs:103:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -87,7 +87,7 @@ LL |     &vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:103:6
+  --> $DIR/check-values-constraints.rs:103:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     &vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:105:6
+  --> $DIR/check-values-constraints.rs:105:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -105,7 +105,7 @@ LL |     &vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:105:6
+  --> $DIR/check-values-constraints.rs:105:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^
@@ -115,7 +115,7 @@ LL |     &vec![MyOwned],
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:111:31
+  --> $DIR/check-values-constraints.rs:111:31
    |
 LL | static STATIC19: Vec<isize> = vec![3];
    |                               ^^^^^^^ allocation not allowed in statics
@@ -123,7 +123,7 @@ LL | static STATIC19: Vec<isize> = vec![3];
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:111:31
+  --> $DIR/check-values-constraints.rs:111:31
    |
 LL | static STATIC19: Vec<isize> = vec![3];
    |                               ^^^^^^^
@@ -133,7 +133,7 @@ LL | static STATIC19: Vec<isize> = vec![3];
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:117:32
+  --> $DIR/check-values-constraints.rs:117:32
    |
 LL |         static x: Vec<isize> = vec![3];
    |                                ^^^^^^^ allocation not allowed in statics
@@ -141,7 +141,7 @@ LL |         static x: Vec<isize> = vec![3];
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:117:32
+  --> $DIR/check-values-constraints.rs:117:32
    |
 LL |         static x: Vec<isize> = vec![3];
    |                                ^^^^^^^
@@ -151,7 +151,7 @@ LL |         static x: Vec<isize> = vec![3];
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0507]: cannot move out of static item `x`
-  --> $DIR/check-static-values-constraints.rs:119:9
+  --> $DIR/check-values-constraints.rs:119:9
    |
 LL |         x
    |         ^ move occurs because `x` has type `Vec<isize>`, which does not implement the `Copy` trait
diff --git a/tests/ui/dont-suggest-private-trait-method.rs b/tests/ui/suggestions/dont-suggest-private-trait-method.rs
index 6e2b1abd137..6e2b1abd137 100644
--- a/tests/ui/dont-suggest-private-trait-method.rs
+++ b/tests/ui/suggestions/dont-suggest-private-trait-method.rs
diff --git a/tests/ui/dont-suggest-private-trait-method.stderr b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr
index f251ad59a58..f251ad59a58 100644
--- a/tests/ui/dont-suggest-private-trait-method.stderr
+++ b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr
diff --git a/tests/ui/suggest-null-ptr.fixed b/tests/ui/suggestions/suggest-null-ptr.fixed
index 55c90859c83..55c90859c83 100644
--- a/tests/ui/suggest-null-ptr.fixed
+++ b/tests/ui/suggestions/suggest-null-ptr.fixed
diff --git a/tests/ui/suggest-null-ptr.rs b/tests/ui/suggestions/suggest-null-ptr.rs
index f4f1269d512..f4f1269d512 100644
--- a/tests/ui/suggest-null-ptr.rs
+++ b/tests/ui/suggestions/suggest-null-ptr.rs
diff --git a/tests/ui/suggest-null-ptr.stderr b/tests/ui/suggestions/suggest-null-ptr.stderr
index 66a79d0749e..66a79d0749e 100644
--- a/tests/ui/suggest-null-ptr.stderr
+++ b/tests/ui/suggestions/suggest-null-ptr.stderr
diff --git a/tests/ui/trait-impl-bound-suggestions.fixed b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed
index 9d3168f5acd..9d3168f5acd 100644
--- a/tests/ui/trait-impl-bound-suggestions.fixed
+++ b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed
diff --git a/tests/ui/trait-impl-bound-suggestions.rs b/tests/ui/suggestions/trait-impl-bound-suggestions.rs
index 342fb4416ad..342fb4416ad 100644
--- a/tests/ui/trait-impl-bound-suggestions.rs
+++ b/tests/ui/suggestions/trait-impl-bound-suggestions.rs
diff --git a/tests/ui/trait-impl-bound-suggestions.stderr b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr
index 6a75cbdf639..6a75cbdf639 100644
--- a/tests/ui/trait-impl-bound-suggestions.stderr
+++ b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr
diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
index f882a159f98..35a06d396f2 100644
--- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
+++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
@@ -3,6 +3,7 @@
 
 fn main() -> Result<(), ()> {
     a(|| {
+        //~^ HELP: try adding a return type
         b()
         //~^ ERROR: mismatched types [E0308]
         //~| NOTE: expected `()`, found `i32`
diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
index 939285498fb..5506456afe9 100644
--- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
+++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
@@ -1,13 +1,20 @@
 error[E0308]: mismatched types
-  --> $DIR/try-operator-dont-suggest-semicolon.rs:6:9
+  --> $DIR/try-operator-dont-suggest-semicolon.rs:7:9
    |
 LL |         b()
-   |         ^^^- help: consider using a semicolon here: `;`
-   |         |
-   |         expected `()`, found `i32`
+   |         ^^^ expected `()`, found `i32`
+   |
+help: consider using a semicolon here
+   |
+LL |         b();
+   |            +
+help: try adding a return type
+   |
+LL |     a(|| -> i32 {
+   |          ++++++
 
 error[E0308]: mismatched types
-  --> $DIR/try-operator-dont-suggest-semicolon.rs:16:9
+  --> $DIR/try-operator-dont-suggest-semicolon.rs:17:9
    |
 LL | /     if true {
 LL | |
diff --git a/tests/ui/suggestions/unused-imports.stderr b/tests/ui/suggestions/unused-imports.stderr
index bf112608da7..31edb4e5ec2 100644
--- a/tests/ui/suggestions/unused-imports.stderr
+++ b/tests/ui/suggestions/unused-imports.stderr
@@ -1,4 +1,4 @@
-warning: unused imports: `A`, `C`
+warning: unused imports: `A` and `C`
   --> $DIR/unused-imports.rs:22:14
    |
 LL | use nested::{A, B, C};
@@ -10,7 +10,7 @@ note: the lint level is defined here
 LL | #![warn(unused_imports)]
    |         ^^^^^^^^^^^^^^
 
-warning: unused imports: `D`, `E`, `G`
+warning: unused imports: `D`, `E`, and `G`
   --> $DIR/unused-imports.rs:26:5
    |
 LL |     D,
diff --git a/tests/ui/tool_lints-fail.rs b/tests/ui/tool-attributes/tool_lints-fail.rs
index 5cbd63be597..5cbd63be597 100644
--- a/tests/ui/tool_lints-fail.rs
+++ b/tests/ui/tool-attributes/tool_lints-fail.rs
diff --git a/tests/ui/tool_lints-fail.stderr b/tests/ui/tool-attributes/tool_lints-fail.stderr
index 7d80e0728f7..7d80e0728f7 100644
--- a/tests/ui/tool_lints-fail.stderr
+++ b/tests/ui/tool-attributes/tool_lints-fail.stderr
diff --git a/tests/ui/tool_lints-rpass.rs b/tests/ui/tool-attributes/tool_lints-rpass.rs
index 458eca19ed6..458eca19ed6 100644
--- a/tests/ui/tool_lints-rpass.rs
+++ b/tests/ui/tool-attributes/tool_lints-rpass.rs
diff --git a/tests/ui/tool_lints.rs b/tests/ui/tool-attributes/tool_lints.rs
index ef27532f6de..ef27532f6de 100644
--- a/tests/ui/tool_lints.rs
+++ b/tests/ui/tool-attributes/tool_lints.rs
diff --git a/tests/ui/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr
index f1d825caba1..f1d825caba1 100644
--- a/tests/ui/tool_lints.stderr
+++ b/tests/ui/tool-attributes/tool_lints.stderr
diff --git a/tests/ui/tool_lints_2018_preview.rs b/tests/ui/tool-attributes/tool_lints_2018_preview.rs
index 458eca19ed6..458eca19ed6 100644
--- a/tests/ui/tool_lints_2018_preview.rs
+++ b/tests/ui/tool-attributes/tool_lints_2018_preview.rs
diff --git a/tests/ui/unknown-lint-tool-name.rs b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
index cd5d2f028af..cd5d2f028af 100644
--- a/tests/ui/unknown-lint-tool-name.rs
+++ b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
diff --git a/tests/ui/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
index 72731ab1e3d..72731ab1e3d 100644
--- a/tests/ui/unknown-lint-tool-name.stderr
+++ b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
diff --git a/tests/ui/unknown-tool-name.rs b/tests/ui/tool-attributes/unknown-tool-name.rs
index 73fca61c65d..73fca61c65d 100644
--- a/tests/ui/unknown-tool-name.rs
+++ b/tests/ui/tool-attributes/unknown-tool-name.rs
diff --git a/tests/ui/unknown-tool-name.stderr b/tests/ui/tool-attributes/unknown-tool-name.stderr
index 361d359a10e..361d359a10e 100644
--- a/tests/ui/unknown-tool-name.stderr
+++ b/tests/ui/tool-attributes/unknown-tool-name.stderr
diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr
index 4d968e7bee1..0b1f83a9de9 100644
--- a/tests/ui/traits/method-on-unbounded-type-param.stderr
+++ b/tests/ui/traits/method-on-unbounded-type-param.stderr
@@ -76,8 +76,8 @@ LL |     x.cmp(&x);
            which is required by `&mut dyn T: Iterator`
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following traits define an item `cmp`, perhaps you need to implement one of them:
-           candidate #1: `Iterator`
-           candidate #2: `Ord`
+           candidate #1: `Ord`
+   = note: the trait `Iterator` defines an item `cmp`, but is explicitly unimplemented
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
index 7eea81ce03c..920f8add507 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
@@ -1,3 +1,4 @@
+//@ revisions: with without
 //@ compile-flags: -Znext-solver
 #![feature(rustc_attrs)]
 
@@ -56,6 +57,7 @@ where
     X: IncompleteGuidance<u32, i8>,
     X: IncompleteGuidance<u32, i16>,
 {
+    #[cfg(with)]
     impls_trait::<B<X>, _, _, _>(); // entering the cycle from `B` works
 
     // entering the cycle from `A` fails, but would work if we were to use the cache
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
index ffa3f29e4bd..a81229e5e35 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
@@ -1,12 +1,12 @@
 error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
-  --> $DIR/incompleteness-unstable-result.rs:63:19
+  --> $DIR/incompleteness-unstable-result.rs:65:19
    |
 LL |     impls_trait::<A<X>, _, _, _>();
    |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
    |
    = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
 note: required for `A<X>` to implement `Trait<_, _, _>`
-  --> $DIR/incompleteness-unstable-result.rs:32:50
+  --> $DIR/incompleteness-unstable-result.rs:33:50
    |
 LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
    |                                                  ^^^^^^^^^^^^^^     ^^^^
@@ -16,7 +16,7 @@ LL |     A<T>: Trait<U, D, V>,
    = note: 8 redundant requirements hidden
    = note: required for `A<X>` to implement `Trait<_, _, _>`
 note: required by a bound in `impls_trait`
-  --> $DIR/incompleteness-unstable-result.rs:51:28
+  --> $DIR/incompleteness-unstable-result.rs:52:28
    |
 LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
    |                            ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
new file mode 100644
index 00000000000..a81229e5e35
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
@@ -0,0 +1,26 @@
+error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
+  --> $DIR/incompleteness-unstable-result.rs:65:19
+   |
+LL |     impls_trait::<A<X>, _, _, _>();
+   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
+   |
+   = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
+note: required for `A<X>` to implement `Trait<_, _, _>`
+  --> $DIR/incompleteness-unstable-result.rs:33:50
+   |
+LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
+   |                                                  ^^^^^^^^^^^^^^     ^^^^
+...
+LL |     A<T>: Trait<U, D, V>,
+   |           -------------- unsatisfied trait bound introduced here
+   = note: 8 redundant requirements hidden
+   = note: required for `A<X>` to implement `Trait<_, _, _>`
+note: required by a bound in `impls_trait`
+  --> $DIR/incompleteness-unstable-result.rs:52:28
+   |
+LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
+   |                            ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs
index 0e1d44e7bb3..75a4fbdb5d6 100644
--- a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs
+++ b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs
@@ -1,4 +1,4 @@
-// User type annotation in fn bodies is a a valid defining site for opaque types.
+// User type annotation in fn bodies is a valid defining site for opaque types.
 //@ check-pass
 #![feature(type_alias_impl_trait)]
 
diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs
index 59ba2694a76..b209b4bc89d 100644
--- a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs
+++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs
@@ -25,7 +25,7 @@ mod mod3 {
 }
 
 // This is similar to the previous cases in that 'a is equal to 'static,
-// which is is some sense an implicit parameter to `Opaque`.
+// which is some sense an implicit parameter to `Opaque`.
 // For example, given a defining use `Opaque<'a> := &'a ()`,
 // it is ambiguous whether `Opaque<'a> := &'a ()` or `Opaque<'a> := &'static ()`
 mod mod4 {
diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout
index e643dba1245..b541cbeb227 100644
--- a/tests/ui/type-alias-impl-trait/issue-60662.stdout
+++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout
@@ -10,5 +10,5 @@ extern crate std;
 trait Animal { }
 
 fn main() {
-        type ServeFut = /*impl Trait*/;
-    }
+    type ServeFut = /*impl Trait*/;
+}
diff --git a/tests/ui/typeck/issue-81943.stderr b/tests/ui/typeck/issue-81943.stderr
index 041ff10752c..f8da9ef0d18 100644
--- a/tests/ui/typeck/issue-81943.stderr
+++ b/tests/ui/typeck/issue-81943.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:7:9
    |
 LL |   f(|x| lib::d!(x));
-   |         ^^^^^^^^^^ expected `()`, found `i32`
+   |        -^^^^^^^^^^ expected `()`, found `i32`
+   |        |
+   |        help: try adding a return type: `-> i32`
    |
    = note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -10,28 +12,22 @@ error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:8:28
    |
 LL |   f(|x| match x { tmp => { g(tmp) } });
-   |         -------------------^^^^^^----
-   |         |                  |
-   |         |                  expected `()`, found `i32`
-   |         expected this to be `()`
+   |                            ^^^^^^ expected `()`, found `i32`
    |
 help: consider using a semicolon here
    |
 LL |   f(|x| match x { tmp => { g(tmp); } });
    |                                  +
-help: consider using a semicolon here
+help: try adding a return type
    |
-LL |   f(|x| match x { tmp => { g(tmp) } };);
-   |                                      +
+LL |   f(|x| -> i32 match x { tmp => { g(tmp) } });
+   |         ++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:10:38
    |
 LL |     ($e:expr) => { match $e { x => { g(x) } } }
-   |                    ------------------^^^^----
-   |                    |                 |
-   |                    |                 expected `()`, found `i32`
-   |                    expected this to be `()`
+   |                                      ^^^^ expected `()`, found `i32`
 LL |   }
 LL |   f(|x| d!(x));
    |         ----- in this macro invocation
@@ -41,10 +37,10 @@ help: consider using a semicolon here
    |
 LL |     ($e:expr) => { match $e { x => { g(x); } } }
    |                                          +
-help: consider using a semicolon here
+help: try adding a return type
    |
-LL |     ($e:expr) => { match $e { x => { g(x) } }; }
-   |                                              +
+LL |   f(|x| -> i32 d!(x));
+   |         ++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/unop-move-semantics.rs b/tests/ui/unop/unop-move-semantics.rs
index 8168da8242f..8168da8242f 100644
--- a/tests/ui/unop-move-semantics.rs
+++ b/tests/ui/unop/unop-move-semantics.rs
diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop/unop-move-semantics.stderr
index bc9b3ea9903..bc9b3ea9903 100644
--- a/tests/ui/unop-move-semantics.stderr
+++ b/tests/ui/unop/unop-move-semantics.stderr
diff --git a/tests/ui/unop-neg-bool.rs b/tests/ui/unop/unop-neg-bool.rs
index 6f1f1aba459..6f1f1aba459 100644
--- a/tests/ui/unop-neg-bool.rs
+++ b/tests/ui/unop/unop-neg-bool.rs
diff --git a/tests/ui/unop-neg-bool.stderr b/tests/ui/unop/unop-neg-bool.stderr
index 9bc5e7dcf22..9bc5e7dcf22 100644
--- a/tests/ui/unop-neg-bool.stderr
+++ b/tests/ui/unop/unop-neg-bool.stderr
diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout
index 07ecb99dccc..c5272711d6e 100644
--- a/tests/ui/unpretty/bad-literal.stdout
+++ b/tests/ui/unpretty/bad-literal.stdout
@@ -7,5 +7,5 @@ extern crate std;
 
 // In #100948 this caused an ICE with -Zunpretty=hir.
 fn main() {
-        <bad-literal>;
-    }
+    <bad-literal>;
+}
diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout
index 0fd51edea24..e3b9b9ac207 100644
--- a/tests/ui/unpretty/box.stdout
+++ b/tests/ui/unpretty/box.stdout
@@ -8,7 +8,7 @@ use ::std::prelude::rust_2015::*;
 extern crate std;
 
 fn main() {
-        let _ =
-            #[rustc_box]
-            Box::new(1);
-    }
+    let _ =
+        #[rustc_box]
+        Box::new(1);
+}
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
index 275fa104e66..2de1cdd96b5 100644
--- a/tests/ui/unpretty/flattened-format-args.stdout
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -6,10 +6,10 @@ extern crate std;
 //@ check-pass
 
 fn main() {
-        let x = 1;
-        // Should flatten to println!("a 123 b {x} xyz\n"):
-        {
-                ::std::io::_print(format_arguments::new_v1(&["a 123 b ",
-                                    " xyz\n"], &[format_argument::new_display(&x)]));
-            };
-    }
+    let x = 1;
+    // Should flatten to println!("a 123 b {x} xyz\n"):
+    {
+        ::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"],
+                &[format_argument::new_display(&x)]));
+    };
+}
diff --git a/tests/ui/unpretty/let-else-hir.stdout b/tests/ui/unpretty/let-else-hir.stdout
index ed55f293876..a2ffa5de567 100644
--- a/tests/ui/unpretty/let-else-hir.stdout
+++ b/tests/ui/unpretty/let-else-hir.stdout
@@ -9,10 +9,10 @@ extern crate std;
 
 fn foo(x:
         Option<u32>) {
-        let Some(_) = x else
-            {
+    let Some(_) = x else
+        {
 
-            { ::std::rt::begin_panic("explicit panic") }
-        };
-    }
+        { ::std::rt::begin_panic("explicit panic") }
+    };
+}
 fn main() { }
diff --git a/tests/ui/use/use-nested-groups-unused-imports.rs b/tests/ui/use/use-nested-groups-unused-imports.rs
index ca6b8ba94d1..0c8ae558a59 100644
--- a/tests/ui/use/use-nested-groups-unused-imports.rs
+++ b/tests/ui/use/use-nested-groups-unused-imports.rs
@@ -13,7 +13,7 @@ mod foo {
 }
 
 use foo::{Foo, bar::{baz::{}, foobar::*}, *};
-    //~^ ERROR unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
+    //~^ ERROR unused imports: `*`, `Foo`, `baz::{}`, and `foobar::*`
 use foo::bar::baz::{*, *};
     //~^ ERROR unused import: `*`
 use foo::{};
diff --git a/tests/ui/use/use-nested-groups-unused-imports.stderr b/tests/ui/use/use-nested-groups-unused-imports.stderr
index 6610f8ecd4a..dd39a852772 100644
--- a/tests/ui/use/use-nested-groups-unused-imports.stderr
+++ b/tests/ui/use/use-nested-groups-unused-imports.stderr
@@ -1,4 +1,4 @@
-error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
+error: unused imports: `*`, `Foo`, `baz::{}`, and `foobar::*`
   --> $DIR/use-nested-groups-unused-imports.rs:15:11
    |
 LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *};
diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs
index 3d052cc193c..dd6a7fa0e65 100644
--- a/tests/ui/wait-forked-but-failed-child.rs
+++ b/tests/ui/wait-forked-but-failed-child.rs
@@ -7,8 +7,6 @@
 
 #![feature(rustc_private)]
 
-extern crate libc;
-
 use std::process::Command;
 
 // The output from "ps -A -o pid,ppid,args" should look like this:
@@ -28,6 +26,7 @@ use std::process::Command;
 
 #[cfg(unix)]
 fn find_zombies() {
+    extern crate libc;
     let my_pid = unsafe { libc::getpid() };
 
     // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html