about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs3
-rw-r--r--Cargo.lock5
-rw-r--r--compiler/rustc_ast/src/token.rs38
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs108
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs2
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl6
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs20
-rw-r--r--compiler/rustc_data_structures/src/sync.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs14
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs4
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs40
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs13
-rw-r--r--compiler/rustc_expand/src/tokenstream/tests.rs5
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs5
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/lib.rs5
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs52
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs4
-rw-r--r--compiler/rustc_middle/src/ty/list.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs369
-rw-r--r--compiler/rustc_mir_build/src/errors.rs14
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs15
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs4
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs29
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs8
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs56
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs50
-rw-r--r--compiler/rustc_parse/src/parser/item.rs36
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs64
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs18
-rw-r--r--compiler/rustc_parse/src/parser/path.rs3
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs8
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/ident.rs24
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/base/apple/tests.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs56
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs2
-rw-r--r--library/alloc/src/boxed/thin.rs2
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/rc.rs4
-rw-r--r--library/alloc/src/sync.rs4
-rw-r--r--library/core/src/ffi/c_str.rs3
-rw-r--r--library/core/src/intrinsics.rs18
-rw-r--r--library/core/src/iter/adapters/filter_map.rs6
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ptr/mod.rs2
-rw-r--r--library/core/src/slice/mod.rs11
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--library/std/src/os/unix/net/addr.rs4
-rw-r--r--library/std/src/os/unix/net/ancillary.rs4
-rw-r--r--library/std/src/os/unix/net/datagram.rs12
-rw-r--r--library/std/src/os/unix/net/listener.rs10
-rw-r--r--library/std/src/os/unix/net/stream.rs4
-rw-r--r--library/std/src/os/unix/ucred.rs4
-rw-r--r--library/std/src/panicking.rs2
-rw-r--r--library/std/src/sync/mod.rs4
-rw-r--r--library/std/src/sync/mpmc/zero.rs8
-rw-r--r--library/std/src/sync/mutex.rs219
-rw-r--r--library/std/src/sync/mutex/tests.rs91
-rw-r--r--library/std/src/sync/poison.rs1
-rw-r--r--library/std/src/sync/rwlock.rs433
-rw-r--r--library/std/src/sync/rwlock/tests.rs241
-rw-r--r--library/std/src/sys/pal/hermit/net.rs4
-rw-r--r--library/std/src/sys/pal/hermit/time.rs4
-rw-r--r--library/std/src/sys/pal/sgx/abi/tls/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/fs.rs6
-rw-r--r--library/std/src/sys/pal/unix/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/net.rs2
-rw-r--r--library/std/src/sys/pal/unix/process/process_fuchsia.rs4
-rw-r--r--library/std/src/sys/pal/unix/process/process_unix.rs12
-rw-r--r--library/std/src/sys/pal/unix/thread.rs8
-rw-r--r--library/std/src/sys/pal/unix/thread_local_dtor.rs2
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs2
-rw-r--r--library/std/src/sys/pal/windows/fs.rs8
-rw-r--r--library/std/src/sys/pal/windows/io.rs2
-rw-r--r--library/std/src/sys/pal/windows/net.rs2
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs2
-rw-r--r--library/std/src/sys/pal/windows/process.rs6
-rw-r--r--library/std/src/sys/pal/windows/rand.rs4
-rw-r--r--library/std/src/sys/pal/windows/thread_parking.rs2
-rw-r--r--library/std/src/sys_common/net.rs8
-rw-r--r--library/std/src/sys_common/once/queue.rs2
-rw-r--r--library/std/src/thread/scoped.rs2
m---------library/stdarch0
-rw-r--r--library/unwind/src/lib.rs2
-rw-r--r--library/unwind/src/libunwind.rs4
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/tarball.rs19
-rw-r--r--src/librustdoc/clean/render_macro_matchers.rs4
-rw-r--r--src/librustdoc/html/format.rs9
-rw-r--r--src/tools/compiletest/src/runtest.rs7
-rw-r--r--src/tools/miri/Cargo.lock244
-rw-r--r--src/tools/miri/README.md4
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock176
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs23
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs9
-rw-r--r--src/tools/miri/cargo-miri/src/util.rs64
-rw-r--r--src/tools/miri/miri-script/Cargo.lock100
-rw-r--r--src/tools/miri/miri.bat10
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs10
-rw-r--r--src/tools/miri/tests/compiletest.rs17
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-extract.rs8
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-extract.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs (renamed from src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond.rs)0
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs (renamed from src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs)0
-rw-r--r--src/tools/miri/tests/pass-dep/shims/mmap.rs5
-rw-r--r--src/tools/miri/tests/pass-dep/shims/pthread-sync.rs56
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync.rs6
-rw-r--r--src/tools/miri/tests/pass/overflow_checks_off.rs3
-rw-r--r--src/tools/miri/tests/pass/portable-simd.rs14
-rw-r--r--src/tools/miri/tests/pass/shims/windows-rand.rs41
-rw-r--r--src/tools/miri/tests/pass/slices.rs3
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml5
-rw-r--r--src/tools/rust-analyzer/.github/workflows/metrics.yaml9
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml6
-rw-r--r--src/tools/rust-analyzer/Cargo.lock1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs292
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs117
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs55
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs92
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs47
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs158
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs46
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs131
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/join_lines.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs123
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs4
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs15
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs7
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs9
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs47
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs47
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs11
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs26
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs11
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs96
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs93
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs20
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs13
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs51
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/derived.rs28
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs124
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/durability.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/input.rs53
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/interned.rs16
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lib.rs19
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lru.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/plumbing.rs15
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/revision.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/runtime.rs52
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs2
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs7
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts66
-rw-r--r--src/tools/rust-analyzer/editors/code/src/snippets.ts144
-rw-r--r--src/tools/rust-analyzer/xtask/src/metrics.rs6
-rw-r--r--src/tools/rust-installer/src/compression.rs11
-rw-r--r--src/tools/rust-installer/src/main.rs2
-rw-r--r--src/tools/rust-installer/src/tarballer.rs4
-rw-r--r--tests/assembly/option-nonzero-eq.rs1
-rw-r--r--tests/assembly/slice-is_ascii.rs1
-rw-r--r--tests/assembly/static-relocation-model.rs1
-rw-r--r--tests/codegen/align-offset.rs1
-rw-r--r--tests/codegen/array-map.rs1
-rw-r--r--tests/codegen/ascii-char.rs1
-rw-r--r--tests/codegen/binary-search-index-no-bound-check.rs1
-rw-r--r--tests/codegen/constant-branch.rs67
-rw-r--r--tests/codegen/infallible-unwrap-in-opt-z.rs1
-rw-r--r--tests/codegen/issue-97217.rs1
-rw-r--r--tests/codegen/issues/issue-101082.rs1
-rw-r--r--tests/codegen/issues/issue-101814.rs1
-rw-r--r--tests/codegen/issues/issue-106369.rs1
-rw-r--r--tests/codegen/issues/issue-116878.rs1
-rw-r--r--tests/codegen/issues/issue-37945.rs1
-rw-r--r--tests/codegen/issues/issue-45222.rs1
-rw-r--r--tests/codegen/issues/issue-45466.rs1
-rw-r--r--tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs1
-rw-r--r--tests/codegen/issues/issue-69101-bounds-check.rs1
-rw-r--r--tests/codegen/issues/issue-73258.rs1
-rw-r--r--tests/codegen/issues/issue-73396-bounds-check-after-position.rs1
-rw-r--r--tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs1
-rw-r--r--tests/codegen/iter-repeat-n-trivial-drop.rs1
-rw-r--r--tests/codegen/layout-size-checks.rs1
-rw-r--r--tests/codegen/lib-optimizations/iter-sum.rs1
-rw-r--r--tests/codegen/mem-replace-big-type.rs2
-rw-r--r--tests/codegen/mem-replace-simple-type.rs2
-rw-r--r--tests/codegen/ptr-arithmetic.rs1
-rw-r--r--tests/codegen/ptr-read-metadata.rs1
-rw-r--r--tests/codegen/simd/simd-wide-sum.rs1
-rw-r--r--tests/codegen/simd/swap-simd-types.rs1
-rw-r--r--tests/codegen/slice-as_chunks.rs1
-rw-r--r--tests/codegen/slice-indexing.rs1
-rw-r--r--tests/codegen/slice-iter-fold.rs1
-rw-r--r--tests/codegen/slice-iter-len-eq-zero.rs1
-rw-r--r--tests/codegen/slice-iter-nonnull.rs1
-rw-r--r--tests/codegen/slice-ref-equality.rs1
-rw-r--r--tests/codegen/slice-reverse.rs2
-rw-r--r--tests/codegen/slice_as_from_ptr_range.rs1
-rw-r--r--tests/codegen/swap-large-types.rs1
-rw-r--r--tests/codegen/swap-small-types.rs1
-rw-r--r--tests/codegen/transmute-optimized.rs1
-rw-r--r--tests/codegen/unchecked_shifts.rs1
-rw-r--r--tests/codegen/unwind-landingpad-inline.rs1
-rw-r--r--tests/codegen/vec-calloc.rs1
-rw-r--r--tests/codegen/vec-in-place.rs2
-rw-r--r--tests/codegen/vec-iter-collect-len.rs1
-rw-r--r--tests/codegen/vec-iter.rs1
-rw-r--r--tests/codegen/vec-optimizes-away.rs1
-rw-r--r--tests/codegen/vec-reserve-extend.rs2
-rw-r--r--tests/codegen/vec-shrink-panik.rs2
-rw-r--r--tests/codegen/vec_pop_push_noop.rs2
-rw-r--r--tests/codegen/vecdeque-drain.rs2
-rw-r--r--tests/codegen/vecdeque-nonempty-get-no-panic.rs1
-rw-r--r--tests/codegen/vecdeque_no_panic.rs2
-rw-r--r--tests/codegen/virtual-function-elimination.rs1
-rw-r--r--tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff19
-rw-r--r--tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff19
-rw-r--r--tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir14
-rw-r--r--tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir14
-rw-r--r--tests/mir-opt/inline/rustc_no_mir_inline.rs17
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.rs1
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir2
-rw-r--r--tests/ui/cfg/cfg-target-abi.rs1
-rw-r--r--tests/ui/check-cfg/well-known-values.rs1
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr56
-rw-r--r--tests/ui/consts/const_in_pattern/issue-65466.rs7
-rw-r--r--tests/ui/consts/const_in_pattern/issue-65466.stderr21
-rw-r--r--tests/ui/consts/promote-not.rs4
-rw-r--r--tests/ui/consts/promote-not.stderr64
-rw-r--r--tests/ui/consts/promotion.rs5
-rw-r--r--tests/ui/feature-gates/feature-gate-cfg-target-abi.rs13
-rw-r--r--tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr43
-rw-r--r--tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs16
-rw-r--r--tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr12
-rw-r--r--tests/ui/lint/lint-overflowing-ops.noopt.stderr263
-rw-r--r--tests/ui/lint/lint-overflowing-ops.opt.stderr359
-rw-r--r--tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr263
-rw-r--r--tests/ui/lint/lint-overflowing-ops.rs12
-rw-r--r--tests/ui/match/issue-72896-non-partial-eq-const.rs4
-rw-r--r--tests/ui/match/issue-72896-non-partial-eq-const.stderr21
-rw-r--r--tests/ui/simd/not-out-of-bounds.rs (renamed from tests/ui/simd/shuffle-not-out-of-bounds.rs)15
-rw-r--r--tests/ui/simd/not-out-of-bounds.stderr (renamed from tests/ui/simd/shuffle-not-out-of-bounds.stderr)42
324 files changed, 4670 insertions, 2581 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index d23682596fd..663ace48e9e 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -20,3 +20,6 @@ f97fddab91fbf290ea5b691fe355d6f915220b6e
 cc907f80b95c6ec530c5ee1b05b044a468f07eca
 # format let-chains
 b2d2184edea578109a48ec3d8decbee5948e8f35
+# test directives migration
+6e48b96692d63a79a14563f27fe5185f122434f8
+ec2cc761bc7067712ecc7734502f703fe3b024c8
diff --git a/Cargo.lock b/Cargo.lock
index 5b19c4a721e..8518bb2a91f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3308,13 +3308,14 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544"
+checksum = "a26170e1d79ea32f7ccec3188dd13cfc1f18c82764a9cbc1071667c0f865a4ea"
 dependencies = [
  "anyhow",
  "rustc_version",
  "tempfile",
+ "walkdir",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 50fe37dcdb6..5ccc7d51066 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -107,7 +107,7 @@ impl Lit {
     /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
     pub fn from_token(token: &Token) -> Option<Lit> {
         match token.uninterpolate().kind {
-            Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
+            Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
             Literal(token_lit) => Some(token_lit),
             Interpolated(ref nt)
                 if let NtExpr(expr) | NtLiteral(expr) = &nt.0
@@ -183,7 +183,7 @@ impl LitKind {
     }
 }
 
-pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
+pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
     let ident_token = Token::new(Ident(name, is_raw), span);
 
     !ident_token.is_reserved_ident()
@@ -214,7 +214,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
         .contains(&name)
 }
 
-fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
+fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
     let ident_token = Token::new(Ident(name, is_raw), span);
 
     !ident_token.is_reserved_ident()
@@ -223,6 +223,24 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
             .contains(&name)
 }
 
+#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
+pub enum IdentIsRaw {
+    No,
+    Yes,
+}
+
+impl From<bool> for IdentIsRaw {
+    fn from(b: bool) -> Self {
+        if b { Self::Yes } else { Self::No }
+    }
+}
+
+impl From<IdentIsRaw> for bool {
+    fn from(is_raw: IdentIsRaw) -> bool {
+        matches!(is_raw, IdentIsRaw::Yes)
+    }
+}
+
 // SAFETY: due to the `Clone` impl below, all fields of all variants other than
 // `Interpolated` must impl `Copy`.
 #[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -298,7 +316,7 @@ pub enum TokenKind {
     /// Do not forget about `NtIdent` when you want to match on identifiers.
     /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
     /// treat regular and interpolated identifiers in the same way.
-    Ident(Symbol, /* is_raw */ bool),
+    Ident(Symbol, IdentIsRaw),
     /// Lifetime identifier token.
     /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
     /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
@@ -411,7 +429,7 @@ impl Token {
 
     /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
     pub fn from_ast_ident(ident: Ident) -> Self {
-        Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
+        Token::new(Ident(ident.name, ident.is_raw_guess().into()), ident.span)
     }
 
     /// For interpolated tokens, returns a span of the fragment to which the interpolated
@@ -567,7 +585,7 @@ impl Token {
     pub fn can_begin_literal_maybe_minus(&self) -> bool {
         match self.uninterpolate().kind {
             Literal(..) | BinOp(Minus) => true,
-            Ident(name, false) if name.is_bool_lit() => true,
+            Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
             Interpolated(ref nt) => match &nt.0 {
                 NtLiteral(_) => true,
                 NtExpr(e) => match &e.kind {
@@ -602,7 +620,7 @@ impl Token {
 
     /// Returns an identifier if this token is an identifier.
     #[inline]
-    pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
+    pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
         // We avoid using `Token::uninterpolate` here because it's slow.
         match &self.kind {
             &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
@@ -755,7 +773,7 @@ impl Token {
     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
         match self.ident() {
-            Some((id, false)) => pred(id),
+            Some((id, IdentIsRaw::No)) => pred(id),
             _ => false,
         }
     }
@@ -806,7 +824,7 @@ impl Token {
                 _ => return None,
             },
             SingleQuote => match joint.kind {
-                Ident(name, false) => Lifetime(Symbol::intern(&format!("'{name}"))),
+                Ident(name, IdentIsRaw::No) => Lifetime(Symbol::intern(&format!("'{name}"))),
                 _ => return None,
             },
 
@@ -836,7 +854,7 @@ pub enum Nonterminal {
     NtPat(P<ast::Pat>),
     NtExpr(P<ast::Expr>),
     NtTy(P<ast::Ty>),
-    NtIdent(Ident, /* is_raw */ bool),
+    NtIdent(Ident, IdentIsRaw),
     NtLifetime(Ident),
     NtLiteral(P<ast::Expr>),
     /// Stuff inside brackets for attributes
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 298c01a4567..adc3056cc29 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -656,7 +656,7 @@ impl TokenStream {
                 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
                 Delimiter::Bracket,
                 [
-                    TokenTree::token_alone(token::Ident(sym::doc, false), span),
+                    TokenTree::token_alone(token::Ident(sym::doc, token::IdentIsRaw::No), span),
                     TokenTree::token_alone(token::Eq, span),
                     TokenTree::token_alone(
                         TokenKind::lit(token::StrRaw(num_of_hashes), data, None),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 7ea0078ea3b..6e1974f48b2 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -185,7 +185,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
 
         // IDENT + `!`: `println!()`, but `if !x { ... }` needs a space after the `if`
         (Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _))
-            if !Ident::new(*sym, *span).is_reserved() || *is_raw =>
+            if !Ident::new(*sym, *span).is_reserved() || matches!(is_raw, IdentIsRaw::Yes) =>
         {
             false
         }
@@ -197,7 +197,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
                 || *sym == kw::Fn
                 || *sym == kw::SelfUpper
                 || *sym == kw::Pub
-                || *is_raw =>
+                || matches!(is_raw, IdentIsRaw::Yes) =>
         {
             false
         }
@@ -731,7 +731,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             token::NtBlock(e) => self.block_to_string(e),
             token::NtStmt(e) => self.stmt_to_string(e),
             token::NtPat(e) => self.pat_to_string(e),
-            token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(),
+            &token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
             token::NtLifetime(e) => e.to_string(),
             token::NtLiteral(e) => self.expr_to_string(e),
             token::NtVis(e) => self.vis_to_string(e),
@@ -795,7 +795,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
 
             /* Name components */
             token::Ident(s, is_raw) => {
-                IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into()
+                IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
             }
             token::Lifetime(s) => s.to_string().into(),
 
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index c5a73c31995..263081ea19e 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,3 +1,4 @@
+use ast::token::IdentIsRaw;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
@@ -416,7 +417,7 @@ fn parse_reg<'a>(
 ) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
     p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
     let result = match p.token.uninterpolate().kind {
-        token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name),
+        token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name),
         token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
             *explicit_reg = true;
             ast::InlineAsmRegOrRegClass::Reg(symbol)
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index d244897f8a5..01821ee833f 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -1,7 +1,6 @@
 use rustc_ast::{
     ptr::P,
-    token,
-    token::Delimiter,
+    token::{self, Delimiter, IdentIsRaw},
     tokenstream::{DelimSpan, TokenStream, TokenTree},
     BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability,
     Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
@@ -170,7 +169,10 @@ impl<'cx, 'a> Context<'cx, 'a> {
         ];
         let captures = self.capture_decls.iter().flat_map(|cap| {
             [
-                TokenTree::token_joint_hidden(token::Ident(cap.ident.name, false), cap.ident.span),
+                TokenTree::token_joint_hidden(
+                    token::Ident(cap.ident.name, IdentIsRaw::No),
+                    cap.ident.span,
+                ),
                 TokenTree::token_alone(token::Comma, self.span),
             ]
         });
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 97d6b82de98..bf4693cd541 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -198,7 +198,7 @@ where
     match fields {
         Unnamed(fields, is_tuple) => {
             let path_expr = cx.expr_path(outer_pat_path);
-            if !*is_tuple {
+            if matches!(is_tuple, IsTuple::No) {
                 path_expr
             } else {
                 let fields = fields
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index d5a42566e19..0bd2d423a29 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -62,8 +62,8 @@ fn default_struct_substructure(
     let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new());
 
     let expr = match summary {
-        Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident),
-        Unnamed(fields, true) => {
+        Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident),
+        Unnamed(fields, IsTuple::Yes) => {
             let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
             cx.expr_call_ident(trait_span, substr.type_ident, exprs)
         }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6eeb028728c..3ee4fded749 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -286,10 +286,16 @@ pub struct FieldInfo {
     pub other_selflike_exprs: Vec<P<Expr>>,
 }
 
+#[derive(Copy, Clone)]
+pub enum IsTuple {
+    No,
+    Yes,
+}
+
 /// Fields for a static method
 pub enum StaticFields {
     /// Tuple and unit structs/enum variants like this.
-    Unnamed(Vec<Span>, bool /*is tuple*/),
+    Unnamed(Vec<Span>, IsTuple),
     /// Normal structs/struct variants.
     Named(Vec<(Ident, Span)>),
 }
@@ -1439,7 +1445,10 @@ impl<'a> TraitDef<'a> {
             }
         }
 
-        let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
+        let is_tuple = match struct_def {
+            ast::VariantData::Tuple(..) => IsTuple::Yes,
+            _ => IsTuple::No,
+        };
         match (just_spans.is_empty(), named_idents.is_empty()) {
             (false, false) => cx
                 .dcx()
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index b66f7111ff0..3366378d38d 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -10,6 +10,7 @@ use rustc_ast::{
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
 use rustc_expand::base::{self, *};
+use rustc_parse::parser::Recovered;
 use rustc_parse_format as parse;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, Span};
@@ -111,9 +112,8 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
                         _ => return Err(err),
                     }
                 }
-                Ok(recovered) => {
-                    assert!(recovered);
-                }
+                Ok(Recovered::Yes) => (),
+                Ok(Recovered::No) => unreachable!(),
             }
         }
         first = false;
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 67bc86e4c90..b6bbc81732e 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -313,7 +313,7 @@ fn get_llvm_object_symbols(
             llvm::LLVMRustGetSymbols(
                 buf.as_ptr(),
                 buf.len(),
-                &mut *state as *mut &mut _ as *mut c_void,
+                std::ptr::addr_of_mut!(*state) as *mut c_void,
                 callback,
                 error_callback,
             )
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 23e6f054a7c..58c0765d814 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1079,7 +1079,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             .map(|(arg_idx, val)| {
                 let idx = val.unwrap_leaf().try_to_i32().unwrap();
                 if idx >= i32::try_from(total_len).unwrap() {
-                    bx.sess().dcx().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
+                    bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
                         span,
                         name,
                         arg_idx: arg_idx as u64,
@@ -1138,24 +1138,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let val = bx.const_get_elt(vector, i as u64);
                 match bx.const_to_opt_u128(val, true) {
                     None => {
-                        bx.sess().dcx().emit_err(
-                            InvalidMonomorphization::ShuffleIndexNotConstant {
-                                span,
-                                name,
-                                arg_idx,
-                            },
-                        );
-                        None
+                        bug!("typeck should have already ensured that these are const")
                     }
                     Some(idx) if idx >= total_len => {
-                        bx.sess().dcx().emit_err(
-                            InvalidMonomorphization::ShuffleIndexOutOfBounds {
-                                span,
-                                name,
-                                arg_idx,
-                                total_len,
-                            },
-                        );
+                        bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
+                            span,
+                            name,
+                            arg_idx,
+                            total_len,
+                        });
                         None
                     }
                     Some(idx) => Some(bx.const_i32(idx as i32)),
@@ -1184,10 +1175,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 out_ty: arg_tys[2]
             }
         );
+        let idx = bx
+            .const_to_opt_u128(args[1].immediate(), false)
+            .expect("typeck should have ensure that this is a const");
+        if idx >= in_len.into() {
+            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
+                span,
+                name,
+                arg_idx: 1,
+                total_len: in_len.into(),
+            });
+            return Ok(bx.const_null(llret_ty));
+        }
         return Ok(bx.insert_element(
             args[0].immediate(),
             args[2].immediate(),
-            args[1].immediate(),
+            bx.const_i32(idx as i32),
         ));
     }
     if name == sym::simd_extract {
@@ -1195,7 +1198,19 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             ret_ty == in_elem,
             InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
         );
-        return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
+        let idx = bx
+            .const_to_opt_u128(args[1].immediate(), false)
+            .expect("typeck should have ensure that this is a const");
+        if idx >= in_len.into() {
+            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
+                span,
+                name,
+                arg_idx: 1,
+                total_len: in_len.into(),
+            });
+            return Ok(bx.const_null(llret_ty));
+        }
+        return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32)));
     }
 
     if name == sym::simd_select {
@@ -2091,9 +2106,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             return Ok(args[0].immediate());
         }
 
+        #[derive(Copy, Clone)]
+        enum Sign {
+            Unsigned,
+            Signed,
+        }
+        use Sign::*;
+
         enum Style {
             Float,
-            Int(/* is signed? */ bool),
+            Int(Sign),
             Unsupported,
         }
 
@@ -2101,11 +2123,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             // vectors of pointer-sized integers should've been
             // disallowed before here, so this unwrap is safe.
             ty::Int(i) => (
-                Style::Int(true),
+                Style::Int(Signed),
                 i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
             ),
             ty::Uint(u) => (
-                Style::Int(false),
+                Style::Int(Unsigned),
                 u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
             ),
             ty::Float(f) => (Style::Float, f.bit_width()),
@@ -2113,11 +2135,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         };
         let (out_style, out_width) = match out_elem.kind() {
             ty::Int(i) => (
-                Style::Int(true),
+                Style::Int(Signed),
                 i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
             ),
             ty::Uint(u) => (
-                Style::Int(false),
+                Style::Int(Unsigned),
                 u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
             ),
             ty::Float(f) => (Style::Float, f.bit_width()),
@@ -2125,31 +2147,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         };
 
         match (in_style, out_style) {
-            (Style::Int(in_is_signed), Style::Int(_)) => {
+            (Style::Int(sign), Style::Int(_)) => {
                 return Ok(match in_width.cmp(&out_width) {
                     Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
                     Ordering::Equal => args[0].immediate(),
-                    Ordering::Less => {
-                        if in_is_signed {
-                            bx.sext(args[0].immediate(), llret_ty)
-                        } else {
-                            bx.zext(args[0].immediate(), llret_ty)
-                        }
-                    }
+                    Ordering::Less => match sign {
+                        Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
+                        Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
+                    },
                 });
             }
-            (Style::Int(in_is_signed), Style::Float) => {
-                return Ok(if in_is_signed {
-                    bx.sitofp(args[0].immediate(), llret_ty)
-                } else {
-                    bx.uitofp(args[0].immediate(), llret_ty)
-                });
+            (Style::Int(Sign::Signed), Style::Float) => {
+                return Ok(bx.sitofp(args[0].immediate(), llret_ty));
             }
-            (Style::Float, Style::Int(out_is_signed)) => {
-                return Ok(match (out_is_signed, name == sym::simd_as) {
-                    (false, false) => bx.fptoui(args[0].immediate(), llret_ty),
-                    (true, false) => bx.fptosi(args[0].immediate(), llret_ty),
-                    (_, true) => bx.cast_float_to_int(out_is_signed, args[0].immediate(), llret_ty),
+            (Style::Int(Sign::Unsigned), Style::Float) => {
+                return Ok(bx.uitofp(args[0].immediate(), llret_ty));
+            }
+            (Style::Float, Style::Int(sign)) => {
+                return Ok(match (sign, name == sym::simd_as) {
+                    (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
+                    (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
+                    (_, true) => bx.cast_float_to_int(
+                        matches!(sign, Sign::Signed),
+                        args[0].immediate(),
+                        llret_ty,
+                    ),
                 });
             }
             (Style::Float, Style::Float) => {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 35210b0b2e8..c84461e53eb 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -169,7 +169,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     fn print_pass_timings(&self) {
         unsafe {
             let mut size = 0;
-            let cstr = llvm::LLVMRustPrintPassTimings(&mut size as *mut usize);
+            let cstr = llvm::LLVMRustPrintPassTimings(std::ptr::addr_of_mut!(size));
             if cstr.is_null() {
                 println!("failed to get pass timings");
             } else {
@@ -182,7 +182,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     fn print_statistics(&self) {
         unsafe {
             let mut size = 0;
-            let cstr = llvm::LLVMRustPrintStatistics(&mut size as *mut usize);
+            let cstr = llvm::LLVMRustPrintStatistics(std::ptr::addr_of_mut!(size));
             if cstr.is_null() {
                 println!("failed to get pass stats");
             } else {
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 54e8ed85e32..1b2beac56a2 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -435,7 +435,7 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess
                     &tm,
                     cpu_cstring.as_ptr(),
                     callback,
-                    &mut out as *mut &mut dyn PrintBackendInfo as *mut c_void,
+                    std::ptr::addr_of_mut!(out) as *mut c_void,
                 );
             }
         }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index fa7719d8971..5ba66d1be43 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -106,14 +106,12 @@ codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `
 
 codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
 
-codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
-
-codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
-
 codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
 
 codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
 
+codegen_ssa_invalid_monomorphization_simd_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: SIMD index #{$arg_idx} is out of bounds (limit {$total_len})
+
 codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
 
 codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index e42a8bd9ed9..a7ac502b248 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -797,16 +797,8 @@ pub enum InvalidMonomorphization<'tcx> {
         out_ty: Ty<'tcx>,
     },
 
-    #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = E0511)]
-    ShuffleIndexNotConstant {
-        #[primary_span]
-        span: Span,
-        name: Symbol,
-        arg_idx: u64,
-    },
-
-    #[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = E0511)]
-    ShuffleIndexOutOfBounds {
+    #[diag(codegen_ssa_invalid_monomorphization_simd_index_out_of_bounds, code = E0511)]
+    SimdIndexOutOfBounds {
         #[primary_span]
         span: Span,
         name: Symbol,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 00007110938..9c7aadb81f8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -319,7 +319,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         targets: &SwitchTargets,
     ) {
         let discr = self.codegen_operand(bx, discr);
+        let discr_value = discr.immediate();
         let switch_ty = discr.layout.ty;
+        // If our discriminant is a constant we can branch directly
+        if let Some(const_discr) = bx.const_to_opt_u128(discr_value, false) {
+            let target = targets.target_for_value(const_discr);
+            bx.br(helper.llbb_with_cleanup(self, target));
+            return;
+        };
+
         let mut target_iter = targets.iter();
         if target_iter.len() == 1 {
             // If there are two targets (one conditional, one fallback), emit `br` instead of
@@ -330,14 +338,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             if switch_ty == bx.tcx().types.bool {
                 // Don't generate trivial icmps when switching on bool.
                 match test_value {
-                    0 => bx.cond_br(discr.immediate(), llfalse, lltrue),
-                    1 => bx.cond_br(discr.immediate(), lltrue, llfalse),
+                    0 => bx.cond_br(discr_value, llfalse, lltrue),
+                    1 => bx.cond_br(discr_value, lltrue, llfalse),
                     _ => bug!(),
                 }
             } else {
                 let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
                 let llval = bx.const_uint_big(switch_llty, test_value);
-                let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
+                let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
                 bx.cond_br(cmp, lltrue, llfalse);
             }
         } else if self.cx.sess().opts.optimize == OptLevel::No
@@ -362,11 +370,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let ll2 = helper.llbb_with_cleanup(self, target2);
             let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
             let llval = bx.const_uint_big(switch_llty, test_value1);
-            let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
+            let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
             bx.cond_br(cmp, ll1, ll2);
         } else {
             bx.switch(
-                discr.immediate(),
+                discr_value,
                 helper.llbb_with_cleanup(self, targets.otherwise()),
                 target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))),
             );
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index f020616f6d8..1cb991b38f7 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -379,10 +379,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let (input, input_len) = self.operand_to_simd(&args[0])?;
                 let (dest, dest_len) = self.place_to_simd(dest)?;
                 assert_eq!(input_len, dest_len, "Return vector length must match input length");
-                assert!(
-                    index < dest_len,
-                    "Index `{index}` must be in bounds of vector with length {dest_len}"
-                );
+                // Bounds are not checked by typeck so we have to do it ourselves.
+                if index >= input_len {
+                    throw_ub_format!(
+                        "`simd_insert` index {index} is out-of-bounds of vector with length {input_len}"
+                    );
+                }
 
                 for i in 0..dest_len {
                     let place = self.project_index(&dest, i)?;
@@ -397,10 +399,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::simd_extract => {
                 let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
                 let (input, input_len) = self.operand_to_simd(&args[0])?;
-                assert!(
-                    index < input_len,
-                    "index `{index}` must be in bounds of vector with length {input_len}"
-                );
+                // Bounds are not checked by typeck so we have to do it ourselves.
+                if index >= input_len {
+                    throw_ub_format!(
+                        "`simd_extract` index {index} is out-of-bounds of vector with length {input_len}"
+                    );
+                }
                 self.copy_op(&self.project_index(&input, index)?, dest)?;
             }
             sym::likely | sym::unlikely | sym::black_box => {
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index adcb6ceaebf..32202ac3ede 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -429,7 +429,7 @@ impl<T> RwLock<T> {
     #[inline(always)]
     pub fn leak(&self) -> &T {
         let guard = self.read();
-        let ret = unsafe { &*(&*guard as *const T) };
+        let ret = unsafe { &*std::ptr::addr_of!(*guard) };
         std::mem::forget(guard);
         ret
     }
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index e66cfbe6fb6..ffc8f782fd3 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -107,7 +107,7 @@
 use crate::errors;
 use crate::mbe::{KleeneToken, TokenTree};
 
-use rustc_ast::token::{Delimiter, Token, TokenKind};
+use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{DiagnosticMessage, MultiSpan};
@@ -409,7 +409,7 @@ fn check_nested_occurrences(
         match (state, tt) {
             (
                 NestedMacroState::Empty,
-                &TokenTree::Token(Token { kind: TokenKind::Ident(name, false), .. }),
+                &TokenTree::Token(Token { kind: TokenKind::Ident(name, IdentIsRaw::No), .. }),
             ) => {
                 if name == kw::MacroRules {
                     state = NestedMacroState::MacroRules;
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index c82609503c1..bf99e9e6d5c 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -8,6 +8,7 @@ use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser}
 use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc};
 use crate::mbe::transcribe::transcribe;
 
+use ast::token::IdentIsRaw;
 use rustc_ast as ast;
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
@@ -1302,7 +1303,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                 match tok {
                     TokenTree::Token(token) => match token.kind {
                         FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes,
-                        Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes,
+                        Ident(name, IdentIsRaw::No) if name == kw::If || name == kw::In => {
+                            IsInFollow::Yes
+                        }
                         _ => IsInFollow::No(TOKENS),
                     },
                     _ => IsInFollow::No(TOKENS),
@@ -1313,7 +1316,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                 match tok {
                     TokenTree::Token(token) => match token.kind {
                         FatArrow | Comma | Eq => IsInFollow::Yes,
-                        Ident(name, false) if name == kw::If || name == kw::In => IsInFollow::Yes,
+                        Ident(name, IdentIsRaw::No) if name == kw::If || name == kw::In => {
+                            IsInFollow::Yes
+                        }
                         _ => IsInFollow::No(TOKENS),
                     },
                     _ => IsInFollow::No(TOKENS),
@@ -1336,7 +1341,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                         | BinOp(token::Shr)
                         | Semi
                         | BinOp(token::Or) => IsInFollow::Yes,
-                        Ident(name, false) if name == kw::As || name == kw::Where => {
+                        Ident(name, IdentIsRaw::No) if name == kw::As || name == kw::Where => {
                             IsInFollow::Yes
                         }
                         _ => IsInFollow::No(TOKENS),
@@ -1364,7 +1369,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
                 match tok {
                     TokenTree::Token(token) => match token.kind {
                         Comma => IsInFollow::Yes,
-                        Ident(name, is_raw) if is_raw || name != kw::Priv => IsInFollow::Yes,
+                        Ident(_, IdentIsRaw::Yes) => IsInFollow::Yes,
+                        Ident(name, _) if name != kw::Priv => IsInFollow::Yes,
                         _ => {
                             if token.can_begin_type() {
                                 IsInFollow::Yes
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 3ca0787ce8e..84f7dc4771a 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -1,4 +1,4 @@
-use rustc_ast::token::{self, Delimiter};
+use rustc_ast::token::{self, Delimiter, IdentIsRaw};
 use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree};
 use rustc_ast::{LitIntType, LitKind};
 use rustc_ast_pretty::pprust;
@@ -142,7 +142,7 @@ fn parse_ident<'sess>(
     if let Some(tt) = iter.next()
         && let TokenTree::Token(token, _) = tt
     {
-        if let Some((elem, false)) = token.ident() {
+        if let Some((elem, IdentIsRaw::No)) = token.ident() {
             return Ok(elem);
         }
         let token_str = pprust::token_to_string(token);
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 0fdfa563138..ec1dd807d1a 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -2,7 +2,7 @@ use crate::errors;
 use crate::mbe::macro_parser::count_metavar_decls;
 use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
-use rustc_ast::token::{self, Delimiter, Token};
+use rustc_ast::token::{self, Delimiter, IdentIsRaw, Token};
 use rustc_ast::{tokenstream, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_feature::Features;
@@ -222,7 +222,7 @@ fn parse_tree<'a>(
                 Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => {
                     let (ident, is_raw) = token.ident().unwrap();
                     let span = ident.span.with_lo(span.lo());
-                    if ident.name == kw::Crate && !is_raw {
+                    if ident.name == kw::Crate && matches!(is_raw, IdentIsRaw::No) {
                         TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
                     } else {
                         TokenTree::MetaVar(span, ident)
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 7a888250ca1..0e07b41b43c 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -2,6 +2,7 @@ use crate::tests::{
     matches_codepattern, string_to_stream, with_error_checking_parse, with_expected_parse_error,
 };
 
+use ast::token::IdentIsRaw;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
@@ -74,9 +75,12 @@ fn string_to_tts_macro() {
 
         match tts {
             [
-                TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }, _),
+                TokenTree::Token(
+                    Token { kind: token::Ident(name_macro_rules, IdentIsRaw::No), .. },
+                    _,
+                ),
                 TokenTree::Token(Token { kind: token::Not, .. }, _),
-                TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }, _),
+                TokenTree::Token(Token { kind: token::Ident(name_zip, IdentIsRaw::No), .. }, _),
                 TokenTree::Delimited(.., macro_delim, macro_tts),
             ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => {
                 let tts = &macro_tts.trees().collect::<Vec<_>>();
@@ -90,7 +94,10 @@ fn string_to_tts_macro() {
                         match &tts[..] {
                             [
                                 TokenTree::Token(Token { kind: token::Dollar, .. }, _),
-                                TokenTree::Token(Token { kind: token::Ident(name, false), .. }, _),
+                                TokenTree::Token(
+                                    Token { kind: token::Ident(name, IdentIsRaw::No), .. },
+                                    _,
+                                ),
                             ] if first_delim == &Delimiter::Parenthesis && name.as_str() == "a" => {
                             }
                             _ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
@@ -99,7 +106,10 @@ fn string_to_tts_macro() {
                         match &tts[..] {
                             [
                                 TokenTree::Token(Token { kind: token::Dollar, .. }, _),
-                                TokenTree::Token(Token { kind: token::Ident(name, false), .. }, _),
+                                TokenTree::Token(
+                                    Token { kind: token::Ident(name, IdentIsRaw::No), .. },
+                                    _,
+                                ),
                             ] if second_delim == &Delimiter::Parenthesis
                                 && name.as_str() == "a" => {}
                             _ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
@@ -119,8 +129,11 @@ fn string_to_tts_1() {
         let tts = string_to_stream("fn a(b: i32) { b; }".to_string());
 
         let expected = TokenStream::new(vec![
-            TokenTree::token_alone(token::Ident(kw::Fn, false), sp(0, 2)),
-            TokenTree::token_joint_hidden(token::Ident(Symbol::intern("a"), false), sp(3, 4)),
+            TokenTree::token_alone(token::Ident(kw::Fn, IdentIsRaw::No), sp(0, 2)),
+            TokenTree::token_joint_hidden(
+                token::Ident(Symbol::intern("a"), IdentIsRaw::No),
+                sp(3, 4),
+            ),
             TokenTree::Delimited(
                 DelimSpan::from_pair(sp(4, 5), sp(11, 12)),
                 // `JointHidden` because the `(` is followed immediately by
@@ -128,10 +141,16 @@ fn string_to_tts_1() {
                 DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
                 Delimiter::Parenthesis,
                 TokenStream::new(vec![
-                    TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(5, 6)),
+                    TokenTree::token_joint(
+                        token::Ident(Symbol::intern("b"), IdentIsRaw::No),
+                        sp(5, 6),
+                    ),
                     TokenTree::token_alone(token::Colon, sp(6, 7)),
                     // `JointHidden` because the `i32` is immediately followed by the `)`.
-                    TokenTree::token_joint_hidden(token::Ident(sym::i32, false), sp(8, 11)),
+                    TokenTree::token_joint_hidden(
+                        token::Ident(sym::i32, IdentIsRaw::No),
+                        sp(8, 11),
+                    ),
                 ])
                 .into(),
             ),
@@ -143,7 +162,10 @@ fn string_to_tts_1() {
                 DelimSpacing::new(Spacing::Alone, Spacing::Alone),
                 Delimiter::Brace,
                 TokenStream::new(vec![
-                    TokenTree::token_joint(token::Ident(Symbol::intern("b"), false), sp(15, 16)),
+                    TokenTree::token_joint(
+                        token::Ident(Symbol::intern("b"), IdentIsRaw::No),
+                        sp(15, 16),
+                    ),
                     // `Alone` because the `;` is followed by whitespace.
                     TokenTree::token_alone(token::Semi, sp(16, 17)),
                 ])
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 62d0deb2d3a..87ea8690ffe 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,4 +1,5 @@
 use crate::base::ExtCtxt;
+use ast::token::IdentIsRaw;
 use pm::bridge::{
     server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
 };
@@ -216,7 +217,9 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
                 Question => op("?"),
                 SingleQuote => op("'"),
 
-                Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { sym, is_raw, span })),
+                Ident(sym, is_raw) => {
+                    trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
+                }
                 Lifetime(name) => {
                     let ident = symbol::Ident::new(name, span).without_first_quote();
                     trees.extend([
@@ -238,7 +241,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
                         escaped.extend(ch.escape_debug());
                     }
                     let stream = [
-                        Ident(sym::doc, false),
+                        Ident(sym::doc, IdentIsRaw::No),
                         Eq,
                         TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
                     ]
@@ -259,7 +262,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
                 Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
                     trees.push(TokenTree::Ident(Ident {
                         sym: ident.name,
-                        is_raw: *is_raw,
+                        is_raw: matches!(is_raw, IdentIsRaw::Yes),
                         span: ident.span,
                     }))
                 }
@@ -352,7 +355,7 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
             }
             TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
                 rustc.sess().symbol_gallery.insert(sym, span);
-                smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)]
+                smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw.into()), span)]
             }
             TokenTree::Literal(self::Literal {
                 kind: self::LitKind::Integer,
@@ -570,7 +573,7 @@ impl server::TokenStream for Rustc<'_, '_> {
         match &expr.kind {
             ast::ExprKind::Lit(token_lit) if token_lit.kind == token::Bool => {
                 Ok(tokenstream::TokenStream::token_alone(
-                    token::Ident(token_lit.symbol, false),
+                    token::Ident(token_lit.symbol, IdentIsRaw::No),
                     expr.span,
                 ))
             }
diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs
index 91c4dd732e3..78795e86fd5 100644
--- a/compiler/rustc_expand/src/tokenstream/tests.rs
+++ b/compiler/rustc_expand/src/tokenstream/tests.rs
@@ -1,6 +1,6 @@
 use crate::tests::string_to_stream;
 
-use rustc_ast::token;
+use rustc_ast::token::{self, IdentIsRaw};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_span::create_default_session_globals_then;
 use rustc_span::{BytePos, Span, Symbol};
@@ -86,7 +86,8 @@ fn test_diseq_1() {
 fn test_is_empty() {
     create_default_session_globals_then(|| {
         let test0 = TokenStream::default();
-        let test1 = TokenStream::token_alone(token::Ident(Symbol::intern("a"), false), sp(0, 1));
+        let test1 =
+            TokenStream::token_alone(token::Ident(Symbol::intern("a"), IdentIsRaw::No), sp(0, 1));
         let test2 = string_to_ts("foo(bar::baz)");
 
         assert_eq!(test0.is_empty(), true);
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 18f6ae35054..1b2993dabdb 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -84,6 +84,8 @@ declare_features! (
     (accepted, cfg_doctest, "1.40.0", Some(62210)),
     /// Enables `#[cfg(panic = "...")]` config key.
     (accepted, cfg_panic, "1.60.0", Some(77443)),
+    /// Allows `cfg(target_abi = "...")`.
+    (accepted, cfg_target_abi, "CURRENT_RUSTC_VERSION", Some(80970)),
     /// Allows `cfg(target_feature = "...")`.
     (accepted, cfg_target_feature, "1.27.0", Some(29717)),
     /// Allows `cfg(target_vendor = "...")`.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 99875ec5405..6cb41be7c94 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -25,7 +25,6 @@ pub type GatedCfg = (Symbol, Symbol, GateFn);
 const GATED_CFGS: &[GatedCfg] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
     (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)),
-    (sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)),
     (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
     (
         sym::target_has_atomic_equal_alignment,
@@ -792,6 +791,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
         "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
     ),
+    rustc_attr!(
+        rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
+        "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 93c183a65ef..8eea4b7d8a8 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -373,8 +373,6 @@ declare_features! (
     (unstable, cfg_sanitize, "1.41.0", Some(39699)),
     /// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`.
     (unstable, cfg_sanitizer_cfi, "1.77.0", Some(89653)),
-    /// Allows `cfg(target_abi = "...")`.
-    (unstable, cfg_target_abi, "1.55.0", Some(80970)),
     /// Allows `cfg(target(abi = "..."))`.
     (unstable, cfg_target_compact, "1.63.0", Some(96901)),
     /// Allows `cfg(target_has_atomic_load_store = "...")`.
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 07bbaa1926e..b46a67d08eb 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -1,14 +1,13 @@
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
+use crate::errors;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
-use rustc_trait_selection::traits;
-
-use crate::errors;
+use rustc_trait_selection::traits::{self, IsFirstInputType};
 
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn orphan_check_impl(
@@ -288,7 +287,7 @@ fn emit_orphan_check_error<'tcx>(
                 (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
             let mut sugg = None;
             for &(mut ty, is_target_ty) in &tys {
-                let span = if is_target_ty {
+                let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
                     // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
                     self_ty_span
                 } else {
@@ -321,7 +320,8 @@ fn emit_orphan_check_error<'tcx>(
                     }
                 }
 
-                let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty;
+                let is_foreign =
+                    !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
 
                 match &ty.kind() {
                     ty::Slice(_) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index e245dee4daf..7715f2ef43a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2437,6 +2437,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let suggestion =
                     if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
                 suggs.push((sp, suggestion))
+            } else if let GenericKind::Alias(ref p) = bound_kind
+                && let ty::Projection = p.kind(self.tcx)
+                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
+                && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
+                    self.tcx.opt_rpitit_info(p.def_id)
+            {
+                // The lifetime found in the `impl` is longer than the one on the RPITIT.
+                // Do not suggest `<Type as Trait>::{opaque}: 'static`.
             } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
                 let pred = format!("{bound_kind}: {lt_name}");
                 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 92f7497362e..9f73d2e6812 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1825,7 +1825,7 @@ impl KeywordIdents {
             match tt {
                 // Only report non-raw idents.
                 TokenTree::Token(token, _) => {
-                    if let Some((ident, false)) = token.ident() {
+                    if let Some((ident, token::IdentIsRaw::No)) = token.ident() {
                         self.check_ident_token(cx, UnderMacro(true), ident);
                     }
                 }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index d8e12c04f75..844f87c3f50 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -527,6 +527,11 @@ fn register_builtins(store: &mut LintStore) {
         "no longer needed, see #93367 \
          <https://github.com/rust-lang/rust/issues/93367> for more information",
     );
+    store.register_removed(
+        "const_patterns_without_partial_eq",
+        "converted into hard error, see RFC #3535 \
+         <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 84a050a242a..1cddb45428c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -32,7 +32,6 @@ declare_lint_pass! {
         CONFLICTING_REPR_HINTS,
         CONST_EVALUATABLE_UNCHECKED,
         CONST_ITEM_MUTATION,
-        CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
         DEAD_CODE,
         DEPRECATED,
         DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
@@ -2343,57 +2342,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `const_patterns_without_partial_eq` lint detects constants that are used in patterns,
-    /// whose type does not implement `PartialEq`.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![deny(const_patterns_without_partial_eq)]
-    ///
-    /// trait EnumSetType {
-    ///    type Repr;
-    /// }
-    ///
-    /// enum Enum8 { }
-    /// impl EnumSetType for Enum8 {
-    ///     type Repr = u8;
-    /// }
-    ///
-    /// #[derive(PartialEq, Eq)]
-    /// struct EnumSet<T: EnumSetType> {
-    ///     __enumset_underlying: T::Repr,
-    /// }
-    ///
-    /// const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
-    ///
-    /// fn main() {
-    ///     match CONST_SET {
-    ///         CONST_SET => { /* ok */ }
-    ///         _ => panic!("match fell through?"),
-    ///     }
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Previous versions of Rust accepted constants in patterns, even if those constants' types
-    /// did not have `PartialEq` implemented. The compiler falls back to comparing the value
-    /// field-by-field. In the future we'd like to ensure that pattern matching always
-    /// follows `PartialEq` semantics, so that trait bound will become a requirement for
-    /// matching on constants.
-    pub CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
-    Warn,
-    "constant in pattern does not implement `PartialEq`",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #116122 <https://github.com/rust-lang/rust/issues/116122>",
-    };
-}
-
-declare_lint! {
     /// The `ambiguous_associated_items` lint detects ambiguity between
     /// [associated items] and [enum variants].
     ///
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index f4dfbe059eb..9c7c46f2ad2 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -233,7 +233,7 @@ impl<'sess> OnDiskCache<'sess> {
 
                 for (index, file) in files.iter().enumerate() {
                     let index = SourceFileIndex(index as u32);
-                    let file_ptr: *const SourceFile = &**file as *const _;
+                    let file_ptr: *const SourceFile = std::ptr::addr_of!(**file);
                     file_to_file_index.insert(file_ptr, index);
                     let source_file_id = EncodedSourceFileId::new(tcx, file);
                     file_index_to_stable_id.insert(index, source_file_id);
@@ -835,7 +835,7 @@ pub struct CacheEncoder<'a, 'tcx> {
 impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
     #[inline]
     fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
-        self.file_to_file_index[&(&*source_file as *const SourceFile)]
+        self.file_to_file_index[&std::ptr::addr_of!(*source_file)]
     }
 
     /// Encode something with additional information that allows to do some
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 4f9c9d85763..336c2dce114 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -61,7 +61,7 @@ impl<T> List<T> {
         // length) that is 64-byte aligned, thus featuring the necessary
         // trailing padding for elements with up to 64-byte alignment.
         static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
-        unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+        unsafe { &*(std::ptr::addr_of!(EMPTY_SLICE) as *const List<T>) }
     }
 
     pub fn len(&self) -> usize {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index f9a8795f5d6..641a278c1d3 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1150,39 +1150,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// the value, we will set and generate a branch to the appropriate
     /// pre-binding block.
     ///
-    /// If we find that *NONE* of the candidates apply, we branch to the
-    /// `otherwise_block`, setting it to `Some` if required. In principle, this
-    /// means that the input list was not exhaustive, though at present we
-    /// sometimes are not smart enough to recognize all exhaustive inputs.
+    /// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`.
     ///
     /// It might be surprising that the input can be non-exhaustive.
     /// Indeed, initially, it is not, because all matches are
     /// exhaustive in Rust. But during processing we sometimes divide
     /// up the list of candidates and recurse with a non-exhaustive
-    /// list. This is important to keep the size of the generated code
-    /// under control. See [`Builder::test_candidates`] for more details.
+    /// list. This is how our lowering approach (called "backtracking
+    /// automaton" in the literature) works.
+    /// See [`Builder::test_candidates`] for more details.
     ///
     /// If `fake_borrows` is `Some`, then places which need fake borrows
     /// will be added to it.
     ///
-    /// For an example of a case where we set `otherwise_block`, even for an
-    /// exhaustive match, consider:
-    ///
+    /// For an example of how we use `otherwise_block`, consider:
     /// ```
-    /// # fn foo(x: (bool, bool)) {
-    /// match x {
-    ///     (true, true) => (),
-    ///     (_, false) => (),
-    ///     (false, true) => (),
+    /// # fn foo((x, y): (bool, bool)) -> u32 {
+    /// match (x, y) {
+    ///     (true, true) => 1,
+    ///     (_, false) => 2,
+    ///     (false, true) => 3,
     /// }
     /// # }
     /// ```
+    /// For this match, we generate something like:
+    /// ```
+    /// # fn foo((x, y): (bool, bool)) -> u32 {
+    /// if x {
+    ///     if y {
+    ///         return 1
+    ///     } else {
+    ///         // continue
+    ///     }
+    /// } else {
+    ///     // continue
+    /// }
+    /// if y {
+    ///     if x {
+    ///         // This is actually unreachable because the `(true, true)` case was handled above.
+    ///         // continue
+    ///     } else {
+    ///         return 3
+    ///     }
+    /// } else {
+    ///     return 2
+    /// }
+    /// // this is the final `otherwise_block`, which is unreachable because the match was exhaustive.
+    /// unreachable!()
+    /// # }
+    /// ```
+    ///
+    /// Every `continue` is an instance of branching to some `otherwise_block` somewhere deep within
+    /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`].
     ///
-    /// For this match, we check if `x.0` matches `true` (for the first
-    /// arm). If it doesn't match, we check `x.1`. If `x.1` is `true` we check
-    /// if `x.0` matches `false` (for the third arm). In the (impossible at
-    /// runtime) case when `x.0` is now `true`, we branch to
-    /// `otherwise_block`.
+    /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
+    /// code size at the expense of non-optimal code paths.
     #[instrument(skip(self, fake_borrows), level = "debug")]
     fn match_candidates<'pat>(
         &mut self,
@@ -1557,18 +1579,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
-    /// This is the most subtle part of the matching algorithm. At
-    /// this point, the input candidates have been fully simplified,
-    /// and so we know that all remaining match-pairs require some
-    /// sort of test. To decide what test to perform, we take the highest
-    /// priority candidate (the first one in the list, as of January 2021)
-    /// and extract the first match-pair from the list. From this we decide
-    /// what kind of test is needed using [`Builder::test`], defined in the
-    /// [`test` module](mod@test).
+    /// Pick a test to run. Which test doesn't matter as long as it is guaranteed to fully match at
+    /// least one match pair. We currently simply pick the test corresponding to the first match
+    /// pair of the first candidate in the list.
     ///
-    /// *Note:* taking the first match pair is somewhat arbitrary, and
-    /// we might do better here by choosing more carefully what to
-    /// test.
+    /// *Note:* taking the first match pair is somewhat arbitrary, and we might do better here by
+    /// choosing more carefully what to test.
     ///
     /// For example, consider the following possible match-pairs:
     ///
@@ -1580,121 +1596,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// [`Switch`]: TestKind::Switch
     /// [`SwitchInt`]: TestKind::SwitchInt
     /// [`Range`]: TestKind::Range
-    ///
-    /// Once we know what sort of test we are going to perform, this
-    /// test may also help us winnow down our candidates. So we walk over
-    /// the candidates (from high to low priority) and check. This
-    /// gives us, for each outcome of the test, a transformed list of
-    /// candidates. For example, if we are testing `x.0`'s variant,
-    /// and we have a candidate `(x.0 @ Some(v), x.1 @ 22)`,
-    /// then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)`.
-    /// Note that the first match-pair is now simpler (and, in fact, irrefutable).
-    ///
-    /// But there may also be candidates that the test just doesn't
-    /// apply to. The classical example involves wildcards:
-    ///
-    /// ```
-    /// # let (x, y, z) = (true, true, true);
-    /// match (x, y, z) {
-    ///     (true , _    , true ) => true,  // (0)
-    ///     (_    , true , _    ) => true,  // (1)
-    ///     (false, false, _    ) => false, // (2)
-    ///     (true , _    , false) => false, // (3)
-    /// }
-    /// # ;
-    /// ```
-    ///
-    /// In that case, after we test on `x`, there are 2 overlapping candidate
-    /// sets:
-    ///
-    /// - If the outcome is that `x` is true, candidates 0, 1, and 3
-    /// - If the outcome is that `x` is false, candidates 1 and 2
-    ///
-    /// Here, the traditional "decision tree" method would generate 2
-    /// separate code-paths for the 2 separate cases.
-    ///
-    /// In some cases, this duplication can create an exponential amount of
-    /// code. This is most easily seen by noticing that this method terminates
-    /// with precisely the reachable arms being reachable - but that problem
-    /// is trivially NP-complete:
-    ///
-    /// ```ignore (illustrative)
-    /// match (var0, var1, var2, var3, ...) {
-    ///     (true , _   , _    , false, true, ...) => false,
-    ///     (_    , true, true , false, _   , ...) => false,
-    ///     (false, _   , false, false, _   , ...) => false,
-    ///     ...
-    ///     _ => true
-    /// }
-    /// ```
-    ///
-    /// Here the last arm is reachable only if there is an assignment to
-    /// the variables that does not match any of the literals. Therefore,
-    /// compilation would take an exponential amount of time in some cases.
-    ///
-    /// That kind of exponential worst-case might not occur in practice, but
-    /// our simplistic treatment of constants and guards would make it occur
-    /// in very common situations - for example [#29740]:
-    ///
-    /// ```ignore (illustrative)
-    /// match x {
-    ///     "foo" if foo_guard => ...,
-    ///     "bar" if bar_guard => ...,
-    ///     "baz" if baz_guard => ...,
-    ///     ...
-    /// }
-    /// ```
-    ///
-    /// [#29740]: https://github.com/rust-lang/rust/issues/29740
-    ///
-    /// Here we first test the match-pair `x @ "foo"`, which is an [`Eq` test].
-    ///
-    /// [`Eq` test]: TestKind::Eq
-    ///
-    /// It might seem that we would end up with 2 disjoint candidate
-    /// sets, consisting of the first candidate or the other two, but our
-    /// algorithm doesn't reason about `"foo"` being distinct from the other
-    /// constants; it considers the latter arms to potentially match after
-    /// both outcomes, which obviously leads to an exponential number
-    /// of tests.
-    ///
-    /// To avoid these kinds of problems, our algorithm tries to ensure
-    /// the amount of generated tests is linear. When we do a k-way test,
-    /// we return an additional "unmatched" set alongside the obvious `k`
-    /// sets. When we encounter a candidate that would be present in more
-    /// than one of the sets, we put it and all candidates below it into the
-    /// "unmatched" set. This ensures these `k+1` sets are disjoint.
-    ///
-    /// After we perform our test, we branch into the appropriate candidate
-    /// set and recurse with `match_candidates`. These sub-matches are
-    /// obviously non-exhaustive - as we discarded our otherwise set - so
-    /// we set their continuation to do `match_candidates` on the
-    /// "unmatched" set (which is again non-exhaustive).
-    ///
-    /// If you apply this to the above test, you basically wind up
-    /// with an if-else-if chain, testing each candidate in turn,
-    /// which is precisely what we want.
-    ///
-    /// In addition to avoiding exponential-time blowups, this algorithm
-    /// also has the nice property that each guard and arm is only generated
-    /// once.
-    fn test_candidates<'pat, 'b, 'c>(
+    fn pick_test(
         &mut self,
-        span: Span,
-        scrutinee_span: Span,
-        mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
-        start_block: BasicBlock,
-        otherwise_block: BasicBlock,
+        candidates: &mut [&mut Candidate<'_, 'tcx>],
         fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
-    ) {
-        // extract the match-pair from the highest priority candidate
+    ) -> (PlaceBuilder<'tcx>, Test<'tcx>) {
+        // Extract the match-pair from the highest priority candidate
         let match_pair = &candidates.first().unwrap().match_pairs[0];
         let mut test = self.test(match_pair);
         let match_place = match_pair.place.clone();
 
-        // most of the time, the test to perform is simply a function
-        // of the main candidate; but for a test like SwitchInt, we
-        // may want to add cases based on the candidates that are
+        debug!(?test, ?match_pair);
+        // Most of the time, the test to perform is simply a function of the main candidate; but for
+        // a test like SwitchInt, we may want to add cases based on the candidates that are
         // available
         match test.kind {
             TestKind::SwitchInt { switch_ty: _, ref mut options } => {
@@ -1721,20 +1635,58 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             fb.insert(resolved_place);
         }
 
-        // perform the test, branching to one of N blocks. For each of
-        // those N possible outcomes, create a (initially empty)
-        // vector of candidates. Those are the candidates that still
-        // apply if the test has that particular outcome.
-        debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair);
+        (match_place, test)
+    }
+
+    /// Given a test, we sort the input candidates into several buckets. If a candidate only matches
+    /// in one of the branches of `test`, we move it there. If it could match in more than one of
+    /// the branches of `test`, we stop sorting candidates.
+    ///
+    /// This returns a pair of
+    /// - the candidates that weren't sorted;
+    /// - for each possible outcome of the test, the candidates that match in that outcome.
+    ///
+    /// Moreover, we transform the branched candidates to reflect the fact that we know which
+    /// outcome of `test` occurred.
+    ///
+    /// For example:
+    /// ```
+    /// # let (x, y, z) = (true, true, true);
+    /// match (x, y, z) {
+    ///     (true , _    , true ) => true,  // (0)
+    ///     (false, false, _    ) => false, // (1)
+    ///     (_    , true , _    ) => true,  // (2)
+    ///     (true , _    , false) => false, // (3)
+    /// }
+    /// # ;
+    /// ```
+    ///
+    /// Assume we are testing on `x`. There are 2 overlapping candidate sets:
+    /// - If the outcome is that `x` is true, candidates 0, 2, and 3
+    /// - If the outcome is that `x` is false, candidates 1 and 2
+    ///
+    /// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes
+    /// into outcome `x == false`, and candidate 2 and 3 remain unsorted.
+    ///
+    /// The sorted candidates are transformed:
+    /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
+    /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
+    fn sort_candidates<'b, 'c, 'pat>(
+        &mut self,
+        match_place: &PlaceBuilder<'tcx>,
+        test: &Test<'tcx>,
+        mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
+    ) -> (&'b mut [&'c mut Candidate<'pat, 'tcx>], Vec<Vec<&'b mut Candidate<'pat, 'tcx>>>) {
+        // For each of the N possible outcomes, create a (initially empty) vector of candidates.
+        // Those are the candidates that apply if the test has that particular outcome.
         let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
         target_candidates.resize_with(test.targets(), Default::default);
 
         let total_candidate_count = candidates.len();
 
-        // Sort the candidates into the appropriate vector in
-        // `target_candidates`. Note that at some point we may
-        // encounter a candidate where the test is not relevant; at
-        // that point, we stop sorting.
+        // Sort the candidates into the appropriate vector in `target_candidates`. Note that at some
+        // point we may encounter a candidate where the test is not relevant; at that point, we stop
+        // sorting.
         while let Some(candidate) = candidates.first_mut() {
             let Some(idx) = self.sort_candidate(&match_place, &test, candidate) else {
                 break;
@@ -1743,7 +1695,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             target_candidates[idx].push(candidate);
             candidates = rest;
         }
-        // at least the first candidate ought to be tested
+
+        // At least the first candidate ought to be tested
         assert!(
             total_candidate_count > candidates.len(),
             "{total_candidate_count}, {candidates:#?}"
@@ -1751,16 +1704,130 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!("tested_candidates: {}", total_candidate_count - candidates.len());
         debug!("untested_candidates: {}", candidates.len());
 
+        (candidates, target_candidates)
+    }
+
+    /// This is the most subtle part of the match lowering algorithm. At this point, the input
+    /// candidates have been fully simplified, so all remaining match-pairs require some sort of
+    /// test.
+    ///
+    /// Once we pick what sort of test we are going to perform, this test will help us winnow down
+    /// our candidates. So we walk over the candidates (from high to low priority) and check. We
+    /// compute, for each outcome of the test, a transformed list of candidates. If a candidate
+    /// matches in a single branch of our test, we add it to the corresponding outcome. We also
+    /// transform it to record the fact that we know which outcome occurred.
+    ///
+    /// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1
+    /// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the
+    /// branch corresponding to `Some`. To ensure we make progress, we always pick a test that
+    /// results in simplifying the first candidate.
+    ///
+    /// But there may also be candidates that the test doesn't
+    /// apply to. The classical example is wildcards:
+    ///
+    /// ```
+    /// # let (x, y, z) = (true, true, true);
+    /// match (x, y, z) {
+    ///     (true , _    , true ) => true,  // (0)
+    ///     (false, false, _    ) => false, // (1)
+    ///     (_    , true , _    ) => true,  // (2)
+    ///     (true , _    , false) => false, // (3)
+    /// }
+    /// # ;
+    /// ```
+    ///
+    /// Here, the traditional "decision tree" method would generate 2 separate code-paths for the 2
+    /// possible values of `x`. This would however duplicate some candidates, which would need to be
+    /// lowered several times.
+    ///
+    /// In some cases, this duplication can create an exponential amount of
+    /// code. This is most easily seen by noticing that this method terminates
+    /// with precisely the reachable arms being reachable - but that problem
+    /// is trivially NP-complete:
+    ///
+    /// ```ignore (illustrative)
+    /// match (var0, var1, var2, var3, ...) {
+    ///     (true , _   , _    , false, true, ...) => false,
+    ///     (_    , true, true , false, _   , ...) => false,
+    ///     (false, _   , false, false, _   , ...) => false,
+    ///     ...
+    ///     _ => true
+    /// }
+    /// ```
+    ///
+    /// Here the last arm is reachable only if there is an assignment to
+    /// the variables that does not match any of the literals. Therefore,
+    /// compilation would take an exponential amount of time in some cases.
+    ///
+    /// In rustc, we opt instead for the "backtracking automaton" approach. This guarantees we never
+    /// duplicate a candidate (except in the presence of or-patterns). In fact this guarantee is
+    /// ensured by the fact that we carry around `&mut Candidate`s which can't be duplicated.
+    ///
+    /// To make this work, whenever we decide to perform a test, if we encounter a candidate that
+    /// could match in more than one branch of the test, we stop. We generate code for the test and
+    /// for the candidates in its branches; the remaining candidates will be tested if the
+    /// candidates in the branches fail to match.
+    ///
+    /// For example, if we test on `x` in the following:
+    /// ```
+    /// # fn foo((x, y, z): (bool, bool, bool)) -> u32 {
+    /// match (x, y, z) {
+    ///     (true , _    , true ) => 0,
+    ///     (false, false, _    ) => 1,
+    ///     (_    , true , _    ) => 2,
+    ///     (true , _    , false) => 3,
+    /// }
+    /// # }
+    /// ```
+    /// this function generates code that looks more of less like:
+    /// ```
+    /// # fn foo((x, y, z): (bool, bool, bool)) -> u32 {
+    /// if x {
+    ///     match (y, z) {
+    ///         (_, true) => return 0,
+    ///         _ => {} // continue matching
+    ///     }
+    /// } else {
+    ///     match (y, z) {
+    ///         (false, _) => return 1,
+    ///         _ => {} // continue matching
+    ///     }
+    /// }
+    /// // the block here is `remainder_start`
+    /// match (x, y, z) {
+    ///     (_    , true , _    ) => 2,
+    ///     (true , _    , false) => 3,
+    ///     _ => unreachable!(),
+    /// }
+    /// # }
+    /// ```
+    fn test_candidates<'pat, 'b, 'c>(
+        &mut self,
+        span: Span,
+        scrutinee_span: Span,
+        candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
+        start_block: BasicBlock,
+        otherwise_block: BasicBlock,
+        fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
+    ) {
+        // Extract the match-pair from the highest priority candidate and build a test from it.
+        let (match_place, test) = self.pick_test(candidates, fake_borrows);
+
+        // For each of the N possible test outcomes, build the vector of candidates that applies if
+        // the test has that particular outcome.
+        let (remaining_candidates, target_candidates) =
+            self.sort_candidates(&match_place, &test, candidates);
+
         // The block that we should branch to if none of the
         // `target_candidates` match.
-        let remainder_start = if !candidates.is_empty() {
+        let remainder_start = if !remaining_candidates.is_empty() {
             let remainder_start = self.cfg.start_new_block();
             self.match_candidates(
                 span,
                 scrutinee_span,
                 remainder_start,
                 otherwise_block,
-                candidates,
+                remaining_candidates,
                 fake_borrows,
             );
             remainder_start
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 48b93ce0ac5..101f1cb9f2f 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -768,6 +768,14 @@ pub struct TypeNotStructural<'tcx> {
 }
 
 #[derive(Diagnostic)]
+#[diag(mir_build_non_partial_eq_match)]
+pub struct TypeNotPartialEq<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub non_peq_ty: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
 #[diag(mir_build_invalid_pattern)]
 pub struct InvalidPattern<'tcx> {
     #[primary_span]
@@ -822,12 +830,6 @@ pub struct NontrivialStructuralMatch<'tcx> {
     pub non_sm_ty: Ty<'tcx>,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(mir_build_non_partial_eq_match)]
-pub struct NonPartialEqMatch<'tcx> {
-    pub non_peq_ty: Ty<'tcx>,
-}
-
 #[derive(Diagnostic)]
 #[diag(mir_build_pattern_not_covered, code = E0005)]
 pub(crate) struct PatternNotCovered<'s, 'tcx> {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index c77c80d9f4b..09727f9b71b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -16,7 +16,7 @@ use std::cell::Cell;
 
 use super::PatCtxt;
 use crate::errors::{
-    IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, PointerPattern,
+    IndirectStructuralMatch, InvalidPattern, NaNPattern, PointerPattern, TypeNotPartialEq,
     TypeNotStructural, UnionPattern, UnsizedPattern,
 };
 
@@ -208,15 +208,12 @@ impl<'tcx> ConstToPat<'tcx> {
                 );
             }
 
-            // Always check for `PartialEq`, even if we emitted other lints. (But not if there were
-            // any errors.) This ensures it shows up in cargo's future-compat reports as well.
+            // Always check for `PartialEq` if we had no other errors yet.
             if !self.type_has_partial_eq_impl(cv.ty()) {
-                self.tcx().emit_node_span_lint(
-                    lint::builtin::CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
-                    self.id,
-                    self.span,
-                    NonPartialEqMatch { non_peq_ty: cv.ty() },
-                );
+                let err = TypeNotPartialEq { span: self.span, non_peq_ty: cv.ty() };
+                let e = self.tcx().dcx().emit_err(err);
+                let kind = PatKind::Error(e);
+                return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
             }
         }
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 2009539d4d0..36546a03cdf 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -421,6 +421,10 @@ impl<'tcx> Inliner<'tcx> {
         callee_attrs: &CodegenFnAttrs,
         cross_crate_inlinable: bool,
     ) -> Result<(), &'static str> {
+        if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_no_mir_inline) {
+            return Err("#[rustc_no_mir_inline]");
+        }
+
         if let InlineAttr::Never = callee_attrs.inline {
             return Err("never inline hint");
         }
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 577b8f2080f..2e11da4d585 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -482,17 +482,40 @@ impl<'tcx> Validator<'_, 'tcx> {
                 match op {
                     BinOp::Div | BinOp::Rem => {
                         if lhs_ty.is_integral() {
+                            let sz = lhs_ty.primitive_size(self.tcx);
                             // Integer division: the RHS must be a non-zero const.
-                            let const_val = match rhs {
+                            let rhs_val = match rhs {
                                 Operand::Constant(c) => {
-                                    c.const_.try_eval_bits(self.tcx, self.param_env)
+                                    c.const_.try_eval_scalar_int(self.tcx, self.param_env)
                                 }
                                 _ => None,
                             };
-                            match const_val {
+                            match rhs_val.map(|x| x.try_to_uint(sz).unwrap()) {
+                                // for the zero test, int vs uint does not matter
                                 Some(x) if x != 0 => {}        // okay
                                 _ => return Err(Unpromotable), // value not known or 0 -- not okay
                             }
+                            // Furthermore, for signed divison, we also have to exclude `int::MIN / -1`.
+                            if lhs_ty.is_signed() {
+                                match rhs_val.map(|x| x.try_to_int(sz).unwrap()) {
+                                    Some(-1) | None => {
+                                        // The RHS is -1 or unknown, so we have to be careful.
+                                        // But is the LHS int::MIN?
+                                        let lhs_val = match lhs {
+                                            Operand::Constant(c) => c
+                                                .const_
+                                                .try_eval_scalar_int(self.tcx, self.param_env),
+                                            _ => None,
+                                        };
+                                        let lhs_min = sz.signed_int_min();
+                                        match lhs_val.map(|x| x.try_to_int(sz).unwrap()) {
+                                            Some(x) if x != lhs_min => {}  // okay
+                                            _ => return Err(Unpromotable), // value not known or int::MIN -- not okay
+                                        }
+                                    }
+                                    _ => {}
+                                }
+                            }
                         }
                     }
                     // The remaining operations can never fail.
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index c768ea93b5f..dc9f5bad765 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -4,7 +4,7 @@ use crate::errors;
 use crate::lexer::unicode_chars::UNICODE_ARRAY;
 use crate::make_unclosed_delims_error;
 use rustc_ast::ast::{self, AttrStyle};
-use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::{codes::*, Applicability, DiagCtxt, DiagnosticBuilder, StashKey};
@@ -181,7 +181,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> {
                         self.dcx().emit_err(errors::CannotBeRawIdent { span, ident: sym });
                     }
                     self.sess.raw_identifier_spans.push(span);
-                    token::Ident(sym, true)
+                    token::Ident(sym, IdentIsRaw::Yes)
                 }
                 rustc_lexer::TokenKind::UnknownPrefix => {
                     self.report_unknown_prefix(start);
@@ -201,7 +201,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> {
                     let span = self.mk_sp(start, self.pos);
                     self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default()
                         .push(span);
-                    token::Ident(sym, false)
+                    token::Ident(sym, IdentIsRaw::No)
                 }
                 // split up (raw) c string literals to an ident and a string literal when edition < 2021.
                 rustc_lexer::TokenKind::Literal {
@@ -339,7 +339,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> {
         let sym = nfc_normalize(self.str_from(start));
         let span = self.mk_sp(start, self.pos);
         self.sess.symbol_gallery.insert(sym, span);
-        token::Ident(sym, false)
+        token::Ident(sym, IdentIsRaw::No)
     }
 
     /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index a136abaa28b..3b4e05332fa 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -307,7 +307,7 @@ pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
 // fancier error recovery to it, as there will be less overall work to do this way.
 const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
     (" ", "Space", None),
-    ("_", "Underscore", Some(token::Ident(kw::Underscore, false))),
+    ("_", "Underscore", Some(token::Ident(kw::Underscore, token::IdentIsRaw::No))),
     ("-", "Minus/Hyphen", Some(token::BinOp(token::Minus))),
     (",", "Comma", Some(token::Comma)),
     (";", "Semicolon", Some(token::Semi)),
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 0cc2170714c..517e3d82787 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -21,6 +21,8 @@ use crate::errors::{
 use crate::fluent_generated as fluent;
 use crate::parser;
 use crate::parser::attr::InnerAttrPolicy;
+use ast::token::IdentIsRaw;
+use parser::Recovered;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
@@ -264,7 +266,7 @@ impl<'a> Parser<'a> {
     pub(super) fn expected_ident_found(
         &mut self,
         recover: bool,
-    ) -> PResult<'a, (Ident, /* is_raw */ bool)> {
+    ) -> PResult<'a, (Ident, IdentIsRaw)> {
         if let TokenKind::DocComment(..) = self.prev_token.kind {
             return Err(self.dcx().create_err(DocCommentDoesNotDocumentAnything {
                 span: self.prev_token.span,
@@ -290,11 +292,11 @@ impl<'a> Parser<'a> {
         let bad_token = self.token.clone();
 
         // suggest prepending a keyword in identifier position with `r#`
-        let suggest_raw = if let Some((ident, false)) = self.token.ident()
+        let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident()
             && ident.is_raw_guess()
             && self.look_ahead(1, |t| valid_follow.contains(&t.kind))
         {
-            recovered_ident = Some((ident, true));
+            recovered_ident = Some((ident, IdentIsRaw::Yes));
 
             // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
             // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
@@ -320,7 +322,7 @@ impl<'a> Parser<'a> {
         let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| {
             let (invalid, valid) = self.token.span.split_at(len as u32);
 
-            recovered_ident = Some((Ident::new(valid_portion, valid), false));
+            recovered_ident = Some((Ident::new(valid_portion, valid), IdentIsRaw::No));
 
             HelpIdentifierStartsWithNumber { num_span: invalid }
         });
@@ -429,7 +431,7 @@ impl<'a> Parser<'a> {
         &mut self,
         edible: &[TokenKind],
         inedible: &[TokenKind],
-    ) -> PResult<'a, bool /* recovered */> {
+    ) -> PResult<'a, Recovered> {
         debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
         fn tokens_to_string(tokens: &[TokenType]) -> String {
             let mut i = tokens.iter();
@@ -532,7 +534,7 @@ impl<'a> Parser<'a> {
                     sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
                 });
                 self.bump();
-                return Ok(true);
+                return Ok(Recovered::Yes);
             } else if self.look_ahead(0, |t| {
                 t == &token::CloseDelim(Delimiter::Brace)
                     || ((t.can_begin_expr() || t.can_begin_item())
@@ -556,7 +558,7 @@ impl<'a> Parser<'a> {
                     unexpected_token_label: Some(self.token.span),
                     sugg: ExpectedSemiSugg::AddSemi(span),
                 });
-                return Ok(true);
+                return Ok(Recovered::Yes);
             }
         }
 
@@ -653,9 +655,9 @@ impl<'a> Parser<'a> {
         // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
         // that in the parser requires unbounded lookahead, so we only add a hint to the existing
         // error rather than replacing it entirely.
-        if ((self.prev_token.kind == TokenKind::Ident(sym::c, false)
+        if ((self.prev_token.kind == TokenKind::Ident(sym::c, IdentIsRaw::No)
             && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
-            || (self.prev_token.kind == TokenKind::Ident(sym::cr, false)
+            || (self.prev_token.kind == TokenKind::Ident(sym::cr, IdentIsRaw::No)
                 && matches!(
                     &self.token.kind,
                     TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
@@ -711,7 +713,7 @@ impl<'a> Parser<'a> {
         if self.check_too_many_raw_str_terminators(&mut err) {
             if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
                 err.emit();
-                return Ok(true);
+                return Ok(Recovered::Yes);
             } else {
                 return Err(err);
             }
@@ -1223,7 +1225,7 @@ impl<'a> Parser<'a> {
                 |p| p.parse_generic_arg(None),
             );
             match x {
-                Ok((_, _, false)) => {
+                Ok((_, _, Recovered::No)) => {
                     if self.eat(&token::Gt) {
                         // We made sense of it. Improve the error message.
                         e.span_suggestion_verbose(
@@ -1247,7 +1249,7 @@ impl<'a> Parser<'a> {
                         }
                     }
                 }
-                Ok((_, _, true)) => {}
+                Ok((_, _, Recovered::Yes)) => {}
                 Err(err) => {
                     err.cancel();
                 }
@@ -1286,7 +1288,7 @@ impl<'a> Parser<'a> {
         err: &mut ComparisonOperatorsCannotBeChained,
         inner_op: &Expr,
         outer_op: &Spanned<AssocOp>,
-    ) -> bool /* advanced the cursor */ {
+    ) -> Recovered {
         if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
             if let ExprKind::Field(_, ident) = l1.kind
                 && ident.as_str().parse::<i32>().is_err()
@@ -1294,7 +1296,7 @@ impl<'a> Parser<'a> {
             {
                 // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish
                 // suggestion being the only one to apply is high.
-                return false;
+                return Recovered::No;
             }
             return match (op.node, &outer_op.node) {
                 // `x == y == z`
@@ -1313,7 +1315,7 @@ impl<'a> Parser<'a> {
                         span: inner_op.span.shrink_to_hi(),
                         middle_term: expr_to_str(r1),
                     });
-                    false // Keep the current parse behavior, where the AST is `(x < y) < z`.
+                    Recovered::No // Keep the current parse behavior, where the AST is `(x < y) < z`.
                 }
                 // `x == y < z`
                 (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
@@ -1327,12 +1329,12 @@ impl<'a> Parser<'a> {
                                 left: r1.span.shrink_to_lo(),
                                 right: r2.span.shrink_to_hi(),
                             });
-                            true
+                            Recovered::Yes
                         }
                         Err(expr_err) => {
                             expr_err.cancel();
                             self.restore_snapshot(snapshot);
-                            false
+                            Recovered::Yes
                         }
                     }
                 }
@@ -1347,19 +1349,19 @@ impl<'a> Parser<'a> {
                                 left: l1.span.shrink_to_lo(),
                                 right: r1.span.shrink_to_hi(),
                             });
-                            true
+                            Recovered::Yes
                         }
                         Err(expr_err) => {
                             expr_err.cancel();
                             self.restore_snapshot(snapshot);
-                            false
+                            Recovered::No
                         }
                     }
                 }
-                _ => false,
+                _ => Recovered::No,
             };
         }
-        false
+        Recovered::No
     }
 
     /// Produces an error if comparison operators are chained (RFC #558).
@@ -1487,8 +1489,9 @@ impl<'a> Parser<'a> {
 
                         // If it looks like a genuine attempt to chain operators (as opposed to a
                         // misformatted turbofish, for instance), suggest a correct form.
-                        if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op)
-                        {
+                        let recovered = self
+                            .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
+                        if matches!(recovered, Recovered::Yes) {
                             self.dcx().emit_err(err);
                             mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                         } else {
@@ -1500,7 +1503,7 @@ impl<'a> Parser<'a> {
                 let recover =
                     self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
                 self.dcx().emit_err(err);
-                if recover {
+                if matches!(recover, Recovered::Yes) {
                     return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
                 }
             }
@@ -1840,10 +1843,7 @@ impl<'a> Parser<'a> {
 
     /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a
     /// closing delimiter.
-    pub(super) fn unexpected_try_recover(
-        &mut self,
-        t: &TokenKind,
-    ) -> PResult<'a, bool /* recovered */> {
+    pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
         let token_str = pprust::token_kind_to_string(t);
         let this_token_str = super::token_descr(&self.token);
         let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 8826c06bebd..1ad637451b1 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3,13 +3,14 @@ use super::diagnostics::SnapshotParser;
 use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
-    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
-    SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
+    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Recovered, Restrictions,
+    SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken,
 };
 
 use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use ast::mut_visit::{noop_visit_expr, MutVisitor};
+use ast::token::IdentIsRaw;
 use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
 use core::mem;
 use rustc_ast::ptr::P;
@@ -126,7 +127,7 @@ impl<'a> Parser<'a> {
         match self.parse_expr_res(restrictions, None) {
             Ok(expr) => Ok(expr),
             Err(err) => match self.token.ident() {
-                Some((Ident { name: kw::Underscore, .. }, false))
+                Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No))
                     if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
                 {
                     // Special-case handling of `foo(_, _, _)`
@@ -457,7 +458,9 @@ impl<'a> Parser<'a> {
                 return None;
             }
             (Some(op), _) => (op, self.token.span),
-            (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
+            (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No)))
+                if self.may_recover() =>
+            {
                 self.dcx().emit_err(errors::InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "and".into(),
@@ -465,7 +468,7 @@ impl<'a> Parser<'a> {
                 });
                 (AssocOp::LAnd, span)
             }
-            (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => {
+            (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
                 self.dcx().emit_err(errors::InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "or".into(),
@@ -742,7 +745,7 @@ impl<'a> Parser<'a> {
                     (
                         // `foo: `
                         ExprKind::Path(None, ast::Path { segments, .. }),
-                        token::Ident(kw::For | kw::Loop | kw::While, false),
+                        token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
                     ) if segments.len() == 1 => {
                         let snapshot = self.create_snapshot_for_diagnostic();
                         let label = Label {
@@ -955,19 +958,20 @@ impl<'a> Parser<'a> {
 
     fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
         loop {
-            let has_question = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) {
-                // we are using noexpect here because we don't expect a `?` directly after a `return`
-                // which could be suggested otherwise
-                self.eat_noexpect(&token::Question)
-            } else {
-                self.eat(&token::Question)
-            };
+            let has_question =
+                if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+                    // we are using noexpect here because we don't expect a `?` directly after a `return`
+                    // which could be suggested otherwise
+                    self.eat_noexpect(&token::Question)
+                } else {
+                    self.eat(&token::Question)
+                };
             if has_question {
                 // `expr?`
                 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
                 continue;
             }
-            let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) {
+            let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
                 // we are using noexpect here because we don't expect a `.` directly after a `return`
                 // which could be suggested otherwise
                 self.eat_noexpect(&token::Dot)
@@ -1126,19 +1130,19 @@ impl<'a> Parser<'a> {
             // 1.
             DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
                 assert!(suffix.is_none());
-                self.token = Token::new(token::Ident(sym, false), ident_span);
+                self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);
                 let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
                 self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token))
             }
             // 1.2 | 1.2e3
             DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => {
-                self.token = Token::new(token::Ident(symbol1, false), ident1_span);
+                self.token = Token::new(token::Ident(symbol1, IdentIsRaw::No), ident1_span);
                 // This needs to be `Spacing::Alone` to prevent regressions.
                 // See issue #76399 and PR #76285 for more details
                 let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
                 let base1 =
                     self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
-                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
+                let next_token2 = Token::new(token::Ident(symbol2, IdentIsRaw::No), ident2_span);
                 self.bump_with((next_token2, self.token_spacing)); // `.`
                 self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
             }
@@ -1555,7 +1559,7 @@ impl<'a> Parser<'a> {
                 return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err));
             }
         };
-        let kind = if es.len() == 1 && !trailing_comma {
+        let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) {
             // `(e)` is parenthesized `e`.
             ExprKind::Paren(es.into_iter().next().unwrap())
         } else {
@@ -1946,7 +1950,7 @@ impl<'a> Parser<'a> {
         self.bump(); // `builtin`
         self.bump(); // `#`
 
-        let Some((ident, false)) = self.token.ident() else {
+        let Some((ident, IdentIsRaw::No)) = self.token.ident() else {
             let err = self.dcx().create_err(errors::ExpectedBuiltinIdent { span: self.token.span });
             return Err(err);
         };
@@ -3087,10 +3091,10 @@ impl<'a> Parser<'a> {
                 if !require_comma {
                     arm_body = Some(expr);
                     this.eat(&token::Comma);
-                    Ok(false)
+                    Ok(Recovered::No)
                 } else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
                     arm_body = Some(body);
-                    Ok(true)
+                    Ok(Recovered::Yes)
                 } else {
                     let expr_span = expr.span;
                     arm_body = Some(expr);
@@ -3171,7 +3175,7 @@ impl<'a> Parser<'a> {
                         this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
                             span: arm_span.shrink_to_hi(),
                         });
-                        return Ok(true);
+                        return Ok(Recovered::Yes);
                     }
                     Err(err)
                 });
@@ -3574,7 +3578,7 @@ impl<'a> Parser<'a> {
     fn find_struct_error_after_field_looking_code(&self) -> Option<ExprField> {
         match self.token.ident() {
             Some((ident, is_raw))
-                if (is_raw || !ident.is_reserved())
+                if (matches!(is_raw, IdentIsRaw::Yes) || !ident.is_reserved())
                     && self.look_ahead(1, |t| *t == token::Colon) =>
             {
                 Some(ast::ExprField {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 77381ef4626..2e049ca908f 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,8 +1,12 @@
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
+use super::{
+    AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing,
+    TrailingToken,
+};
 use crate::errors::{self, MacroExpandsToAdtField};
 use crate::fluent_generated as fluent;
+use ast::token::IdentIsRaw;
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, TokenKind};
@@ -1076,7 +1080,7 @@ impl<'a> Parser<'a> {
 
     fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> {
         match self.token.ident() {
-            Some((ident @ Ident { name: kw::Underscore, .. }, false)) => {
+            Some((ident @ Ident { name: kw::Underscore, .. }, IdentIsRaw::No)) => {
                 self.bump();
                 Ok(ident)
             }
@@ -1453,7 +1457,7 @@ impl<'a> Parser<'a> {
         let (variants, _) = if self.token == TokenKind::Semi {
             self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
             self.bump();
-            (thin_vec![], false)
+            (thin_vec![], Trailing::No)
         } else {
             self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span))
                 .map_err(|mut err| {
@@ -1530,10 +1534,10 @@ impl<'a> Parser<'a> {
                                 err.span_label(span, "while parsing this enum");
                                 err.help(help);
                                 err.emit();
-                                (thin_vec![], true)
+                                (thin_vec![], Recovered::Yes)
                             }
                         };
-                    VariantData::Struct { fields, recovered }
+                    VariantData::Struct { fields, recovered: recovered.into() }
                 } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
                     let body = match this.parse_tuple_struct_body() {
                         Ok(body) => body,
@@ -1618,7 +1622,7 @@ impl<'a> Parser<'a> {
                     class_name.span,
                     generics.where_clause.has_where_token,
                 )?;
-                VariantData::Struct { fields, recovered }
+                VariantData::Struct { fields, recovered: recovered.into() }
             }
         // No `where` so: `struct Foo<T>;`
         } else if self.eat(&token::Semi) {
@@ -1630,7 +1634,7 @@ impl<'a> Parser<'a> {
                 class_name.span,
                 generics.where_clause.has_where_token,
             )?;
-            VariantData::Struct { fields, recovered }
+            VariantData::Struct { fields, recovered: recovered.into() }
         // Tuple-style struct definition with optional where-clause.
         } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
@@ -1659,14 +1663,14 @@ impl<'a> Parser<'a> {
                 class_name.span,
                 generics.where_clause.has_where_token,
             )?;
-            VariantData::Struct { fields, recovered }
+            VariantData::Struct { fields, recovered: recovered.into() }
         } else if self.token == token::OpenDelim(Delimiter::Brace) {
             let (fields, recovered) = self.parse_record_struct_body(
                 "union",
                 class_name.span,
                 generics.where_clause.has_where_token,
             )?;
-            VariantData::Struct { fields, recovered }
+            VariantData::Struct { fields, recovered: recovered.into() }
         } else {
             let token_str = super::token_descr(&self.token);
             let msg = format!("expected `where` or `{{` after union name, found {token_str}");
@@ -1683,14 +1687,14 @@ impl<'a> Parser<'a> {
         adt_ty: &str,
         ident_span: Span,
         parsed_where: bool,
-    ) -> PResult<'a, (ThinVec<FieldDef>, /* recovered */ bool)> {
+    ) -> PResult<'a, (ThinVec<FieldDef>, Recovered)> {
         let mut fields = ThinVec::new();
-        let mut recovered = false;
+        let mut recovered = Recovered::No;
         if self.eat(&token::OpenDelim(Delimiter::Brace)) {
             while self.token != token::CloseDelim(Delimiter::Brace) {
                 let field = self.parse_field_def(adt_ty).map_err(|e| {
                     self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
-                    recovered = true;
+                    recovered = Recovered::Yes;
                     e
                 });
                 match field {
@@ -1962,7 +1966,7 @@ impl<'a> Parser<'a> {
         let (ident, is_raw) = self.ident_or_err(true)?;
         if ident.name == kw::Underscore {
             self.sess.gated_spans.gate(sym::unnamed_fields, lo);
-        } else if !is_raw && ident.is_reserved() {
+        } else if matches!(is_raw, IdentIsRaw::No) && ident.is_reserved() {
             let snapshot = self.create_snapshot_for_diagnostic();
             let err = if self.check_fn_front_matter(false, Case::Sensitive) {
                 let inherited_vis = Visibility {
@@ -2461,8 +2465,8 @@ impl<'a> Parser<'a> {
             // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
             // account for this.
             match self.expect_one_of(&[], &[]) {
-                Ok(true) => {}
-                Ok(false) => unreachable!(),
+                Ok(Recovered::Yes) => {}
+                Ok(Recovered::No) => unreachable!(),
                 Err(mut err) => {
                     // Qualifier keywords ordering check
                     enum WrongKw {
@@ -2740,7 +2744,7 @@ impl<'a> Parser<'a> {
     fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
         // Extract an identifier *after* having confirmed that the token is one.
         let expect_self_ident = |this: &mut Self| match this.token.ident() {
-            Some((ident, false)) => {
+            Some((ident, IdentIsRaw::No)) => {
                 this.bump();
                 ident
             }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index dea2b9e6ca7..29dd2eeb56a 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -11,6 +11,7 @@ mod stmt;
 mod ty;
 
 use crate::lexer::UnmatchedDelim;
+use ast::token::IdentIsRaw;
 pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 pub(crate) use expr::ForbiddenLetReason;
@@ -357,6 +358,25 @@ pub enum FollowedByType {
     No,
 }
 
+/// Whether a function performed recovery
+#[derive(Copy, Clone, Debug)]
+pub enum Recovered {
+    No,
+    Yes,
+}
+
+impl From<Recovered> for bool {
+    fn from(r: Recovered) -> bool {
+        matches!(r, Recovered::Yes)
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum Trailing {
+    No,
+    Yes,
+}
+
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub enum TokenDescription {
     ReservedIdentifier,
@@ -455,11 +475,11 @@ impl<'a> Parser<'a> {
     }
 
     /// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
-    pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> {
+    pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
         if self.expected_tokens.is_empty() {
             if self.token == *t {
                 self.bump();
-                Ok(false)
+                Ok(Recovered::No)
             } else {
                 self.unexpected_try_recover(t)
             }
@@ -475,13 +495,13 @@ impl<'a> Parser<'a> {
         &mut self,
         edible: &[TokenKind],
         inedible: &[TokenKind],
-    ) -> PResult<'a, bool /* recovered */> {
+    ) -> PResult<'a, Recovered> {
         if edible.contains(&self.token.kind) {
             self.bump();
-            Ok(false)
+            Ok(Recovered::No)
         } else if inedible.contains(&self.token.kind) {
             // leave it in the input
-            Ok(false)
+            Ok(Recovered::No)
         } else if self.token.kind != token::Eof
             && self.last_unexpected_token_span == Some(self.token.span)
         {
@@ -499,7 +519,7 @@ impl<'a> Parser<'a> {
     fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> {
         let (ident, is_raw) = self.ident_or_err(recover)?;
 
-        if !is_raw && ident.is_reserved() {
+        if matches!(is_raw, IdentIsRaw::No) && ident.is_reserved() {
             let err = self.expected_ident_found_err();
             if recover {
                 err.emit();
@@ -511,7 +531,7 @@ impl<'a> Parser<'a> {
         Ok(ident)
     }
 
-    fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
+    fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, IdentIsRaw)> {
         match self.token.ident() {
             Some(ident) => Ok(ident),
             None => self.expected_ident_found(recover),
@@ -568,7 +588,7 @@ impl<'a> Parser<'a> {
         }
 
         if case == Case::Insensitive
-            && let Some((ident, /* is_raw */ false)) = self.token.ident()
+            && let Some((ident, IdentIsRaw::No)) = self.token.ident()
             && ident.as_str().to_lowercase() == kw.as_str().to_lowercase()
         {
             true
@@ -598,7 +618,7 @@ impl<'a> Parser<'a> {
         }
 
         if case == Case::Insensitive
-            && let Some((ident, /* is_raw */ false)) = self.token.ident()
+            && let Some((ident, IdentIsRaw::No)) = self.token.ident()
             && ident.as_str().to_lowercase() == kw.as_str().to_lowercase()
         {
             self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() });
@@ -783,10 +803,10 @@ impl<'a> Parser<'a> {
         sep: SeqSep,
         expect: TokenExpectType,
         mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
+    ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
         let mut first = true;
-        let mut recovered = false;
-        let mut trailing = false;
+        let mut recovered = Recovered::No;
+        let mut trailing = Trailing::No;
         let mut v = ThinVec::new();
 
         while !self.expect_any_with_type(kets, expect) {
@@ -800,12 +820,12 @@ impl<'a> Parser<'a> {
                 } else {
                     // check for separator
                     match self.expect(t) {
-                        Ok(false) /* not recovered */ => {
+                        Ok(Recovered::No) => {
                             self.current_closure.take();
                         }
-                        Ok(true) /* recovered */ => {
+                        Ok(Recovered::Yes) => {
                             self.current_closure.take();
-                            recovered = true;
+                            recovered = Recovered::Yes;
                             break;
                         }
                         Err(mut expect_err) => {
@@ -900,7 +920,7 @@ impl<'a> Parser<'a> {
                 }
             }
             if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) {
-                trailing = true;
+                trailing = Trailing::Yes;
                 break;
             }
 
@@ -978,7 +998,7 @@ impl<'a> Parser<'a> {
         ket: &TokenKind,
         sep: SeqSep,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
+    ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
         self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
     }
 
@@ -990,9 +1010,9 @@ impl<'a> Parser<'a> {
         ket: &TokenKind,
         sep: SeqSep,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
+    ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
-        if !recovered {
+        if matches!(recovered, Recovered::No) {
             self.eat(ket);
         }
         Ok((val, trailing))
@@ -1007,7 +1027,7 @@ impl<'a> Parser<'a> {
         ket: &TokenKind,
         sep: SeqSep,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
+    ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         self.expect(bra)?;
         self.parse_seq_to_end(ket, sep, f)
     }
@@ -1019,7 +1039,7 @@ impl<'a> Parser<'a> {
         &mut self,
         delim: Delimiter,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
+    ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         self.parse_unspanned_seq(
             &token::OpenDelim(delim),
             &token::CloseDelim(delim),
@@ -1034,7 +1054,7 @@ impl<'a> Parser<'a> {
     fn parse_paren_comma_seq<T>(
         &mut self,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
+    ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         self.parse_delim_comma_seq(Delimiter::Parenthesis, f)
     }
 
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 071d6b72f3b..f1572a18a8b 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -201,6 +201,6 @@ impl<'a> Parser<'a> {
 
 /// The token is an identifier, but not `_`.
 /// We prohibit passing `_` to macros expecting `ident` for now.
-fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> {
+fn get_macro_ident(token: &Token) -> Option<(Ident, token::IdentIsRaw)> {
     token.ident().filter(|(ident, _)| ident.name != kw::Underscore)
 }
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 75fc013d3e6..2ede19b11e0 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,4 +1,4 @@
-use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken};
+use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, TrailingToken};
 use crate::errors::{
     self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
     DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
@@ -311,7 +311,7 @@ impl<'a> Parser<'a> {
             matches!(
                 &token.uninterpolate().kind,
                 token::FatArrow // e.g. `a | => 0,`.
-                | token::Ident(kw::If, false) // e.g. `a | if expr`.
+                | token::Ident(kw::If, token::IdentIsRaw::No) // e.g. `a | if expr`.
                 | token::Eq // e.g. `let a | = 0`.
                 | token::Semi // e.g. `let a |;`.
                 | token::Colon // e.g. `let a | :`.
@@ -696,7 +696,9 @@ impl<'a> Parser<'a> {
 
         // Here, `(pat,)` is a tuple pattern.
         // For backward compatibility, `(..)` is a tuple pattern as well.
-        Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
+        let paren_pattern =
+            fields.len() == 1 && !(matches!(trailing_comma, Trailing::Yes) || fields[0].is_rest());
+        if paren_pattern {
             let pat = fields.into_iter().next().unwrap();
             let close_paren = self.prev_token.span;
 
@@ -714,7 +716,7 @@ impl<'a> Parser<'a> {
                         },
                     });
 
-                    self.parse_pat_range_begin_with(begin.clone(), form)?
+                    self.parse_pat_range_begin_with(begin.clone(), form)
                 }
                 // recover ranges with parentheses around the `(start)..`
                 PatKind::Err(_)
@@ -729,15 +731,15 @@ impl<'a> Parser<'a> {
                         },
                     });
 
-                    self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)?
+                    self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)
                 }
 
                 // (pat) with optional parentheses
-                _ => PatKind::Paren(pat),
+                _ => Ok(PatKind::Paren(pat)),
             }
         } else {
-            PatKind::Tuple(fields)
-        })
+            Ok(PatKind::Tuple(fields))
+        }
     }
 
     /// Parse a mutable binding with the `mut` token already eaten.
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 681039999a6..6e7bbe7e06d 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -2,6 +2,7 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{Parser, Restrictions, TokenType};
 use crate::errors::PathSingleColon;
 use crate::{errors, maybe_whole};
+use ast::token::IdentIsRaw;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::{
@@ -390,7 +391,7 @@ impl<'a> Parser<'a> {
 
     pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> {
         match self.token.ident() {
-            Some((ident, false)) if ident.is_path_segment_keyword() => {
+            Some((ident, IdentIsRaw::No)) if ident.is_path_segment_keyword() => {
                 self.bump();
                 Ok(ident)
             }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 1bae5b32240..ee02b69c614 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -11,6 +11,7 @@ use crate::errors;
 use crate::maybe_whole;
 
 use crate::errors::MalformedLoopLabel;
+use crate::parser::Recovered;
 use ast::Label;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
@@ -661,7 +662,6 @@ impl<'a> Parser<'a> {
                 if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
             {
                 // Just check for errors and recover; do not eat semicolon yet.
-                // `expect_one_of` returns PResult<'a, bool /* recovered */>
 
                 let expect_result =
                     self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
@@ -669,7 +669,7 @@ impl<'a> Parser<'a> {
                 let replace_with_err = 'break_recover: {
                     match expect_result {
                         // Recover from parser, skip type error to avoid extra errors.
-                        Ok(true) => true,
+                        Ok(Recovered::Yes) => true,
                         Err(e) => {
                             if self.recover_colon_as_semi() {
                                 // recover_colon_as_semi has already emitted a nicer error.
@@ -691,7 +691,7 @@ impl<'a> Parser<'a> {
                                                     token.kind,
                                                     token::Ident(
                                                         kw::For | kw::Loop | kw::While,
-                                                        false
+                                                        token::IdentIsRaw::No
                                                     ) | token::OpenDelim(Delimiter::Brace)
                                                 )
                                         })
@@ -735,7 +735,7 @@ impl<'a> Parser<'a> {
 
                             true
                         }
-                        Ok(false) => false,
+                        Ok(Recovered::No) => false,
                     }
                 };
 
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 23a92e6dd3d..e3fe535bd5f 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,4 +1,4 @@
-use super::{Parser, PathStyle, TokenType};
+use super::{Parser, PathStyle, TokenType, Trailing};
 
 use crate::errors::{
     self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
@@ -415,7 +415,7 @@ impl<'a> Parser<'a> {
             Ok(ty)
         })?;
 
-        if ts.len() == 1 && !trailing {
+        if ts.len() == 1 && matches!(trailing, Trailing::No) {
             let ty = ts.into_iter().next().unwrap().into_inner();
             let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
             match ty.kind {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d64a3b43aad..222dd69dbc4 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1111,7 +1111,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         suggestions.extend(
                             tmp_suggestions
                                 .into_iter()
-                                .filter(|s| use_prelude || this.is_builtin_macro(s.res)),
+                                .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)),
                         );
                     }
                 }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 4583f991cab..7e7424be303 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -23,6 +23,18 @@ use Namespace::*;
 
 type Visibility = ty::Visibility<LocalDefId>;
 
+#[derive(Copy, Clone)]
+pub enum UsePrelude {
+    No,
+    Yes,
+}
+
+impl From<UsePrelude> for bool {
+    fn from(up: UsePrelude) -> bool {
+        matches!(up, UsePrelude::Yes)
+    }
+}
+
 impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// A generic scope visitor.
     /// Visits scopes in order to resolve some identifier in them or perform other actions.
@@ -32,12 +44,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         scope_set: ScopeSet<'a>,
         parent_scope: &ParentScope<'a>,
         ctxt: SyntaxContext,
-        mut visitor: impl FnMut(
-            &mut Self,
-            Scope<'a>,
-            /*use_prelude*/ bool,
-            SyntaxContext,
-        ) -> Option<T>,
+        mut visitor: impl FnMut(&mut Self, Scope<'a>, UsePrelude, SyntaxContext) -> Option<T>,
     ) -> Option<T> {
         // General principles:
         // 1. Not controlled (user-defined) names should have higher priority than controlled names
@@ -133,6 +140,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             };
 
             if visit {
+                let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No };
                 if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) {
                     return break_result;
                 }
@@ -579,7 +587,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 None,
                                 ignore_binding,
                             ) {
-                                if use_prelude || this.is_builtin_macro(binding.res()) {
+                                if matches!(use_prelude, UsePrelude::Yes)
+                                    || this.is_builtin_macro(binding.res())
+                                {
                                     result = Ok((binding, Flags::MISC_FROM_PRELUDE));
                                 }
                             }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 46472a131ff..609ab054da2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1441,6 +1441,7 @@ symbols! {
         rustc_mir,
         rustc_must_implement_one_of,
         rustc_never_returns_null_ptr,
+        rustc_no_mir_inline,
         rustc_nonnull_optimization_guaranteed,
         rustc_nounwind,
         rustc_object_lifetime_default,
diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs
index f13058ebc82..097039d6c73 100644
--- a/compiler/rustc_target/src/spec/base/apple/tests.rs
+++ b/compiler/rustc_target/src/spec/base/apple/tests.rs
@@ -14,7 +14,7 @@ fn simulator_targets_set_abi() {
         aarch64_apple_watchos_sim::target(),
     ];
 
-    for target in all_sim_targets {
+    for target in &all_sim_targets {
         assert_eq!(target.abi, "sim")
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
index 22f6ee81055..70e40f60f22 100644
--- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs
@@ -8,8 +8,7 @@ pub fn target() -> Target {
         arch: "arm".into(),
         options: TargetOptions {
             abi: "eabihf".into(),
-            // FIXME: change env to "gnu" when cfg_target_abi becomes stable
-            env: "gnueabihf".into(),
+            env: "gnu".into(),
             features: "+v6,+vfp2,-d32".into(),
             max_atomic_width: Some(64),
             mcount: "\u{1}__gnu_mcount_nc".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
index 84d9ceac04d..ca0db5e5640 100644
--- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs
@@ -8,8 +8,6 @@ pub fn target() -> Target {
         arch: "arm".into(),
         options: TargetOptions {
             abi: "eabihf".into(),
-            // FIXME: remove env when cfg_target_abi becomes stable
-            env: "eabihf".into(),
             features: "+v6,+vfp2,-d32".into(),
             max_atomic_width: Some(64),
             mcount: "__mcount".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
index 9f4a432c6fa..61b6d7a63e3 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs
@@ -8,8 +8,7 @@ pub fn target() -> Target {
         arch: "arm".into(),
         options: TargetOptions {
             abi: "eabihf".into(),
-            // FIXME: change env to "gnu" when cfg_target_abi becomes stable
-            env: "gnueabihf".into(),
+            env: "gnu".into(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
             max_atomic_width: Some(64),
             mcount: "\u{1}__gnu_mcount_nc".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
index e5518c6daec..7afdb87b62e 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs
@@ -8,8 +8,6 @@ pub fn target() -> Target {
         arch: "arm".into(),
         options: TargetOptions {
             abi: "eabihf".into(),
-            // FIXME: remove env when cfg_target_abi becomes stable
-            env: "eabihf".into(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
             max_atomic_width: Some(64),
             mcount: "__mcount".into(),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 3619d02438d..e82171de378 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -320,22 +320,25 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
         let mut errors = fulfill_cx.select_where_possible(infcx);
         errors.pop().map(|err| err.obligation)
     } else {
-        obligations.iter().cloned().find(|obligation| {
-            // We use `evaluate_root_obligation` to correctly track intercrate
-            // ambiguity clauses. We cannot use this in the new solver.
-            let evaluation_result = selcx.evaluate_root_obligation(obligation);
-
-            match evaluation_result {
-                Ok(result) => !result.may_apply(),
-                // If overflow occurs, we need to conservatively treat the goal as possibly holding,
-                // since there can be instantiations of this goal that don't overflow and result in
-                // success. This isn't much of a problem in the old solver, since we treat overflow
-                // fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
-                // but in the new solver, this is very important for correctness, since overflow
-                // *must* be treated as ambiguity for completeness.
-                Err(_overflow) => false,
-            }
-        })
+        obligations
+            .iter()
+            .find(|obligation| {
+                // We use `evaluate_root_obligation` to correctly track intercrate
+                // ambiguity clauses. We cannot use this in the new solver.
+                let evaluation_result = selcx.evaluate_root_obligation(obligation);
+
+                match evaluation_result {
+                    Ok(result) => !result.may_apply(),
+                    // If overflow occurs, we need to conservatively treat the goal as possibly holding,
+                    // since there can be instantiations of this goal that don't overflow and result in
+                    // success. This isn't much of a problem in the old solver, since we treat overflow
+                    // fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
+                    // but in the new solver, this is very important for correctness, since overflow
+                    // *must* be treated as ambiguity for completeness.
+                    Err(_overflow) => false,
+                }
+            })
+            .cloned()
     }
 }
 
@@ -598,9 +601,24 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
     trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
 }
 
+#[derive(Debug, Copy, Clone)]
+pub enum IsFirstInputType {
+    No,
+    Yes,
+}
+
+impl From<bool> for IsFirstInputType {
+    fn from(b: bool) -> IsFirstInputType {
+        match b {
+            false => IsFirstInputType::No,
+            true => IsFirstInputType::Yes,
+        }
+    }
+}
+
 #[derive(Debug)]
 pub enum OrphanCheckErr<'tcx> {
-    NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>),
+    NonLocalInputType(Vec<(Ty<'tcx>, IsFirstInputType)>),
     UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
 }
 
@@ -751,7 +769,7 @@ struct OrphanChecker<'tcx, F> {
     /// Ignore orphan check failures and exclusively search for the first
     /// local type.
     search_first_local_ty: bool,
-    non_local_tys: Vec<(Ty<'tcx>, bool)>,
+    non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>,
 }
 
 impl<'tcx, F, E> OrphanChecker<'tcx, F>
@@ -769,7 +787,7 @@ where
     }
 
     fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
-        self.non_local_tys.push((t, self.in_self_ty));
+        self.non_local_tys.push((t, self.in_self_ty.into()));
         ControlFlow::Continue(())
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 9eec60ea06c..32447aca390 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -42,7 +42,7 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
-pub use self::coherence::{OrphanCheckErr, OverlapResult};
+pub use self::coherence::{IsFirstInputType, OrphanCheckErr, OverlapResult};
 pub use self::engine::{ObligationCtxt, TraitEngineExt};
 pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
 pub use self::normalize::NormalizeExt;
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index 6272f793f40..0f7d8d7e083 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -208,7 +208,7 @@ where
     if TLV.is_set() {
         Err(Error::from("StableMIR already running"))
     } else {
-        let ptr: *const () = &context as *const &_ as _;
+        let ptr: *const () = std::ptr::addr_of!(context) as _;
         TLV.set(&Cell::new(ptr), || Ok(f()))
     }
 }
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 3b29c144a89..0421a12b3a9 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -176,7 +176,7 @@ impl<T: ?Sized> ThinBox<T> {
 
     fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> {
         // SAFETY: both types are transparent to `NonNull<u8>`
-        unsafe { &*((&self.ptr) as *const WithOpaqueHeader as *const WithHeader<_>) }
+        unsafe { &*(core::ptr::addr_of!(self.ptr) as *const WithHeader<_>) }
     }
 }
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index b84273848ee..45e93feb6c5 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -92,6 +92,7 @@
 #![warn(multiple_supertrait_upcastable)]
 #![allow(internal_features)]
 #![allow(rustdoc::redundant_explicit_links)]
+#![deny(ffi_unwind_calls)]
 //
 // Library features:
 // tidy-alphabetical-start
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index c3d0019be39..084157b97ab 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1969,7 +1969,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
 
             // Copy value as bytes
             ptr::copy_nonoverlapping(
-                &*src as *const T as *const u8,
+                core::ptr::addr_of!(*src) as *const u8,
                 ptr::addr_of_mut!((*ptr).value) as *mut u8,
                 value_size,
             );
@@ -2440,7 +2440,7 @@ impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for Rc<T, A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized, A: Allocator> fmt::Pointer for Rc<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Pointer::fmt(&(&**self as *const T), f)
+        fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f)
     }
 }
 
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 524aa35e045..00f47f5c6e0 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1914,7 +1914,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
 
             // Copy value as bytes
             ptr::copy_nonoverlapping(
-                &*src as *const T as *const u8,
+                core::ptr::addr_of!(*src) as *const u8,
                 ptr::addr_of_mut!((*ptr).data) as *mut u8,
                 value_size,
             );
@@ -3265,7 +3265,7 @@ impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for Arc<T, A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized, A: Allocator> fmt::Pointer for Arc<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Pointer::fmt(&(&**self as *const T), f)
+        fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f)
     }
 }
 
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 248943cf022..20186a2de0f 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -4,6 +4,7 @@ use crate::ffi::c_char;
 use crate::fmt;
 use crate::intrinsics;
 use crate::ops;
+use crate::ptr::addr_of;
 use crate::slice;
 use crate::slice::memchr;
 use crate::str;
@@ -603,7 +604,7 @@ impl CStr {
     pub const fn to_bytes_with_nul(&self) -> &[u8] {
         // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
         // is safe on all supported targets.
-        unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
+        unsafe { &*(addr_of!(self.inner) as *const [u8]) }
     }
 
     /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index e42b2315ea5..f9d89795a99 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2706,13 +2706,25 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
 macro_rules! assert_unsafe_precondition {
     ($message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
         {
+            // #[cfg(bootstrap)] (this comment)
             // When the standard library is compiled with debug assertions, we want the check to inline for better performance.
             // This is important when working on the compiler, which is compiled with debug assertions locally.
             // When not compiled with debug assertions (so the precompiled std) we outline the check to minimize the compile
             // time impact when debug assertions are disabled.
-            // It is not clear whether that is the best solution, see #120848.
-            #[cfg_attr(debug_assertions, inline(always))]
-            #[cfg_attr(not(debug_assertions), inline(never))]
+            // The proper solution to this is the `#[rustc_no_mir_inline]` below, but we still want decent performance for cfg(bootstrap).
+            #[cfg_attr(all(debug_assertions, bootstrap), inline(always))]
+            #[cfg_attr(all(not(debug_assertions), bootstrap), inline(never))]
+
+            // This check is inlineable, but not by the MIR inliner.
+            // The reason for this is that the MIR inliner is in an exceptionally bad position
+            // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
+            // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
+            // would be bad for compile times.
+            //
+            // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
+            // inlining the check. If it's `true`, it can inline it and get significantly better performance.
+            #[cfg_attr(not(bootstrap), rustc_no_mir_inline)]
+            #[cfg_attr(not(bootstrap), inline)]
             #[rustc_nounwind]
             fn precondition_check($($name:$ty),*) {
                 if !$e {
diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs
index 64bd5b3e2b6..1a5f9e62654 100644
--- a/library/core/src/iter/adapters/filter_map.rs
+++ b/library/core/src/iter/adapters/filter_map.rs
@@ -2,6 +2,7 @@ use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedF
 use crate::mem::{ManuallyDrop, MaybeUninit};
 use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
+use crate::ptr::addr_of;
 use crate::{array, fmt};
 
 /// An iterator that uses `f` to both filter and map elements from `iter`.
@@ -98,9 +99,8 @@ where
             // SAFETY: Loop conditions ensure the index is in bounds.
 
             unsafe {
-                let opt_payload_at: *const MaybeUninit<B> = (&val as *const Option<B>)
-                    .byte_add(core::mem::offset_of!(Option<B>, Some.0))
-                    .cast();
+                let opt_payload_at: *const MaybeUninit<B> =
+                    addr_of!(val).byte_add(core::mem::offset_of!(Option<B>, Some.0)).cast();
                 let dst = guard.array.as_mut_ptr().add(idx);
                 crate::ptr::copy_nonoverlapping(opt_payload_at, dst, 1);
                 crate::mem::forget(val);
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 456d88122af..49cead680e3 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -106,6 +106,7 @@
 #![allow(incomplete_features)]
 #![warn(multiple_supertrait_upcastable)]
 #![allow(internal_features)]
+#![deny(ffi_unwind_calls)]
 // Do not check link redundancy on bootstraping phase
 #![allow(rustdoc::redundant_explicit_links)]
 //
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 90b3341f0ad..fc5b08c9801 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1553,7 +1553,7 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
     // `dst` cannot overlap `src` because the caller has mutable access
     // to `dst` while `src` is owned by this function.
     unsafe {
-        copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::<T>());
+        copy_nonoverlapping(addr_of!(src) as *const u8, dst as *mut u8, mem::size_of::<T>());
         // We are calling the intrinsic directly to avoid function calls in the generated code.
         intrinsics::forget(src);
     }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 031666fb012..1ad81fcfcfe 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -146,6 +146,9 @@ impl<T> [T] {
     /// ```
     /// let a = [1, 2, 3];
     /// assert!(!a.is_empty());
+    ///
+    /// let b: &[i32] = &[];
+    /// assert!(b.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")]
@@ -185,6 +188,9 @@ impl<T> [T] {
     ///     *first = 5;
     /// }
     /// assert_eq!(x, &[5, 1, 2]);
+    ///
+    /// let y: &mut [i32] = &mut [];
+    /// assert_eq!(None, y.first_mut());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")]
@@ -297,7 +303,7 @@ impl<T> [T] {
         if let [.., last] = self { Some(last) } else { None }
     }
 
-    /// Returns a mutable reference to the last item in the slice.
+    /// Returns a mutable reference to the last item in the slice, or `None` if it is empty.
     ///
     /// # Examples
     ///
@@ -308,6 +314,9 @@ impl<T> [T] {
     ///     *last = 10;
     /// }
     /// assert_eq!(x, &[0, 1, 10]);
+    ///
+    /// let y: &mut [i32] = &mut [];
+    /// assert_eq!(None, y.last_mut());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index d05458a6944..610966625b5 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -36,6 +36,7 @@
 #![feature(strict_provenance)]
 #![recursion_limit = "256"]
 #![allow(internal_features)]
+#![deny(ffi_unwind_calls)]
 
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index 6c99e8c3620..9757653e02c 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -21,7 +21,7 @@ mod libc {
 fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
     // Work with an actual instance of the type since using a null pointer is UB
     let base = (addr as *const libc::sockaddr_un).addr();
-    let path = (&addr.sun_path as *const libc::c_char).addr();
+    let path = core::ptr::addr_of!(addr.sun_path).addr();
     path - base
 }
 
@@ -98,7 +98,7 @@ impl SocketAddr {
         unsafe {
             let mut addr: libc::sockaddr_un = mem::zeroed();
             let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
-            cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
+            cvt(f(core::ptr::addr_of_mut!(addr) as *mut _, &mut len))?;
             SocketAddr::from_parts(addr, len)
         }
     }
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
index 218536689fd..1d279d6adbc 100644
--- a/library/std/src/os/unix/net/ancillary.rs
+++ b/library/std/src/os/unix/net/ancillary.rs
@@ -37,7 +37,7 @@ pub(super) fn recv_vectored_with_ancillary_from(
     unsafe {
         let mut msg_name: libc::sockaddr_un = zeroed();
         let mut msg: libc::msghdr = zeroed();
-        msg.msg_name = &mut msg_name as *mut _ as *mut _;
+        msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _;
         msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
         msg.msg_iov = bufs.as_mut_ptr().cast();
         msg.msg_iovlen = bufs.len() as _;
@@ -70,7 +70,7 @@ pub(super) fn send_vectored_with_ancillary_to(
             if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
 
         let mut msg: libc::msghdr = zeroed();
-        msg.msg_name = &mut msg_name as *mut _ as *mut _;
+        msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _;
         msg.msg_namelen = msg_namelen;
         msg.msg_iov = bufs.as_ptr() as *mut _;
         msg.msg_iovlen = bufs.len() as _;
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 3b7b610fdf9..0b4d955294c 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -91,7 +91,7 @@ impl UnixDatagram {
             let socket = UnixDatagram::unbound()?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+            cvt(libc::bind(socket.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len as _))?;
 
             Ok(socket)
         }
@@ -124,7 +124,7 @@ impl UnixDatagram {
             let socket = UnixDatagram::unbound()?;
             cvt(libc::bind(
                 socket.as_raw_fd(),
-                &socket_addr.addr as *const _ as *const _,
+                core::ptr::addr_of!(socket_addr.addr) as *const _,
                 socket_addr.len as _,
             ))?;
             Ok(socket)
@@ -206,7 +206,7 @@ impl UnixDatagram {
         unsafe {
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?;
+            cvt(libc::connect(self.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?;
         }
         Ok(())
     }
@@ -238,7 +238,7 @@ impl UnixDatagram {
         unsafe {
             cvt(libc::connect(
                 self.as_raw_fd(),
-                &socket_addr.addr as *const _ as *const _,
+                core::ptr::addr_of!(socket_addr.addr) as *const _,
                 socket_addr.len,
             ))?;
         }
@@ -505,7 +505,7 @@ impl UnixDatagram {
                 buf.as_ptr() as *const _,
                 buf.len(),
                 MSG_NOSIGNAL,
-                &addr as *const _ as *const _,
+                core::ptr::addr_of!(addr) as *const _,
                 len,
             ))?;
             Ok(count as usize)
@@ -540,7 +540,7 @@ impl UnixDatagram {
                 buf.as_ptr() as *const _,
                 buf.len(),
                 MSG_NOSIGNAL,
-                &socket_addr.addr as *const _ as *const _,
+                core::ptr::addr_of!(socket_addr.addr) as *const _,
                 socket_addr.len,
             ))?;
             Ok(count as usize)
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index d64a43bc20b..31286a906ea 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -99,7 +99,11 @@ impl UnixListener {
             )))]
             const backlog: libc::c_int = libc::SOMAXCONN;
 
-            cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
+            cvt(libc::bind(
+                inner.as_inner().as_raw_fd(),
+                core::ptr::addr_of!(addr) as *const _,
+                len as _,
+            ))?;
             cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
 
             Ok(UnixListener(inner))
@@ -139,7 +143,7 @@ impl UnixListener {
             const backlog: libc::c_int = 128;
             cvt(libc::bind(
                 inner.as_raw_fd(),
-                &socket_addr.addr as *const _ as *const _,
+                core::ptr::addr_of!(socket_addr.addr) as *const _,
                 socket_addr.len as _,
             ))?;
             cvt(libc::listen(inner.as_raw_fd(), backlog))?;
@@ -174,7 +178,7 @@ impl UnixListener {
     pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
         let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
         let mut len = mem::size_of_val(&storage) as libc::socklen_t;
-        let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+        let sock = self.0.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?;
         let addr = SocketAddr::from_parts(storage, len)?;
         Ok((UnixStream(sock), addr))
     }
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index e117f616caf..b1cd504e219 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -96,7 +96,7 @@ impl UnixStream {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
 
-            cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?;
+            cvt(libc::connect(inner.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?;
             Ok(UnixStream(inner))
         }
     }
@@ -130,7 +130,7 @@ impl UnixStream {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             cvt(libc::connect(
                 inner.as_raw_fd(),
-                &socket_addr.addr as *const _ as *const _,
+                core::ptr::addr_of!(socket_addr.addr) as *const _,
                 socket_addr.len,
             ))?;
             Ok(UnixStream(inner))
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
index 6a0cc2d2c48..6efa74182cc 100644
--- a/library/std/src/os/unix/ucred.rs
+++ b/library/std/src/os/unix/ucred.rs
@@ -62,7 +62,7 @@ pub mod impl_linux {
                 socket.as_raw_fd(),
                 SOL_SOCKET,
                 SO_PEERCRED,
-                &mut ucred as *mut ucred as *mut c_void,
+                core::ptr::addr_of_mut!(ucred) as *mut c_void,
                 &mut ucred_size,
             );
 
@@ -122,7 +122,7 @@ pub mod impl_mac {
                 socket.as_raw_fd(),
                 SOL_LOCAL,
                 LOCAL_PEERPID,
-                &mut pid as *mut pid_t as *mut c_void,
+                core::ptr::addr_of_mut!(pid) as *mut c_void,
                 &mut pid_size,
             );
 
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 66b4ec37c8e..ef701d3867a 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -502,7 +502,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     // method of calling a catch panic whilst juggling ownership.
     let mut data = Data { f: ManuallyDrop::new(f) };
 
-    let data_ptr = &mut data as *mut _ as *mut u8;
+    let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8;
     // SAFETY:
     //
     // Access to the union's fields: this is `std` and we know that the `r#try`
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index f6a7c0a9f75..ca62179e95b 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -165,6 +165,8 @@ pub use core::sync::Exclusive;
 pub use self::barrier::{Barrier, BarrierWaitResult};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::condvar::{Condvar, WaitTimeoutResult};
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+pub use self::mutex::MappedMutexGuard;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::mutex::{Mutex, MutexGuard};
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -172,6 +174,8 @@ pub use self::mutex::{Mutex, MutexGuard};
 pub use self::once::{Once, OnceState, ONCE_INIT};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult};
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
 
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index 33f768dcbe9..1b82713edc7 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -182,7 +182,11 @@ impl<T> Channel<T> {
             // Prepare for blocking until a receiver wakes us up.
             let oper = Operation::hook(token);
             let mut packet = Packet::<T>::message_on_stack(msg);
-            inner.senders.register_with_packet(oper, &mut packet as *mut Packet<T> as *mut (), cx);
+            inner.senders.register_with_packet(
+                oper,
+                core::ptr::addr_of_mut!(packet) as *mut (),
+                cx,
+            );
             inner.receivers.notify();
             drop(inner);
 
@@ -251,7 +255,7 @@ impl<T> Channel<T> {
             let mut packet = Packet::<T>::empty_on_stack();
             inner.receivers.register_with_packet(
                 oper,
-                &mut packet as *mut Packet<T> as *mut (),
+                core::ptr::addr_of_mut!(packet) as *mut (),
                 cx,
             );
             inner.senders.notify();
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 920143b7ac7..fa91f9d907a 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -3,7 +3,10 @@ mod tests;
 
 use crate::cell::UnsafeCell;
 use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::ManuallyDrop;
 use crate::ops::{Deref, DerefMut};
+use crate::ptr::NonNull;
 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
 use crate::sys::locks as sys;
 
@@ -213,6 +216,47 @@ impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
 #[stable(feature = "mutexguard", since = "1.19.0")]
 unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
 
+/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
+/// subfield of the protected data. When this structure is dropped (falls out
+/// of scope), the lock will be unlocked.
+///
+/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the
+/// former cannot be used with [`Condvar`], since that
+/// could introduce soundness issues if the locked object is modified by another
+/// thread while the `Mutex` is unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`map`] and [`try_map`] methods on
+/// [`MutexGuard`].
+///
+/// [`map`]: MutexGuard::map
+/// [`try_map`]: MutexGuard::try_map
+/// [`Condvar`]: crate::sync::Condvar
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MappedMutexGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+#[clippy::has_significant_drop]
+pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
+    // `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
+    // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
+    // below for the correct variance over `T` (invariance).
+    data: NonNull<T>,
+    inner: &'a sys::Mutex,
+    poison_flag: &'a poison::Flag,
+    poison: poison::Guard,
+    _variance: PhantomData<&'a mut T>,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
+
 impl<T> Mutex<T> {
     /// Creates a new mutex in an unlocked state ready for use.
     ///
@@ -550,3 +594,178 @@ pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
 pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
     &guard.lock.poison
 }
+
+impl<'a, T: ?Sized> MutexGuard<'a, T> {
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MutexGuard::map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedMutexGuard {
+            data,
+            inner: &orig.lock.inner,
+            poison_flag: &orig.lock.poison,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MutexGuard::try_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { &mut *orig.lock.data.get() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedMutexGuard {
+                    data,
+                    inner: &orig.lock.inner,
+                    poison_flag: &orig.lock.poison,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { self.data.as_mut() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.poison_flag.done(&self.poison);
+            self.inner.unlock();
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedMutexGuard {
+            data,
+            inner: orig.inner,
+            poison_flag: orig.poison_flag,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedMutexGuard::try_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_mut() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedMutexGuard {
+                    data,
+                    inner: orig.inner,
+                    poison_flag: orig.poison_flag,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs
index 1786a3c09ff..19ec096c593 100644
--- a/library/std/src/sync/mutex/tests.rs
+++ b/library/std/src/sync/mutex/tests.rs
@@ -1,6 +1,6 @@
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::mpsc::channel;
-use crate::sync::{Arc, Condvar, Mutex};
+use crate::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
 use crate::thread;
 
 struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
@@ -189,6 +189,21 @@ fn test_mutex_arc_poison() {
 }
 
 #[test]
+fn test_mutex_arc_poison_mapped() {
+    let arc = Arc::new(Mutex::new(1));
+    assert!(!arc.is_poisoned());
+    let arc2 = arc.clone();
+    let _ = thread::spawn(move || {
+        let lock = arc2.lock().unwrap();
+        let lock = MutexGuard::map(lock, |val| val);
+        assert_eq!(*lock, 2); // deliberate assertion failure to poison the mutex
+    })
+    .join();
+    assert!(arc.lock().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
 fn test_mutex_arc_nested() {
     // Tests nested mutexes and access
     // to underlying data.
@@ -236,3 +251,77 @@ fn test_mutex_unsized() {
     let comp: &[i32] = &[4, 2, 5];
     assert_eq!(&*mutex.lock().unwrap(), comp);
 }
+
+#[test]
+fn test_mapping_mapped_guard() {
+    let arr = [0; 4];
+    let mut lock = Mutex::new(arr);
+    let guard = lock.lock().unwrap();
+    let guard = MutexGuard::map(guard, |arr| &mut arr[..2]);
+    let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]);
+    assert_eq!(guard.len(), 1);
+    guard[0] = 42;
+    drop(guard);
+    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
+}
+
+#[test]
+fn panic_while_mapping_unlocked_poison() {
+    let lock = Mutex::new(());
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let _guard = MutexGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MutexGuard::map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MutexGuard::map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MutexGuard::try_map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let guard = MutexGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedMutexGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MappedMutexGuard::map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MappedMutexGuard::map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.lock().unwrap();
+        let guard = MutexGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_lock() {
+        Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    drop(lock);
+}
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index 1e978bec4b4..3c51389fa34 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -78,6 +78,7 @@ impl Flag {
     }
 }
 
+#[derive(Clone)]
 pub struct Guard {
     #[cfg(panic = "unwind")]
     panicking: bool,
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index c5d846b85aa..0b3d25c3298 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -3,6 +3,8 @@ mod tests;
 
 use crate::cell::UnsafeCell;
 use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::ManuallyDrop;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr::NonNull;
 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
@@ -105,7 +107,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
 #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")]
 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
     // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
-    // `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
+    // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
     // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
     // is preferable over `const* T` to allow for niche optimization.
     data: NonNull<T>,
@@ -144,6 +146,67 @@ impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
 #[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
 unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
 
+/// RAII structure used to release the shared read access of a lock when
+/// dropped, which can point to a subfield of the protected data.
+///
+/// This structure is created by the [`map`] and [`try_map`] methods
+/// on [`RwLockReadGuard`].
+///
+/// [`map`]: RwLockReadGuard::map
+/// [`try_map`]: RwLockReadGuard::try_map
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+#[clippy::has_significant_drop]
+pub struct MappedRwLockReadGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
+    // `MappedRwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops.
+    // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull`
+    // is preferable over `const* T` to allow for niche optimization.
+    data: NonNull<T>,
+    inner_lock: &'a sys::RwLock,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> !Send for MappedRwLockReadGuard<'_, T> {}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {}
+
+/// RAII structure used to release the exclusive write access of a lock when
+/// dropped, which can point to a subfield of the protected data.
+///
+/// This structure is created by the [`map`] and [`try_map`] methods
+/// on [`RwLockWriteGuard`].
+///
+/// [`map`]: RwLockWriteGuard::map
+/// [`try_map`]: RwLockWriteGuard::try_map
+#[must_use = "if unused the RwLock will immediately unlock"]
+#[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Future's to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+#[clippy::has_significant_drop]
+pub struct MappedRwLockWriteGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
+    // `MappedRwLockWriteGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
+    // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
+    // below for the correct variance over `T` (invariance).
+    data: NonNull<T>,
+    inner_lock: &'a sys::RwLock,
+    poison_flag: &'a poison::Flag,
+    poison: poison::Guard,
+    _variance: PhantomData<&'a mut T>,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {}
+
 impl<T> RwLock<T> {
     /// Creates a new instance of an `RwLock<T>` which is unlocked.
     ///
@@ -557,12 +620,40 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
     }
 }
 
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
     type Target = T;
 
     fn deref(&self) -> &T {
-        // SAFETY: the conditions of `RwLockGuard::new` were satisfied when created.
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created.
         unsafe { self.data.as_ref() }
     }
 }
@@ -585,6 +676,37 @@ impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
     }
 }
 
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe { self.data.as_mut() }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
     fn drop(&mut self) {
@@ -605,3 +727,310 @@ impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
         }
     }
 }
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe {
+            self.inner_lock.read_unlock();
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> {
+    fn drop(&mut self) {
+        self.poison_flag.done(&self.poison);
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        unsafe {
+            self.inner_lock.write_unlock();
+        }
+    }
+}
+
+impl<'a, T: ?Sized> RwLockReadGuard<'a, T> {
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockReadGuard::map(...)`. A method would interfere with methods of
+    /// the same name on the contents of the `RwLockReadGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
+    where
+        F: FnOnce(&T) -> &U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_ref() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }
+    }
+
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockReadGuard::try_map(...)`. A method would interfere with methods
+    /// of the same name on the contents of the `RwLockReadGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
+    where
+        F: FnOnce(&T) -> Option<&U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_ref() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> {
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data,
+    /// e.g. an enum variant.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockReadGuard::map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockReadGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U>
+    where
+        F: FnOnce(&T) -> &U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_ref() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }
+    }
+
+    /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data.
+    /// The original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for reading, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockReadGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self>
+    where
+        F: FnOnce(&T) -> Option<&U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_ref() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockWriteGuard::map(...)`. A method would interfere with methods of
+    /// the same name on the contents of the `RwLockWriteGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockWriteGuard {
+            data,
+            inner_lock: &orig.lock.inner,
+            poison_flag: &orig.lock.poison,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods
+    /// of the same name on the contents of the `RwLockWriteGuard` used through
+    /// `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { &mut *orig.lock.data.get() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockWriteGuard {
+                    data,
+                    inner_lock: &orig.lock.inner,
+                    poison_flag: &orig.lock.poison,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> {
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data,
+    /// e.g. an enum variant.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockWriteGuard::map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockWriteGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedRwLockWriteGuard {
+            data,
+            inner_lock: orig.inner_lock,
+            poison_flag: orig.poison_flag,
+            poison: orig.poison.clone(),
+            _variance: PhantomData,
+        }
+    }
+
+    /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data.
+    /// The original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `RwLock` is already locked for writing, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with
+    /// methods of the same name on the contents of the `MappedRwLockWriteGuard`
+    /// used through `Deref`.
+    ///
+    /// # Panics
+    ///
+    /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned.
+    #[doc(alias = "filter_map")]
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `try_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_mut() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedRwLockWriteGuard {
+                    data,
+                    inner_lock: orig.inner_lock,
+                    poison_flag: orig.poison_flag,
+                    poison: orig.poison.clone(),
+                    _variance: PhantomData,
+                })
+            }
+            None => Err(orig),
+        }
+    }
+}
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index 1a9d3d3f12f..9cc5e7a3a60 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -1,6 +1,9 @@
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::mpsc::channel;
-use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError};
+use crate::sync::{
+    Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
+    TryLockError,
+};
 use crate::thread;
 use rand::Rng;
 
@@ -56,6 +59,19 @@ fn test_rw_arc_poison_wr() {
 }
 
 #[test]
+fn test_rw_arc_poison_mapped_w_r() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.write().unwrap();
+        let _lock = RwLockWriteGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    assert!(arc.read().is_err());
+}
+
+#[test]
 fn test_rw_arc_poison_ww() {
     let arc = Arc::new(RwLock::new(1));
     assert!(!arc.is_poisoned());
@@ -70,6 +86,20 @@ fn test_rw_arc_poison_ww() {
 }
 
 #[test]
+fn test_rw_arc_poison_mapped_w_w() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.write().unwrap();
+        let _lock = RwLockWriteGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    assert!(arc.write().is_err());
+    assert!(arc.is_poisoned());
+}
+
+#[test]
 fn test_rw_arc_no_poison_rr() {
     let arc = Arc::new(RwLock::new(1));
     let arc2 = arc.clone();
@@ -81,6 +111,21 @@ fn test_rw_arc_no_poison_rr() {
     let lock = arc.read().unwrap();
     assert_eq!(*lock, 1);
 }
+
+#[test]
+fn test_rw_arc_no_poison_mapped_r_r() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.read().unwrap();
+        let _lock = RwLockReadGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    let lock = arc.read().unwrap();
+    assert_eq!(*lock, 1);
+}
+
 #[test]
 fn test_rw_arc_no_poison_rw() {
     let arc = Arc::new(RwLock::new(1));
@@ -95,6 +140,20 @@ fn test_rw_arc_no_poison_rw() {
 }
 
 #[test]
+fn test_rw_arc_no_poison_mapped_r_w() {
+    let arc = Arc::new(RwLock::new(1));
+    let arc2 = arc.clone();
+    let _: Result<(), _> = thread::spawn(move || {
+        let lock = arc2.read().unwrap();
+        let _lock = RwLockReadGuard::map(lock, |val| val);
+        panic!();
+    })
+    .join();
+    let lock = arc.write().unwrap();
+    assert_eq!(*lock, 1);
+}
+
+#[test]
 fn test_rw_arc() {
     let arc = Arc::new(RwLock::new(0));
     let arc2 = arc.clone();
@@ -179,6 +238,16 @@ fn test_rwlock_try_write() {
     }
 
     drop(read_guard);
+    let mapped_read_guard = RwLockReadGuard::map(lock.read().unwrap(), |_| &());
+
+    let write_result = lock.try_write();
+    match write_result {
+        Err(TryLockError::WouldBlock) => (),
+        Ok(_) => assert!(false, "try_write should not succeed while mapped_read_guard is in scope"),
+        Err(_) => assert!(false, "unexpected error"),
+    }
+
+    drop(mapped_read_guard);
 }
 
 #[test]
@@ -257,3 +326,173 @@ fn test_read_guard_covariance() {
     }
     drop(lock);
 }
+
+#[test]
+fn test_mapped_read_guard_covariance() {
+    fn do_stuff<'a>(_: MappedRwLockReadGuard<'_, &'a i32>, _: &'a i32) {}
+    let j: i32 = 5;
+    let lock = RwLock::new((&j, &j));
+    {
+        let i = 6;
+        let guard = lock.read().unwrap();
+        let guard = RwLockReadGuard::map(guard, |(val, _val)| val);
+        do_stuff(guard, &i);
+    }
+    drop(lock);
+}
+
+#[test]
+fn test_mapping_mapped_guard() {
+    let arr = [0; 4];
+    let mut lock = RwLock::new(arr);
+    let guard = lock.write().unwrap();
+    let guard = RwLockWriteGuard::map(guard, |arr| &mut arr[..2]);
+    let mut guard = MappedRwLockWriteGuard::map(guard, |slice| &mut slice[1..]);
+    assert_eq!(guard.len(), 1);
+    guard[0] = 42;
+    drop(guard);
+    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
+
+    let guard = lock.read().unwrap();
+    let guard = RwLockReadGuard::map(guard, |arr| &arr[..2]);
+    let guard = MappedRwLockReadGuard::map(guard, |slice| &slice[1..]);
+    assert_eq!(*guard, [42]);
+    drop(guard);
+    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
+}
+
+#[test]
+fn panic_while_mapping_read_unlocked_no_poison() {
+    let lock = RwLock::new(());
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let _guard = RwLockReadGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockReadGuard::map closure should release the read lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {
+            panic!("panicking in a RwLockReadGuard::map closure should not poison the RwLock")
+        }
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {
+            panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock")
+        }
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockReadGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a MappedRwLockReadGuard::map closure should release the read lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {
+            panic!("panicking in a MappedRwLockReadGuard::map closure should not poison the RwLock")
+        }
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.read().unwrap();
+        let guard = RwLockReadGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {}
+        Err(TryLockError::WouldBlock) => panic!(
+            "panicking in a MappedRwLockReadGuard::try_map closure should release the read lock"
+        ),
+        Err(TryLockError::Poisoned(_)) => panic!(
+            "panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock"
+        ),
+    }
+
+    drop(lock);
+}
+
+#[test]
+fn panic_while_mapping_write_unlocked_poison() {
+    let lock = RwLock::new(());
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let _guard = RwLockWriteGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => panic!("panicking in a RwLockWriteGuard::map closure should poison the RwLock"),
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockWriteGuard::map closure should release the write lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {
+            panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock")
+        }
+        Err(TryLockError::WouldBlock) => {
+            panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock")
+        }
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockWriteGuard::map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => {
+            panic!("panicking in a MappedRwLockWriteGuard::map closure should poison the RwLock")
+        }
+        Err(TryLockError::WouldBlock) => panic!(
+            "panicking in a MappedRwLockWriteGuard::map closure should release the write lock"
+        ),
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    let _ = crate::panic::catch_unwind(|| {
+        let guard = lock.write().unwrap();
+        let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val);
+        let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!());
+    });
+
+    match lock.try_write() {
+        Ok(_) => panic!(
+            "panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock"
+        ),
+        Err(TryLockError::WouldBlock) => panic!(
+            "panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock"
+        ),
+        Err(TryLockError::Poisoned(_)) => {}
+    }
+
+    drop(lock);
+}
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs
index 871a2ccdfa4..1c53796f5d4 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/pal/hermit/net.rs
@@ -207,7 +207,7 @@ impl Socket {
                 buf.as_mut_ptr(),
                 buf.len(),
                 flags,
-                &mut storage as *mut _ as *mut _,
+                core::ptr::addr_of_mut!(storage) as *mut _,
                 &mut addrlen,
             )
         })?;
@@ -323,7 +323,7 @@ impl Socket {
             netc::ioctl(
                 self.as_raw_fd(),
                 netc::FIONBIO,
-                &mut nonblocking as *mut _ as *mut core::ffi::c_void,
+                core::ptr::addr_of_mut!(nonblocking) as *mut core::ffi::c_void,
             )
         })
         .map(drop)
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index b0e9634d229..f289dafd8bc 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -100,7 +100,7 @@ pub struct Instant(Timespec);
 impl Instant {
     pub fn now() -> Instant {
         let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
+        let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) };
 
         Instant(time)
     }
@@ -197,7 +197,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
 impl SystemTime {
     pub fn now() -> SystemTime {
         let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
+        let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
 
         SystemTime(time)
     }
diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
index 6762a43b483..8a9ea4ac00d 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
@@ -95,7 +95,7 @@ impl Tls {
     #[allow(unused)]
     pub unsafe fn activate_persistent(self: Box<Self>) {
         // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
-        unsafe { set_tls_ptr((&*self) as *const Tls as _) };
+        unsafe { set_tls_ptr(core::ptr::addr_of!(*self) as _) };
         mem::forget(self);
     }
 
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index c75323ef775..086cdfe6e94 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -1344,7 +1344,7 @@ impl File {
                 }
                 cvt(unsafe { libc::fsetattrlist(
                     self.as_raw_fd(),
-                    (&attrlist as *const libc::attrlist).cast::<libc::c_void>().cast_mut(),
+                    core::ptr::addr_of!(attrlist).cast::<libc::c_void>().cast_mut(),
                     buf.as_ptr().cast::<libc::c_void>().cast_mut(),
                     num_times * mem::size_of::<libc::timespec>(),
                     0
@@ -1744,7 +1744,7 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)>
 #[cfg(target_os = "espidf")]
 fn open_to_and_set_permissions(
     to: &Path,
-    reader_metadata: crate::fs::Metadata,
+    _reader_metadata: crate::fs::Metadata,
 ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> {
     use crate::fs::OpenOptions;
     let writer = OpenOptions::new().open(to)?;
@@ -1918,7 +1918,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         copyfile_state_get(
             state.0,
             COPYFILE_STATE_COPIED,
-            &mut bytes_copied as *mut libc::off_t as *mut libc::c_void,
+            core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void,
         )
     })?;
     Ok(bytes_copied as u64)
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 04b8c5ca916..23287258f2f 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -38,7 +38,7 @@ pub mod thread_parking;
 pub mod time;
 
 #[cfg(target_os = "espidf")]
-pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {}
+pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
 
 #[cfg(not(target_os = "espidf"))]
 // SAFETY: must be called only once during runtime initialization.
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index 1b6a6bb2c5c..f4ae7d21781 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -316,7 +316,7 @@ impl Socket {
                 buf.as_mut_ptr() as *mut c_void,
                 buf.len(),
                 flags,
-                &mut storage as *mut _ as *mut _,
+                core::ptr::addr_of_mut!(storage) as *mut _,
                 &mut addrlen,
             )
         })?;
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
index b6a74fb4831..23c2be6adf9 100644
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
@@ -182,7 +182,7 @@ impl Process {
             zx_cvt(zx_object_get_info(
                 self.handle.raw(),
                 ZX_INFO_PROCESS,
-                &mut proc_info as *mut _ as *mut libc::c_void,
+                core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void,
                 mem::size_of::<zx_info_process_t>(),
                 &mut actual,
                 &mut avail,
@@ -219,7 +219,7 @@ impl Process {
             zx_cvt(zx_object_get_info(
                 self.handle.raw(),
                 ZX_INFO_PROCESS,
-                &mut proc_info as *mut _ as *mut libc::c_void,
+                core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void,
                 mem::size_of::<zx_info_process_t>(),
                 &mut actual,
                 &mut avail,
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index d5a77085725..97cbd1929d3 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -694,15 +694,15 @@ impl Command {
             let mut iov = [IoSlice::new(b"")];
             let mut msg: libc::msghdr = mem::zeroed();
 
-            msg.msg_iov = &mut iov as *mut _ as *mut _;
+            msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _;
             msg.msg_iovlen = 1;
 
             // only attach cmsg if we successfully acquired the pidfd
             if pidfd >= 0 {
                 msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
-                msg.msg_control = &mut cmsg.buf as *mut _ as *mut _;
+                msg.msg_control = core::ptr::addr_of_mut!(cmsg.buf) as *mut _;
 
-                let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _);
+                let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _);
                 (*hdr).cmsg_level = SOL_SOCKET;
                 (*hdr).cmsg_type = SCM_RIGHTS;
                 (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _;
@@ -744,17 +744,17 @@ impl Command {
 
             let mut msg: libc::msghdr = mem::zeroed();
 
-            msg.msg_iov = &mut iov as *mut _ as *mut _;
+            msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _;
             msg.msg_iovlen = 1;
             msg.msg_controllen = mem::size_of::<Cmsg>() as _;
-            msg.msg_control = &mut cmsg as *mut _ as *mut _;
+            msg.msg_control = core::ptr::addr_of_mut!(cmsg) as *mut _;
 
             match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) {
                 Err(_) => return -1,
                 Ok(_) => {}
             }
 
-            let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _);
+            let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _);
             if hdr.is_null()
                 || (*hdr).cmsg_level != SOL_SOCKET
                 || (*hdr).cmsg_type != SCM_RIGHTS
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 97976407bb4..864de31c6eb 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -239,7 +239,7 @@ impl Thread {
                     tv_nsec: nsecs,
                 };
                 secs -= ts.tv_sec as u64;
-                let ts_ptr = &mut ts as *mut _;
+                let ts_ptr = core::ptr::addr_of_mut!(ts);
                 if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
                     assert_eq!(os::errno(), libc::EINTR);
                     secs += ts.tv_sec as u64;
@@ -418,8 +418,8 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     libc::sysctl(
                         mib.as_mut_ptr(),
                         2,
-                        &mut cpus as *mut _ as *mut _,
-                        &mut cpus_size as *mut _ as *mut _,
+                        core::ptr::addr_of_mut!(cpus) as *mut _,
+                        core::ptr::addr_of_mut!(cpus_size) as *mut _,
                         ptr::null_mut(),
                         0,
                     )
@@ -864,7 +864,7 @@ pub mod guard {
                         .unwrap();
                         match sysctlbyname.get() {
                             Some(fcn) => {
-                                if fcn(oid.as_ptr(), &mut guard as *mut _ as *mut _, &mut size as *mut _ as *mut _, crate::ptr::null_mut(), 0) == 0 {
+                                if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
                                     return guard;
                                 }
                                 return 1;
diff --git a/library/std/src/sys/pal/unix/thread_local_dtor.rs b/library/std/src/sys/pal/unix/thread_local_dtor.rs
index 8857f96501c..79b152cece9 100644
--- a/library/std/src/sys/pal/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/pal/unix/thread_local_dtor.rs
@@ -58,7 +58,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
                     unsafe extern "C" fn(*mut libc::c_void),
                 >(dtor),
                 t.cast(),
-                &__dso_handle as *const _ as *mut _,
+                core::ptr::addr_of!(__dso_handle) as *mut _,
             );
         }
         return;
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index 084b8e0e216..e6cbd51e768 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -166,7 +166,7 @@ pub fn abort_internal() -> ! {
 pub fn hashmap_random_keys() -> (u64, u64) {
     let mut ret = (0u64, 0u64);
     unsafe {
-        let base = &mut ret as *mut (u64, u64) as *mut u8;
+        let base = core::ptr::addr_of_mut!(ret) as *mut u8;
         let len = mem::size_of_val(&ret);
         wasi::random_get(base, len).expect("random_get failure");
     }
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index b82a83ae7a3..3a9e7b4660b 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -394,7 +394,7 @@ impl File {
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
-                &mut info as *mut _ as *mut c_void,
+                core::ptr::addr_of_mut!(info) as *mut c_void,
                 size as c::DWORD,
             ))?;
             let mut attr = FileAttr {
@@ -422,7 +422,7 @@ impl File {
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileStandardInfo,
-                &mut info as *mut _ as *mut c_void,
+                core::ptr::addr_of_mut!(info) as *mut c_void,
                 size as c::DWORD,
             ))?;
             attr.file_size = info.AllocationSize as u64;
@@ -638,7 +638,7 @@ impl File {
             cvt(c::GetFileInformationByHandleEx(
                 self.handle.as_raw_handle(),
                 c::FileBasicInfo,
-                &mut info as *mut _ as *mut c_void,
+                core::ptr::addr_of_mut!(info) as *mut c_void,
                 size as c::DWORD,
             ))?;
             Ok(info)
@@ -1438,7 +1438,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
             pfrom.as_ptr(),
             pto.as_ptr(),
             Some(callback),
-            &mut size as *mut _ as *mut _,
+            core::ptr::addr_of_mut!(size) as *mut _,
             ptr::null_mut(),
             0,
         )
diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs
index b73d9f3ff4c..77b8f3c410e 100644
--- a/library/std/src/sys/pal/windows/io.rs
+++ b/library/std/src/sys/pal/windows/io.rs
@@ -122,7 +122,7 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
     let res = c::GetFileInformationByHandleEx(
         handle,
         c::FileNameInfo,
-        &mut name_info as *mut _ as *mut c_void,
+        core::ptr::addr_of_mut!(name_info) as *mut c_void,
         size_of::<FILE_NAME_INFO>() as u32,
     );
     if res == 0 {
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index e37fbe9ef83..1e6169ea8ec 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -310,7 +310,7 @@ impl Socket {
                 buf.as_mut_ptr() as *mut _,
                 length,
                 flags,
-                &mut storage as *mut _ as *mut _,
+                core::ptr::addr_of_mut!(storage) as *mut _,
                 &mut addrlen,
             )
         };
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index fd10df82d8b..013f588676a 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -375,7 +375,7 @@ impl AnonPipe {
         let mut overlapped: c::OVERLAPPED = crate::mem::zeroed();
         // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`.
         // Therefore the documentation suggests using it to smuggle a pointer to the callback.
-        overlapped.hEvent = &mut async_result as *mut _ as *mut _;
+        overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _;
 
         // Asynchronous read of the pipe.
         // If successful, `callback` will be called once it completes.
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index 6a94d377140..e4ab2ca7da1 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -350,10 +350,10 @@ impl Command {
                 StartupInfo: si,
                 lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _,
             };
-            si_ptr = &mut si_ex as *mut _ as _;
+            si_ptr = core::ptr::addr_of_mut!(si_ex) as _;
         } else {
             si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD;
-            si_ptr = &mut si as *mut _ as _;
+            si_ptr = core::ptr::addr_of_mut!(si) as _;
         }
 
         unsafe {
@@ -935,7 +935,7 @@ fn make_proc_thread_attribute_list(
     // It's theoretically possible for the attribute count to exceed a u32 value.
     // Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
     for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
-        let value_ptr = &*value.data as *const (dyn Send + Sync) as _;
+        let value_ptr = core::ptr::addr_of!(*value.data) as _;
         cvt(unsafe {
             c::UpdateProcThreadAttribute(
                 proc_thread_attribute_list.0.as_mut_ptr() as _,
diff --git a/library/std/src/sys/pal/windows/rand.rs b/library/std/src/sys/pal/windows/rand.rs
index 5d8fd13785a..bd1ae6b0607 100644
--- a/library/std/src/sys/pal/windows/rand.rs
+++ b/library/std/src/sys/pal/windows/rand.rs
@@ -7,7 +7,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     let ret = unsafe {
         c::BCryptGenRandom(
             ptr::null_mut(),
-            &mut v as *mut _ as *mut u8,
+            core::ptr::addr_of_mut!(v) as *mut u8,
             mem::size_of_val(&v) as c::ULONG,
             c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
         )
@@ -28,7 +28,7 @@ fn fallback_rng() -> (u64, u64) {
 
     let mut v = (0, 0);
     let ret = unsafe {
-        c::RtlGenRandom(&mut v as *mut _ as *mut c_void, mem::size_of_val(&v) as c::ULONG)
+        c::RtlGenRandom(core::ptr::addr_of_mut!(v) as *mut c_void, mem::size_of_val(&v) as c::ULONG)
     };
 
     if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
diff --git a/library/std/src/sys/pal/windows/thread_parking.rs b/library/std/src/sys/pal/windows/thread_parking.rs
index 343b530b15e..ea485d71f5a 100644
--- a/library/std/src/sys/pal/windows/thread_parking.rs
+++ b/library/std/src/sys/pal/windows/thread_parking.rs
@@ -215,7 +215,7 @@ impl Parker {
     }
 
     fn ptr(&self) -> c::LPVOID {
-        &self.state as *const _ as c::LPVOID
+        core::ptr::addr_of!(self.state) as c::LPVOID
     }
 }
 
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index de7d31baaaf..581c46af0ea 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -70,7 +70,7 @@ pub fn setsockopt<T>(
             sock.as_raw(),
             level,
             option_name,
-            &option_value as *const T as *const _,
+            core::ptr::addr_of!(option_value) as *const _,
             mem::size_of::<T>() as c::socklen_t,
         ))?;
         Ok(())
@@ -85,7 +85,7 @@ pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> i
             sock.as_raw(),
             level,
             option_name,
-            &mut option_value as *mut T as *mut _,
+            core::ptr::addr_of_mut!(option_value) as *mut _,
             &mut option_len,
         ))?;
         Ok(option_value)
@@ -99,7 +99,7 @@ where
     unsafe {
         let mut storage: c::sockaddr_storage = mem::zeroed();
         let mut len = mem::size_of_val(&storage) as c::socklen_t;
-        cvt(f(&mut storage as *mut _ as *mut _, &mut len))?;
+        cvt(f(core::ptr::addr_of_mut!(storage) as *mut _, &mut len))?;
         sockaddr_to_addr(&storage, len as usize)
     }
 }
@@ -444,7 +444,7 @@ impl TcpListener {
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
         let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
         let mut len = mem::size_of_val(&storage) as c::socklen_t;
-        let sock = self.inner.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+        let sock = self.inner.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?;
         let addr = sockaddr_to_addr(&storage, len as usize)?;
         Ok((TcpStream { inner: sock }, addr))
     }
diff --git a/library/std/src/sys_common/once/queue.rs b/library/std/src/sys_common/once/queue.rs
index 3cc1df113e3..730cdb768bd 100644
--- a/library/std/src/sys_common/once/queue.rs
+++ b/library/std/src/sys_common/once/queue.rs
@@ -212,7 +212,7 @@ fn wait(state_and_queue: &AtomicPtr<Masked>, mut current_state: *mut Masked) {
             signaled: AtomicBool::new(false),
             next: current_state.with_addr(current_state.addr() & !STATE_MASK) as *const Waiter,
         };
-        let me = &node as *const Waiter as *const Masked as *mut Masked;
+        let me = core::ptr::addr_of!(node) as *const Masked as *mut Masked;
 
         // Try to slide in the node at the head of the linked list, making sure
         // that another thread didn't just replace the head of the linked list.
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index ada69aa8269..7b11e7c17b1 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -311,7 +311,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// Checks if the associated thread has finished running its main function.
     ///
     /// `is_finished` supports implementing a non-blocking join operation, by checking
-    /// `is_finished`, and calling `join` if it returns `false`. This function does not block. To
+    /// `is_finished`, and calling `join` if it returns `true`. This function does not block. To
     /// block while waiting on the thread to finish, use [`join`][Self::join].
     ///
     /// This might return `true` for a brief moment after the thread's main
diff --git a/library/stdarch b/library/stdarch
-Subproject d5fab978fe1c2f0043db0451e9f4857eeba1743
+Subproject 56087ea170d878a7a57b3a5725e0c00f5f5cad7
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index f5988a4df13..a64f2904633 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -3,7 +3,7 @@
 #![feature(link_cfg)]
 #![feature(staged_api)]
 #![feature(c_unwind)]
-#![feature(cfg_target_abi)]
+#![cfg_attr(bootstrap, feature(cfg_target_abi))]
 #![feature(strict_provenance)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 #![allow(internal_features)]
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index 1b5f6f9dde3..527c408c89e 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -219,14 +219,14 @@ if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", targe
     pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
         let mut val: _Unwind_Word = core::ptr::null();
         _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
-                        &mut val as *mut _ as *mut c_void);
+                        core::ptr::addr_of_mut!(val) as *mut c_void);
         val
     }
 
     pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
         let mut value = value;
         _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
-                        &mut value as *mut _ as *mut c_void);
+                        core::ptr::addr_of_mut!(value) as *mut c_void);
     }
 
     pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index b813d82ca6f..9a50ad4437e 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -131,4 +131,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "The \"codegen\"/\"llvm\" profile has been removed and replaced with \"compiler\", use it instead for the same behavior.",
     },
+    ChangeInfo {
+        change_id: 118724,
+        severity: ChangeSeverity::Info,
+        summary: "`x install` now skips providing tarball sources (under 'build/dist' path) to speed up the installation process.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 573d923ed8f..a14dfd1ca12 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -3,8 +3,8 @@ use std::{
     process::Command,
 };
 
-use crate::core::build_steps::dist::distdir;
 use crate::core::builder::Builder;
+use crate::core::{build_steps::dist::distdir, builder::Kind};
 use crate::utils::channel;
 use crate::utils::helpers::t;
 
@@ -325,7 +325,22 @@ impl<'a> Tarball<'a> {
             assert!(!formats.is_empty(), "dist.compression-formats can't be empty");
             cmd.arg("--compression-formats").arg(formats.join(","));
         }
-        cmd.args(["--compression-profile", &self.builder.config.dist_compression_profile]);
+
+        // For `x install` tarball files aren't needed, so we can speed up the process by not producing them.
+        let compression_profile = if self.builder.kind == Kind::Install {
+            self.builder.verbose("Forcing dist.compression-profile = 'no-op' for `x install`.");
+            // "no-op" indicates that the rust-installer won't produce compressed tarball sources.
+            "no-op"
+        } else {
+            assert!(
+                self.builder.config.dist_compression_profile != "no-op",
+                "dist.compression-profile = 'no-op' can only be used for `x install`"
+            );
+
+            &self.builder.config.dist_compression_profile
+        };
+
+        cmd.args(&["--compression-profile", compression_profile]);
         self.builder.run(&mut cmd);
 
         // Ensure there are no symbolic links in the tarball. In particular,
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index b736f4a7956..b6880cfc60f 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -1,4 +1,4 @@
-use rustc_ast::token::{self, BinOpToken, Delimiter};
+use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast_pretty::pprust::state::State as Printer;
 use rustc_ast_pretty::pprust::PrintState;
@@ -148,7 +148,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
                     (false, Other)
                 }
                 (Pound, token::Not) => (false, PoundBang),
-                (_, token::Ident(symbol, /* is_raw */ false))
+                (_, token::Ident(symbol, IdentIsRaw::No))
                     if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) =>
                 {
                     (true, Ident)
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index bb68c84f529..973036a4098 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -879,11 +879,16 @@ fn primitive_link_fragment(
         match m.primitive_locations.get(&prim) {
             Some(&def_id) if def_id.is_local() => {
                 let len = cx.current.len();
-                let len = if len == 0 { 0 } else { len - 1 };
+                let path = if len == 0 {
+                    let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
+                    format!("{cname_sym}/")
+                } else {
+                    "../".repeat(len - 1)
+                };
                 write!(
                     f,
                     "<a class=\"primitive\" href=\"{}primitive.{}.html{fragment}\">",
-                    "../".repeat(len),
+                    path,
                     prim.as_sym()
                 )?;
                 needs_termination = true;
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 27a8079d893..61211a7d675 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2503,8 +2503,11 @@ impl<'test> TestCx<'test> {
                 // overridden by `compile-flags`.
                 rustc.arg("-Copt-level=2");
             }
-            RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake
-            | CodegenUnits | JsDocTest | Assembly => {
+            Assembly | Codegen => {
+                rustc.arg("-Cdebug-assertions=no");
+            }
+            RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
+            | CodegenUnits | JsDocTest => {
                 // do not use JSON output
             }
         }
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 87dc51bd612..1adae2b7a22 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aes"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
 dependencies = [
  "cfg-if",
  "cipher",
@@ -58,9 +58,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.79"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
 name = "autocfg"
@@ -91,9 +91,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.1"
+version = "2.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
 
 [[package]]
 name = "bstr"
@@ -117,9 +117,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d"
+checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
 dependencies = [
  "serde",
 ]
@@ -140,12 +140,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730"
 
 [[package]]
 name = "cfg-if"
@@ -208,15 +205,15 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335"
 
 [[package]]
 name = "console"
-version = "0.15.7"
+version = "0.15.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
+checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
 dependencies = [
  "encode_unicode",
  "lazy_static",
  "libc",
  "unicode-width",
- "windows-sys 0.45.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -230,22 +227,18 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.10"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2"
+checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
 dependencies = [
- "cfg-if",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.18"
+version = "0.8.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
-dependencies = [
- "cfg-if",
-]
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
 
 [[package]]
 name = "crypto-common"
@@ -285,9 +278,9 @@ dependencies = [
 
 [[package]]
 name = "eyre"
-version = "0.6.11"
+version = "0.6.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799"
+checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
 dependencies = [
  "indenter",
  "once_cell",
@@ -311,9 +304,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.11"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -334,9 +327,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indicatif"
-version = "0.17.7"
+version = "0.17.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
+checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
 dependencies = [
  "console",
  "instant",
@@ -393,9 +386,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
 
 [[package]]
 name = "libc"
-version = "0.2.151"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libffi"
@@ -428,9 +421,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
 
 [[package]]
 name = "lock_api"
@@ -479,9 +472,9 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
 dependencies = [
  "adler",
 ]
@@ -513,7 +506,7 @@ version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "cfg-if",
  "libc",
 ]
@@ -616,9 +609,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
@@ -673,9 +666,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -685,9 +678,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -735,11 +728,11 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.28"
+version = "0.38.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -748,9 +741,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
 
 [[package]]
 name = "scopeguard"
@@ -760,27 +753,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.21"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.195"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.195"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -789,9 +782,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.111"
+version = "1.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
 dependencies = [
  "itoa",
  "ryu",
@@ -809,15 +802,15 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.11.2"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
+checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
 
 [[package]]
 name = "syn"
-version = "2.0.48"
+version = "2.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -826,31 +819,30 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.9.0"
+version = "3.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
+checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall",
  "rustix",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -859,9 +851,9 @@ dependencies = [
 
 [[package]]
 name = "thread_local"
-version = "1.1.7"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -995,15 +987,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
@@ -1017,22 +1000,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -1052,42 +1020,30 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.3",
+ "windows_aarch64_msvc 0.52.3",
+ "windows_i686_gnu 0.52.3",
+ "windows_i686_msvc 0.52.3",
+ "windows_x86_64_gnu 0.52.3",
+ "windows_x86_64_gnullvm 0.52.3",
+ "windows_x86_64_msvc 0.52.3",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -1097,15 +1053,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -1115,15 +1065,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -1133,15 +1077,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -1151,15 +1089,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -1169,15 +1101,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -1187,9 +1113,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
 
 [[package]]
 name = "yansi-term"
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 60bf07b1736..944d2bbe879 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -279,7 +279,7 @@ Miri builds and vice-versa.
 
 You may be running `cargo miri` with a different compiler version than the one
 used to build the custom libstd that Miri uses, and Miri failed to detect that.
-Try deleting `~/.cache/miri`.
+Try running `cargo miri clean`.
 
 #### "no mir for `std::rt::lang_start_internal`"
 
@@ -465,7 +465,7 @@ Moreover, Miri recognizes some environment variables:
   must point to the `library` subdirectory of a `rust-lang/rust` repository
   checkout. Note that changing files in that directory does not automatically
   trigger a re-build of the standard library; you have to clear the Miri build
-  cache manually (on Linux, `rm -rf ~/.cache/miri`;
+  cache with `cargo miri clean` or deleting it manually (on Linux, `rm -rf ~/.cache/miri`;
   on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`;
   and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`).
 * `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index fe384c9d497..6841a345ce1 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "anyhow"
-version = "1.0.79"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
 name = "bitflags"
@@ -16,9 +16,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.1"
+version = "2.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
 
 [[package]]
 name = "camino"
@@ -44,9 +44,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d"
+checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
 dependencies = [
  "serde",
 ]
@@ -110,9 +110,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
 
 [[package]]
 name = "getrandom"
-version = "0.2.11"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -127,9 +127,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
 [[package]]
 name = "libc"
-version = "0.2.151"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libredox"
@@ -137,16 +137,16 @@ version = "0.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "libc",
  "redox_syscall",
 ]
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
 
 [[package]]
 name = "option-ext"
@@ -156,9 +156,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
@@ -194,13 +194,14 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39dcf8d82b1f79a179bdb284dc44db440a9666eefa5a6df5ef282d6db930d544"
+checksum = "a26170e1d79ea32f7ccec3188dd13cfc1f18c82764a9cbc1071667c0f865a4ea"
 dependencies = [
  "anyhow",
  "rustc_version",
  "tempfile",
+ "walkdir",
 ]
 
 [[package]]
@@ -220,11 +221,11 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.28"
+version = "0.38.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -233,33 +234,42 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
 
 [[package]]
 name = "semver"
-version = "1.0.21"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.195"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.195"
+version = "1.0.197"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -268,9 +278,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.111"
+version = "1.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
 dependencies = [
  "itoa",
  "ryu",
@@ -279,9 +289,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.48"
+version = "2.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -290,31 +300,30 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.9.0"
+version = "3.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
+checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall",
  "rustix",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -328,12 +337,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
+name = "walkdir"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -348,7 +398,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -368,17 +418,17 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.3",
+ "windows_aarch64_msvc 0.52.3",
+ "windows_i686_gnu 0.52.3",
+ "windows_i686_msvc 0.52.3",
+ "windows_x86_64_gnu 0.52.3",
+ "windows_x86_64_gnullvm 0.52.3",
+ "windows_x86_64_msvc 0.52.3",
 ]
 
 [[package]]
@@ -389,9 +439,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -401,9 +451,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -413,9 +463,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -425,9 +475,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -437,9 +487,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -449,9 +499,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -461,6 +511,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 79ce1f4ca32..315f7a23a91 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -20,6 +20,7 @@ Subcommands:
     test, t                  Run tests
     nextest                  Run tests with nextest (requires cargo-nextest installed)
     setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)
+    clean                    Clean the Miri cache & target directory
 
 The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
 
@@ -74,14 +75,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     // We cannot know which of those flags take arguments and which do not,
     // so we cannot detect subcommands later.
     let Some(subcommand) = args.next() else {
-        show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)");
+        show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`, `clean`)");
     };
     let subcommand = match &*subcommand {
         "setup" => MiriCommand::Setup,
         "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
+        "clean" => MiriCommand::Clean,
         _ =>
             show_error!(
-                "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`."
+                "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`."
             ),
     };
     let verbose = num_arg_flag("-v");
@@ -93,6 +95,16 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     let target = get_arg_flag_value("--target");
     let target = target.as_ref().unwrap_or(host);
 
+    // If cleaning the the target directory & sysroot cache,
+    // delete them then exit. There is no reason to setup a new
+    // sysroot in this execution.
+    if let MiriCommand::Clean = subcommand {
+        let metadata = get_cargo_metadata();
+        clean_target_dir(&metadata);
+        clean_sysroot();
+        return;
+    }
+
     // We always setup.
     let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose);
 
@@ -110,6 +122,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     let cargo_cmd = match subcommand {
         MiriCommand::Forward(s) => s,
         MiriCommand::Setup => return, // `cargo miri setup` stops here.
+        MiriCommand::Clean => unreachable!(),
     };
     let metadata = get_cargo_metadata();
     let mut cmd = cargo();
@@ -142,11 +155,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
         .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']"));
 
     // Set `--target-dir` to `miri` inside the original target directory.
-    let mut target_dir = match get_arg_flag_value("--target-dir") {
-        Some(dir) => PathBuf::from(dir),
-        None => metadata.target_directory.clone().into_std_path_buf(),
-    };
-    target_dir.push("miri");
+    let target_dir = get_target_dir(&metadata);
     cmd.arg("--target-dir").arg(target_dir);
 
     // *After* we set all the flags that need setting, forward everything else. Make sure to skip
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index 8ae5b8c3e82..a98e1fcd485 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -67,13 +67,8 @@ pub fn setup(
     }
 
     // Determine where to put the sysroot.
-    let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
-        Some(dir) => PathBuf::from(dir),
-        None => {
-            let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
-            user_dirs.cache_dir().to_owned()
-        }
-    };
+    let sysroot_dir = get_sysroot_dir();
+
     // Sysroot configuration and build details.
     let no_std = match std::env::var_os("MIRI_NO_STD") {
         None =>
diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs
index 3c591268455..6c1a074cd8c 100644
--- a/src/tools/miri/cargo-miri/src/util.rs
+++ b/src/tools/miri/cargo-miri/src/util.rs
@@ -74,6 +74,8 @@ pub enum MiriCommand {
     Setup,
     /// A command to be forwarded to cargo.
     Forward(String),
+    /// Clean the miri cache
+    Clean,
 }
 
 /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax.
@@ -249,3 +251,65 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) {
     }
     eprintln!("{prefix} running command: {cmd:?}");
 }
+
+/// Get the target directory for miri output.
+///
+/// Either in an argument passed-in, or from cargo metadata.
+pub fn get_target_dir(meta: &Metadata) -> PathBuf {
+    let mut output = match get_arg_flag_value("--target-dir") {
+        Some(dir) => PathBuf::from(dir),
+        None => meta.target_directory.clone().into_std_path_buf(),
+    };
+    output.push("miri");
+    output
+}
+
+/// Determines where the sysroot of this exeuction is
+///
+/// Either in a user-specified spot by an envar, or in a default cache location.
+pub fn get_sysroot_dir() -> PathBuf {
+    match std::env::var_os("MIRI_SYSROOT") {
+        Some(dir) => PathBuf::from(dir),
+        None => {
+            let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
+            user_dirs.cache_dir().to_owned()
+        }
+    }
+}
+
+/// An idempotent version of the stdlib's remove_dir_all
+/// it is considered a success if the directory was not there.
+fn remove_dir_all_idem(dir: &Path) -> std::io::Result<()> {
+    match std::fs::remove_dir_all(dir) {
+        Ok(_) => Ok(()),
+        // If the directory doesn't exist, it is still a success.
+        Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
+        Err(err) => Err(err),
+    }
+}
+
+/// Deletes the Miri sysroot cache
+/// Returns an error if the MIRI_SYSROOT env var is set.
+pub fn clean_sysroot() {
+    if std::env::var_os("MIRI_SYSROOT").is_some() {
+        show_error!(
+            "MIRI_SYSROOT is set. Please clean your custom sysroot cache directory manually."
+        )
+    }
+
+    let sysroot_dir = get_sysroot_dir();
+
+    eprintln!("Cleaning sysroot cache at {}", sysroot_dir.display());
+
+    // Keep it simple, just remove the directory.
+    remove_dir_all_idem(&sysroot_dir).unwrap_or_else(|err| show_error!("{}", err));
+}
+
+/// Deletes the Miri target directory
+pub fn clean_target_dir(meta: &Metadata) {
+    let target_dir = get_target_dir(meta);
+
+    eprintln!("Cleaning target directory at {}", target_dir.display());
+
+    remove_dir_all_idem(&target_dir).unwrap_or_else(|err| show_error!("{}", err))
+}
diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock
index 04615f3d8c1..a6f7467f0a2 100644
--- a/src/tools/miri/miri-script/Cargo.lock
+++ b/src/tools/miri/miri-script/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "anyhow"
-version = "1.0.79"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
 name = "bitflags"
@@ -16,9 +16,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.1"
+version = "2.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
 
 [[package]]
 name = "cfg-if"
@@ -55,9 +55,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
 
 [[package]]
 name = "either"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
 
 [[package]]
 name = "errno"
@@ -71,9 +71,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.11"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -100,9 +100,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.151"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libredox"
@@ -110,16 +110,16 @@ version = "0.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "libc",
  "redox_syscall",
 ]
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
 
 [[package]]
 name = "miri-script"
@@ -157,9 +157,9 @@ checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
@@ -204,11 +204,11 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.28"
+version = "0.38.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -226,9 +226,9 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.21"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
 
 [[package]]
 name = "shell-words"
@@ -238,9 +238,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
 
 [[package]]
 name = "syn"
-version = "2.0.48"
+version = "2.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -249,18 +249,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.56"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -347,7 +347,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.3",
 ]
 
 [[package]]
@@ -367,17 +367,17 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.3",
+ "windows_aarch64_msvc 0.52.3",
+ "windows_i686_gnu 0.52.3",
+ "windows_i686_msvc 0.52.3",
+ "windows_x86_64_gnu 0.52.3",
+ "windows_x86_64_gnullvm 0.52.3",
+ "windows_x86_64_msvc 0.52.3",
 ]
 
 [[package]]
@@ -388,9 +388,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -400,9 +400,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -412,9 +412,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -424,9 +424,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -436,9 +436,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -448,9 +448,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -460,9 +460,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
 
 [[package]]
 name = "xshell"
diff --git a/src/tools/miri/miri.bat b/src/tools/miri/miri.bat
new file mode 100644
index 00000000000..91e8a6e8f3b
--- /dev/null
+++ b/src/tools/miri/miri.bat
@@ -0,0 +1,10 @@
+:: This makes execution of ./miri on Linux and Windows the same.
+:: Windows will not execute the bash script, and select this.
+@echo off
+set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
+cargo build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml
+
+:: Forwards all arguments to this file to the executable.
+:: We invoke the binary directly to avoid going through rustup, which would set some extra
+:: env vars that we do not want.
+%MIRI_SCRIPT_TARGET_DIR%\debug\miri-script %*
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index ab6f899cd3a..02ab748c447 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-4316d0c6252cb1f833e582dfa68adb98efd5ddfb
+c5f69bdd5173a948e0131f934fa7c4cbf5e0b55f
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index ea2d104694a..ca8773cac14 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -563,9 +563,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         let right_idx = src_index.checked_sub(left_len).unwrap();
                         this.read_immediate(&this.project_index(&right, right_idx)?)?
                     } else {
-                        span_bug!(
-                            this.cur_span(),
-                            "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}",
+                        throw_ub_format!(
+                            "`simd_shuffle_generic` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
                         );
                     };
                     this.write_immediate(*val, &dest)?;
@@ -604,9 +603,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                         let right_idx = src_index.checked_sub(left_len).unwrap();
                         this.read_immediate(&this.project_index(&right, right_idx)?)?
                     } else {
-                        span_bug!(
-                            this.cur_span(),
-                            "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}",
+                        throw_ub_format!(
+                            "`simd_shuffle` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
                         );
                     };
                     this.write_immediate(*val, &dest)?;
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index 8bed321e655..d8f7cafe3b2 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -99,18 +99,15 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
     };
 
     if with_dependencies {
+        // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary.
+        // (It's a separate crate, so we don't get an env var from cargo.)
+        let mut prog = miri_path();
+        prog.set_file_name("cargo-miri");
+        config.dependency_builder.program = prog;
+        let builder_args = ["miri", "run"]; // There is no `cargo miri build` so we just use `cargo miri run`.
+        config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect();
         config.dependencies_crate_manifest_path =
             Some(Path::new("test_dependencies").join("Cargo.toml"));
-        let mut builder_args = vec!["run".into()];
-        builder_args.extend(flagsplit(&env::var("CARGO_EXTRA_FLAGS").unwrap_or_default()));
-        builder_args.extend([
-            "--manifest-path".into(),
-            "cargo-miri/Cargo.toml".into(),
-            "--".into(),
-            "miri".into(),
-            "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`.
-        ]);
-        config.dependency_builder.args = builder_args.into_iter().map(Into::into).collect();
         // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
         config.dependency_builder.envs.push(("RUSTFLAGS".into(), None));
     }
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-extract.rs b/src/tools/miri/tests/fail/intrinsics/simd-extract.rs
new file mode 100644
index 00000000000..02b9d30df5e
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/simd-extract.rs
@@ -0,0 +1,8 @@
+#![feature(portable_simd, core_intrinsics)]
+use std::simd::*;
+
+fn main() {
+    let v = i32x4::splat(0);
+    let _x: i32 = unsafe { std::intrinsics::simd::simd_extract(v, 4) };
+    //~^ERROR: index 4 is out-of-bounds
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr b/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr
new file mode 100644
index 00000000000..dc6b22de492
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/simd-extract.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `simd_extract` index 4 is out-of-bounds of vector with length 4
+  --> $DIR/simd-extract.rs:LL:CC
+   |
+LL |     let _x: i32 = unsafe { std::intrinsics::simd::simd_extract(v, 4) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `simd_extract` index 4 is out-of-bounds of vector with length 4
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/simd-extract.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs
index f362caa11dc..f362caa11dc 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs
diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs
index 66c0895a5da..66c0895a5da 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs
diff --git a/src/tools/miri/tests/pass-dep/shims/mmap.rs b/src/tools/miri/tests/pass-dep/shims/mmap.rs
index 0cbe8d94294..5acdedc67bf 100644
--- a/src/tools/miri/tests/pass-dep/shims/mmap.rs
+++ b/src/tools/miri/tests/pass-dep/shims/mmap.rs
@@ -155,8 +155,9 @@ fn test_mremap() {
 
     // Test all of our error conditions
     // Not aligned
-    let ptr =
-        unsafe { libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) };
+    let ptr = unsafe {
+        libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE)
+    };
     assert_eq!(ptr, libc::MAP_FAILED);
     assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
 
diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs b/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
index 077bbfff164..c9d10cb83d4 100644
--- a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
+++ b/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
@@ -4,8 +4,8 @@
 #![feature(sync_unsafe_cell)]
 
 use std::cell::SyncUnsafeCell;
-use std::thread;
-use std::{mem, ptr};
+use std::mem::MaybeUninit;
+use std::{mem, ptr, thread};
 
 fn main() {
     test_mutex_libc_init_recursive();
@@ -15,9 +15,10 @@ fn main() {
     #[cfg(target_os = "linux")]
     test_mutex_libc_static_initializer_recursive();
 
-    test_mutex();
+    check_mutex();
     check_rwlock_write();
     check_rwlock_read_no_deadlock();
+    check_cond();
 }
 
 fn test_mutex_libc_init_recursive() {
@@ -119,7 +120,7 @@ impl<T> Clone for SendPtr<T> {
     }
 }
 
-fn test_mutex() {
+fn check_mutex() {
     // Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex.
     unsafe {
         let data = SyncUnsafeCell::new((libc::PTHREAD_MUTEX_INITIALIZER, 0));
@@ -213,6 +214,53 @@ fn check_rwlock_read_no_deadlock() {
     }
 }
 
+fn check_cond() {
+    unsafe {
+        let mut cond: MaybeUninit<libc::pthread_cond_t> = MaybeUninit::uninit();
+        assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), ptr::null()), 0);
+        let cond = SendPtr { ptr: cond.as_mut_ptr() };
+
+        let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
+        let mutex = SendPtr { ptr: &mut mutex };
+
+        let mut data = 0;
+        let data = SendPtr { ptr: &mut data };
+
+        let t = thread::spawn(move || {
+            let mutex = mutex; // circumvent per-field closure capture
+            let cond = cond;
+            let data = data;
+            assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0);
+            assert!(data.ptr.read() == 0);
+            data.ptr.write(1);
+            libc::pthread_cond_wait(cond.ptr, mutex.ptr);
+            assert!(data.ptr.read() == 3);
+            data.ptr.write(4);
+            assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0);
+        });
+
+        thread::yield_now();
+
+        assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0);
+        assert!(data.ptr.read() == 1);
+        data.ptr.write(2);
+        assert_eq!(libc::pthread_cond_signal(cond.ptr), 0);
+        thread::yield_now(); // the other thread wakes up but can't get the lock yet
+        assert!(data.ptr.read() == 2);
+        data.ptr.write(3);
+        assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0);
+
+        thread::yield_now(); // now the other thread gets the lock back
+
+        assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0);
+        assert!(data.ptr.read() == 4);
+        assert_eq!(libc::pthread_cond_broadcast(cond.ptr), 0); // just a smoke test
+        assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0);
+
+        t.join().unwrap();
+    }
+}
+
 // std::sync::RwLock does not even used pthread_rwlock any more.
 // Do some smoke testing of the API surface.
 fn test_rwlock_libc_static_initializer() {
diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs
index 1d48e5312d4..a6c181098b7 100644
--- a/src/tools/miri/tests/pass/concurrency/sync.rs
+++ b/src/tools/miri/tests/pass/concurrency/sync.rs
@@ -63,10 +63,10 @@ fn check_conditional_variables_timed_wait_timeout() {
     let cvar = Condvar::new();
     let guard = lock.lock().unwrap();
     let now = Instant::now();
-    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
+    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(10)).unwrap();
     assert!(timeout.timed_out());
     let elapsed_time = now.elapsed().as_millis();
-    assert!(100 <= elapsed_time && elapsed_time <= 1000);
+    assert!(10 <= elapsed_time && elapsed_time <= 1000);
 }
 
 /// Test that signaling a conditional variable when waiting with a timeout works
@@ -79,7 +79,7 @@ fn check_conditional_variables_timed_wait_notimeout() {
     let guard = lock.lock().unwrap();
 
     let handle = thread::spawn(move || {
-        thread::sleep(Duration::from_millis(100)); // Make sure the other thread is waiting by the time we call `notify`.
+        thread::sleep(Duration::from_millis(1)); // Make sure the other thread is waiting by the time we call `notify`.
         let (_lock, cvar) = &*pair2;
         cvar.notify_one();
     });
diff --git a/src/tools/miri/tests/pass/overflow_checks_off.rs b/src/tools/miri/tests/pass/overflow_checks_off.rs
index 7b9d4f8fff5..831bffb6c5e 100644
--- a/src/tools/miri/tests/pass/overflow_checks_off.rs
+++ b/src/tools/miri/tests/pass/overflow_checks_off.rs
@@ -7,10 +7,9 @@
 // Miri does not implement the codegen-time hack that backs `#[rustc_inherit_overflow_checks]`.
 // use std::ops::*;
 
-
 // Disable _compile-time_ overflow linting
 // so that we can test runtime overflow checks
- #![allow(arithmetic_overflow)]
+#![allow(arithmetic_overflow)]
 
 fn main() {
     assert_eq!(-{ -0x80i8 }, -0x80);
diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs
index 57d0b6a87b2..d4b3ab8ac09 100644
--- a/src/tools/miri/tests/pass/portable-simd.rs
+++ b/src/tools/miri/tests/pass/portable-simd.rs
@@ -268,15 +268,11 @@ fn simd_mask() {
     }
 
     // This used to cause an ICE. It exercises simd_select_bitmask with an array as input.
-    if cfg!(target_endian = "little") {
-        // FIXME this test currently fails on big-endian:
-        // <https://github.com/rust-lang/portable-simd/issues/379>
-        let bitmask = u8x4::from_array([0b00001101, 0, 0, 0]);
-        assert_eq!(
-            mask32x4::from_bitmask_vector(bitmask),
-            mask32x4::from_array([true, false, true, true]),
-        );
-    }
+    let bitmask = u8x4::from_array([0b00001101, 0, 0, 0]);
+    assert_eq!(
+        mask32x4::from_bitmask_vector(bitmask),
+        mask32x4::from_array([true, false, true, true]),
+    );
     let bitmask = u8x8::from_array([0b01000101, 0, 0, 0, 0, 0, 0, 0]);
     assert_eq!(
         mask32x8::from_bitmask_vector(bitmask),
diff --git a/src/tools/miri/tests/pass/shims/windows-rand.rs b/src/tools/miri/tests/pass/shims/windows-rand.rs
new file mode 100644
index 00000000000..e2bcb7bd7cb
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/windows-rand.rs
@@ -0,0 +1,41 @@
+//@only-target-windows: this directly tests windows only random functions
+use core::ffi::c_void;
+use core::mem::size_of_val;
+use core::ptr::null_mut;
+
+// Windows API definitions.
+type NTSTATUS = i32;
+type BOOLEAN = u8;
+const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
+const BCRYPT_RNG_ALG_HANDLE: *mut c_void = 0x81 as *mut c_void;
+#[link(name = "bcrypt")]
+extern "system" {
+    fn BCryptGenRandom(
+        halgorithm: *mut c_void,
+        pbbuffer: *mut u8,
+        cbbuffer: u32,
+        dwflags: u32,
+    ) -> NTSTATUS;
+}
+#[link(name = "advapi32")]
+extern "system" {
+    #[link_name = "SystemFunction036"]
+    fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> BOOLEAN;
+}
+
+fn main() {
+    let mut key = [0u8; 24];
+    let len: u32 = size_of_val(&key).try_into().unwrap();
+    let ret = unsafe {
+        BCryptGenRandom(null_mut(), key.as_mut_ptr(), len, BCRYPT_USE_SYSTEM_PREFERRED_RNG)
+    };
+    // NTSTATUS codes use the high bit to indicate an error
+    assert!(ret >= 0);
+
+    let ret = unsafe { BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, key.as_mut_ptr(), len, 0) };
+    assert!(ret >= 0);
+
+    let ret = unsafe { RtlGenRandom(key.as_mut_ptr(), len) };
+    // RtlGenRandom returns a BOOLEAN where 0 indicates an error
+    assert_ne!(ret, 0);
+}
diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs
index d30ca96ea41..0b9805681b4 100644
--- a/src/tools/miri/tests/pass/slices.rs
+++ b/src/tools/miri/tests/pass/slices.rs
@@ -29,7 +29,8 @@ fn slice_of_zst() {
 
     // In a slice of zero-size elements the pointer is meaningless.
     // Ensure iteration still works even if the pointer is at the end of the address space.
-    let slice: &[()] = unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) };
+    let slice: &[()] =
+        unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) };
     assert_eq!(slice.len(), 10);
     assert_eq!(slice.iter().count(), 10);
 
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 62fbd57abc1..5a8b18e3fe1 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -226,6 +226,11 @@ jobs:
       - name: download typos
         run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
 
+      - name: Checkout repository
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ github.event.pull_request.head.sha }}
+
       - name: check for typos
         run: typos
 
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index be9f504e599..de61b2389ae 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -67,7 +67,7 @@ jobs:
   other_metrics:
     strategy:
       matrix:
-        names: [self, rustc_tests, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18]
+        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]
 
@@ -118,11 +118,6 @@ jobs:
         with:
           name: self-${{ github.sha }}
 
-      - name: Download rustc_tests metrics
-        uses: actions/download-artifact@v3
-        with:
-          name: rustc_tests-${{ github.sha }}
-
       - name: Download ripgrep-13.0.0 metrics
         uses: actions/download-artifact@v3
         with:
@@ -151,7 +146,7 @@ jobs:
           chmod 700 ~/.ssh
 
           git clone --depth 1 git@github.com:rust-analyzer/metrics.git
-          jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5] * .[6]" build.json self.json rustc_tests.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json
+          jq -s ".[0] * .[1] * .[2] * .[3] * .[4] * .[5]" build.json self.json ripgrep-13.0.0.json webrender-2022.json diesel-1.4.8.json hyper-0.14.18.json -c >> metrics/metrics.json
           cd metrics
           git add .
           git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index adb1c850516..ac536d0fdde 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -59,7 +59,7 @@ jobs:
 
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v4
+        uses: actions/checkout@v3
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
@@ -78,9 +78,9 @@ jobs:
           rustup component add rust-src
 
       - name: Install Node.js
-        uses: actions/setup-node@v4
+        uses: actions/setup-node@v3
         with:
-          node-version: 18
+          node-version: 16
 
       - name: Update apt repositories
         if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 7b29d7bb798..3c87291dbad 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1709,6 +1709,7 @@ dependencies = [
  "dissimilar",
  "expect-test",
  "indexmap",
+ "itertools",
  "linked-hash-map",
  "lock_api",
  "oorandom",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 8229b1ccf3d..cd14f7b855a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -6,8 +6,8 @@ use itertools::Itertools;
 
 use crate::{
     hir::{
-        Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst,
-        Movability, Statement,
+        Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability,
+        Statement,
     },
     pretty::{print_generic_args, print_path, print_type_ref},
     type_ref::TypeRef,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index 540f643ae7d..f07b1257662 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -40,7 +40,7 @@ pub struct StructData {
 }
 
 bitflags! {
-    #[derive(Debug, Clone, PartialEq, Eq)]
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
     pub struct StructFlags: u8 {
         const NO_FLAGS         = 0;
         /// Indicates whether the struct is `PhantomData`.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 38cfcf0f281..faa1eed15a4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -477,7 +477,7 @@ mod tests {
     use expect_test::{expect, Expect};
     use test_fixture::WithFixture;
 
-    use crate::{db::DefDatabase, test_db::TestDB, ItemContainerId, Lookup};
+    use crate::{test_db::TestDB, ItemContainerId, Lookup};
 
     use super::*;
 
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 be16a5e31a2..bb36950f95a 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
@@ -44,13 +44,13 @@ use std::{
     ops::{Index, Range},
 };
 
-use ast::{AstNode, HasName, StructKind};
+use ast::{AstNode, StructKind};
 use base_db::CrateId;
 use either::Either;
 use hir_expand::{
     ast_id_map::{AstIdNode, FileAstId},
     attrs::RawAttrs,
-    name::{name, AsName, Name},
+    name::Name,
     ExpandTo, HirFileId, InFile,
 };
 use intern::Interned;
@@ -67,7 +67,7 @@ use crate::{
     attr::Attrs,
     db::DefDatabase,
     generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
-    path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
+    path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
     type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
     visibility::{RawVisibility, VisibilityExplicitness},
     BlockId, Lookup,
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 b51cb5de0f4..37fdece8768 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
@@ -2,17 +2,33 @@
 
 use std::collections::hash_map::Entry;
 
-use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef};
-use syntax::ast::{HasModuleItem, HasTypeBounds, IsString};
+use hir_expand::{
+    ast_id_map::AstIdMap, mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId,
+};
+use la_arena::Arena;
+use syntax::{
+    ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
+    AstNode,
+};
+use triomphe::Arc;
 
 use crate::{
-    generics::{GenericParamsCollector, TypeParamData, TypeParamProvenance},
-    type_ref::{LifetimeRef, TraitBoundModifier},
+    db::DefDatabase,
+    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,
+    },
+    path::AssociatedTypeBinding,
+    type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
+    visibility::RawVisibility,
     LocalLifetimeParamId, LocalTypeOrConstParamId,
 };
 
-use super::*;
-
 fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
     FileItemTreeId(index)
 }
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 dae876f7ecb..87c90a4c6ab 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
@@ -1,16 +1,22 @@
 //! `ItemTree` debug printer.
 
-use std::fmt::Write;
+use std::fmt::{self, Write};
 
 use span::ErasedFileAstId;
 
 use crate::{
-    generics::{WherePredicate, WherePredicateTypeTarget},
+    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,
+        RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union,
+        Use, UseTree, UseTreeKind, Variant,
+    },
     pretty::{print_path, print_type_bounds, print_type_ref},
+    visibility::RawVisibility,
 };
 
-use super::*;
-
 pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String {
     let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
 
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 88838f58fe7..32825406505 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
@@ -2446,7 +2446,7 @@ mod tests {
     use base_db::SourceDatabase;
     use test_fixture::WithFixture;
 
-    use crate::{db::DefDatabase, test_db::TestDB};
+    use crate::test_db::TestDB;
 
     use super::*;
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index bf89ea711a0..d278b75e815 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -1,10 +1,7 @@
 use expect_test::expect;
-use test_fixture::WithFixture;
 
 use itertools::Itertools;
 
-use crate::nameres::tests::check;
-
 use super::*;
 
 #[test]
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 bd243518fc6..e678a2fee13 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
@@ -1,7 +1,7 @@
 //! The implementation of `RustIrDatabase` for Chalk, which provides information
 //! about the code that Chalk needs.
 use core::ops;
-use std::{iter, sync::Arc};
+use std::{iter, ops::ControlFlow, sync::Arc};
 
 use tracing::debug;
 
@@ -10,9 +10,10 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 
 use base_db::CrateId;
 use hir_def::{
+    data::adt::StructFlags,
     hir::Movability,
     lang_item::{LangItem, LangItemTarget},
-    AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId,
+    AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId,
 };
 use hir_expand::name::name;
 
@@ -33,7 +34,7 @@ use crate::{
 
 pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
 pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>;
-pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
+pub(crate) type AdtDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
 pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>;
 pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
 
@@ -53,8 +54,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> {
         self.db.trait_datum(self.krate, trait_id)
     }
-    fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> {
-        self.db.struct_datum(self.krate, struct_id)
+    fn adt_datum(&self, struct_id: AdtId) -> Arc<AdtDatum> {
+        self.db.adt_datum(self.krate, struct_id)
     }
     fn adt_repr(&self, _struct_id: AdtId) -> Arc<rust_ir::AdtRepr<Interner>> {
         // FIXME: keep track of these
@@ -136,81 +137,92 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
             _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
         };
 
-        let trait_module = trait_.module(self.db.upcast());
-        let type_module = match self_ty_fp {
-            Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
-            Some(TyFingerprint::ForeignType(type_id)) => {
-                Some(from_foreign_def_id(type_id).module(self.db.upcast()))
-            }
-            Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
-            _ => None,
-        };
-
-        let mut def_blocks =
-            [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())];
-
-        // Note: Since we're using impls_for_trait, only impls where the trait
-        // can be resolved should ever reach Chalk. impl_datum relies on that
-        // and will panic if the trait can't be resolved.
-        let in_deps = self.db.trait_impls_in_deps(self.krate);
-        let in_self = self.db.trait_impls_in_crate(self.krate);
-
-        let block_impls = iter::successors(self.block, |&block_id| {
-            cov_mark::hit!(block_local_impls);
-            self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block())
-        })
-        .inspect(|&block_id| {
-            // make sure we don't search the same block twice
-            def_blocks.iter_mut().for_each(|block| {
-                if *block == Some(block_id) {
-                    *block = None;
-                }
-            });
-        })
-        .filter_map(|block_id| self.db.trait_impls_in_block(block_id));
-
         let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
+
         let mut result = vec![];
-        match fps {
-            [] => {
-                debug!("Unrestricted search for {:?} impls...", trait_);
-                let mut f = |impls: &TraitImpls| {
-                    result.extend(impls.for_trait(trait_).map(id_to_chalk));
-                };
-                f(&in_self);
-                in_deps.iter().map(ops::Deref::deref).for_each(&mut f);
-                block_impls.for_each(|it| f(&it));
-                def_blocks
-                    .into_iter()
-                    .flatten()
-                    .filter_map(|it| self.db.trait_impls_in_block(it))
-                    .for_each(|it| f(&it));
-            }
-            fps => {
-                let mut f =
-                    |impls: &TraitImpls| {
-                        result.extend(fps.iter().flat_map(|fp| {
-                            impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
-                        }));
-                    };
-                f(&in_self);
-                in_deps.iter().map(ops::Deref::deref).for_each(&mut f);
-                block_impls.for_each(|it| f(&it));
-                def_blocks
-                    .into_iter()
-                    .flatten()
-                    .filter_map(|it| self.db.trait_impls_in_block(it))
-                    .for_each(|it| f(&it));
-            }
-        }
+        if fps.is_empty() {
+            debug!("Unrestricted search for {:?} impls...", trait_);
+            self.for_trait_impls(trait_, self_ty_fp, |impls| {
+                result.extend(impls.for_trait(trait_).map(id_to_chalk));
+                ControlFlow::Continue(())
+            })
+        } else {
+            self.for_trait_impls(trait_, self_ty_fp, |impls| {
+                result.extend(
+                    fps.iter().flat_map(move |fp| {
+                        impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
+                    }),
+                );
+                ControlFlow::Continue(())
+            })
+        };
 
         debug!("impls_for_trait returned {} impls", result.len());
         result
     }
+
     fn impl_provided_for(&self, auto_trait_id: TraitId, kind: &chalk_ir::TyKind<Interner>) -> bool {
         debug!("impl_provided_for {:?}, {:?}", auto_trait_id, kind);
-        false // FIXME
+
+        let trait_id = from_chalk_trait_id(auto_trait_id);
+        let self_ty = kind.clone().intern(Interner);
+        // We cannot filter impls by `TyFingerprint` for the following types:
+        let self_ty_fp = match kind {
+            // because we need to find any impl whose Self type is a ref with the same mutability
+            // (we don't care about the inner type).
+            TyKind::Ref(..) => None,
+            // because we need to find any impl whose Self type is a tuple with the same arity.
+            TyKind::Tuple(..) => None,
+            _ => TyFingerprint::for_trait_impl(&self_ty),
+        };
+
+        let check_kind = |impl_id| {
+            let impl_self_ty = self.db.impl_self_ty(impl_id);
+            // NOTE(skip_binders): it's safe to skip binders here as we don't check substitutions.
+            let impl_self_kind = impl_self_ty.skip_binders().kind(Interner);
+
+            match (kind, impl_self_kind) {
+                (TyKind::Adt(id_a, _), TyKind::Adt(id_b, _)) => id_a == id_b,
+                (TyKind::AssociatedType(id_a, _), TyKind::AssociatedType(id_b, _)) => id_a == id_b,
+                (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a == scalar_b,
+                (TyKind::Error, TyKind::Error)
+                | (TyKind::Str, TyKind::Str)
+                | (TyKind::Slice(_), TyKind::Slice(_))
+                | (TyKind::Never, TyKind::Never)
+                | (TyKind::Array(_, _), TyKind::Array(_, _)) => true,
+                (TyKind::Tuple(arity_a, _), TyKind::Tuple(arity_b, _)) => arity_a == arity_b,
+                (TyKind::OpaqueType(id_a, _), TyKind::OpaqueType(id_b, _)) => id_a == id_b,
+                (TyKind::FnDef(id_a, _), TyKind::FnDef(id_b, _)) => id_a == id_b,
+                (TyKind::Ref(id_a, _, _), TyKind::Ref(id_b, _, _))
+                | (TyKind::Raw(id_a, _), TyKind::Raw(id_b, _)) => id_a == id_b,
+                (TyKind::Closure(id_a, _), TyKind::Closure(id_b, _)) => id_a == id_b,
+                (TyKind::Coroutine(id_a, _), TyKind::Coroutine(id_b, _))
+                | (TyKind::CoroutineWitness(id_a, _), TyKind::CoroutineWitness(id_b, _)) => {
+                    id_a == id_b
+                }
+                (TyKind::Foreign(id_a), TyKind::Foreign(id_b)) => id_a == id_b,
+                (_, _) => false,
+            }
+        };
+
+        if let Some(fp) = self_ty_fp {
+            self.for_trait_impls(trait_id, self_ty_fp, |impls| {
+                match impls.for_trait_and_self_ty(trait_id, fp).any(check_kind) {
+                    true => ControlFlow::Break(()),
+                    false => ControlFlow::Continue(()),
+                }
+            })
+        } else {
+            self.for_trait_impls(trait_id, self_ty_fp, |impls| {
+                match impls.for_trait(trait_id).any(check_kind) {
+                    true => ControlFlow::Break(()),
+                    false => ControlFlow::Continue(()),
+                }
+            })
+        }
+        .is_break()
     }
+
     fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
         self.db.associated_ty_value(self.krate, id)
     }
@@ -489,6 +501,59 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     }
 }
 
+impl<'a> ChalkContext<'a> {
+    fn for_trait_impls(
+        &self,
+        trait_id: hir_def::TraitId,
+        self_ty_fp: Option<TyFingerprint>,
+        mut f: impl FnMut(&TraitImpls) -> ControlFlow<()>,
+    ) -> ControlFlow<()> {
+        // Note: Since we're using `impls_for_trait` and `impl_provided_for`,
+        // only impls where the trait can be resolved should ever reach Chalk.
+        // `impl_datum` relies on that and will panic if the trait can't be resolved.
+        let in_deps = self.db.trait_impls_in_deps(self.krate);
+        let in_self = self.db.trait_impls_in_crate(self.krate);
+        let trait_module = trait_id.module(self.db.upcast());
+        let type_module = match self_ty_fp {
+            Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
+            Some(TyFingerprint::ForeignType(type_id)) => {
+                Some(from_foreign_def_id(type_id).module(self.db.upcast()))
+            }
+            Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
+            _ => None,
+        };
+
+        let mut def_blocks =
+            [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())];
+
+        let block_impls = iter::successors(self.block, |&block_id| {
+            cov_mark::hit!(block_local_impls);
+            self.db.block_def_map(block_id).parent().and_then(|module| module.containing_block())
+        })
+        .inspect(|&block_id| {
+            // make sure we don't search the same block twice
+            def_blocks.iter_mut().for_each(|block| {
+                if *block == Some(block_id) {
+                    *block = None;
+                }
+            });
+        })
+        .filter_map(|block_id| self.db.trait_impls_in_block(block_id));
+        f(&in_self)?;
+        for it in in_deps.iter().map(ops::Deref::deref) {
+            f(it)?;
+        }
+        for it in block_impls {
+            f(&it)?;
+        }
+        for it in def_blocks.into_iter().flatten().filter_map(|it| self.db.trait_impls_in_block(it))
+        {
+            f(&it)?;
+        }
+        ControlFlow::Continue(())
+    }
+}
+
 impl chalk_ir::UnificationDatabase<Interner> for &dyn HirDatabase {
     fn fn_def_variance(
         &self,
@@ -590,7 +655,7 @@ pub(crate) fn trait_datum_query(
         coinductive: false, // only relevant for Chalk testing
         // FIXME: set these flags correctly
         marker: false,
-        fundamental: false,
+        fundamental: trait_data.fundamental,
     };
     let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
     let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
@@ -649,35 +714,74 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem {
     }
 }
 
-pub(crate) fn struct_datum_query(
+pub(crate) fn adt_datum_query(
     db: &dyn HirDatabase,
     krate: CrateId,
-    struct_id: AdtId,
-) -> Arc<StructDatum> {
-    debug!("struct_datum {:?}", struct_id);
-    let chalk_ir::AdtId(adt_id) = struct_id;
+    chalk_ir::AdtId(adt_id): AdtId,
+) -> Arc<AdtDatum> {
+    debug!("adt_datum {:?}", adt_id);
     let generic_params = generics(db.upcast(), adt_id.into());
-    let upstream = adt_id.module(db.upcast()).krate() != krate;
-    let where_clauses = {
-        let generic_params = generics(db.upcast(), adt_id.into());
-        let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-        convert_where_clauses(db, adt_id.into(), &bound_vars)
+    let bound_vars_subst = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let where_clauses = convert_where_clauses(db, adt_id.into(), &bound_vars_subst);
+
+    let (fundamental, phantom_data) = match adt_id {
+        hir_def::AdtId::StructId(s) => {
+            let flags = db.struct_data(s).flags;
+            (
+                flags.contains(StructFlags::IS_FUNDAMENTAL),
+                flags.contains(StructFlags::IS_PHANTOM_DATA),
+            )
+        }
+        // FIXME set fundamental flags correctly
+        hir_def::AdtId::UnionId(_) => (false, false),
+        hir_def::AdtId::EnumId(_) => (false, false),
     };
     let flags = rust_ir::AdtFlags {
-        upstream,
-        // FIXME set fundamental and phantom_data flags correctly
-        fundamental: false,
-        phantom_data: false,
+        upstream: adt_id.module(db.upcast()).krate() != krate,
+        fundamental,
+        phantom_data,
     };
-    // FIXME provide enum variants properly (for auto traits)
-    let variant = rust_ir::AdtVariantDatum {
-        fields: Vec::new(), // FIXME add fields (only relevant for auto traits),
+
+    // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
+    let _variant_id_to_fields = |id: VariantId| {
+        let variant_data = &id.variant_data(db.upcast());
+        let fields = if variant_data.fields().is_empty() {
+            vec![]
+        } else {
+            let field_types = db.field_types(id);
+            variant_data
+                .fields()
+                .iter()
+                .map(|(idx, _)| field_types[idx].clone().substitute(Interner, &bound_vars_subst))
+                .filter(|it| !it.contains_unknown())
+                .collect()
+        };
+        rust_ir::AdtVariantDatum { fields }
     };
-    let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses };
-    let struct_datum = StructDatum {
-        // FIXME set ADT kind
-        kind: rust_ir::AdtKind::Struct,
-        id: struct_id,
+    let variant_id_to_fields = |_: VariantId| rust_ir::AdtVariantDatum { fields: vec![] };
+
+    let (kind, variants) = match adt_id {
+        hir_def::AdtId::StructId(id) => {
+            (rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())])
+        }
+        hir_def::AdtId::EnumId(id) => {
+            let variants = db
+                .enum_data(id)
+                .variants
+                .iter()
+                .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into()))
+                .collect();
+            (rust_ir::AdtKind::Enum, variants)
+        }
+        hir_def::AdtId::UnionId(id) => {
+            (rust_ir::AdtKind::Union, vec![variant_id_to_fields(id.into())])
+        }
+    };
+
+    let struct_datum_bound = rust_ir::AdtDatumBound { variants, where_clauses };
+    let struct_datum = AdtDatum {
+        kind,
+        id: chalk_ir::AdtId(adt_id),
         binders: make_binders(db, &generic_params, struct_datum_bound),
         flags,
     };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index fbd366864a4..f9e8cff5539 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -90,7 +90,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::cycle(crate::lower::ty_recover)]
     fn ty(&self, def: TyDefId) -> Binders<Ty>;
 
-    /// Returns the type of the value of the given constant, or `None` if the the `ValueTyDefId` is
+    /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
     /// a `StructId` or `EnumVariantId` with a record constructor.
     #[salsa::invoke(crate::lower::value_ty_query)]
     fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>;
@@ -220,12 +220,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         trait_id: chalk_db::TraitId,
     ) -> sync::Arc<chalk_db::TraitDatum>;
 
-    #[salsa::invoke(chalk_db::struct_datum_query)]
-    fn struct_datum(
+    #[salsa::invoke(chalk_db::adt_datum_query)]
+    fn adt_datum(
         &self,
         krate: CrateId,
         struct_id: chalk_db::AdtId,
-    ) -> sync::Arc<chalk_db::StructDatum>;
+    ) -> sync::Arc<chalk_db::AdtDatum>;
 
     #[salsa::invoke(chalk_db::impl_datum_query)]
     fn impl_datum(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index c4329a7b82b..6c8a1875165 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -12,6 +12,8 @@ use hir_expand::name;
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::usefulness::{compute_match_usefulness, ValidityConstraint};
+use syntax::{ast, AstNode};
+use tracing::debug;
 use triomphe::Arc;
 use typed_arena::Arena;
 
@@ -44,6 +46,10 @@ pub enum BodyValidationDiagnostic {
         match_expr: ExprId,
         uncovered_patterns: String,
     },
+    NonExhaustiveLet {
+        pat: PatId,
+        uncovered_patterns: String,
+    },
     RemoveTrailingReturn {
         return_expr: ExprId,
     },
@@ -57,7 +63,8 @@ impl BodyValidationDiagnostic {
         let _p =
             tracing::span!(tracing::Level::INFO, "BodyValidationDiagnostic::collect").entered();
         let infer = db.infer(owner);
-        let mut validator = ExprValidator::new(owner, infer);
+        let body = db.body(owner);
+        let mut validator = ExprValidator { owner, body, infer, diagnostics: Vec::new() };
         validator.validate_body(db);
         validator.diagnostics
     }
@@ -65,18 +72,16 @@ impl BodyValidationDiagnostic {
 
 struct ExprValidator {
     owner: DefWithBodyId,
+    body: Arc<Body>,
     infer: Arc<InferenceResult>,
-    pub(super) diagnostics: Vec<BodyValidationDiagnostic>,
+    diagnostics: Vec<BodyValidationDiagnostic>,
 }
 
 impl ExprValidator {
-    fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> ExprValidator {
-        ExprValidator { owner, infer, diagnostics: Vec::new() }
-    }
-
     fn validate_body(&mut self, db: &dyn HirDatabase) {
-        let body = db.body(self.owner);
         let mut filter_map_next_checker = None;
+        // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint
+        let body = Arc::clone(&self.body);
 
         if matches!(self.owner, DefWithBodyId::FunctionId(_)) {
             self.check_for_trailing_return(body.body_expr, &body);
@@ -104,7 +109,10 @@ impl ExprValidator {
                     self.check_for_trailing_return(*body_expr, &body);
                 }
                 Expr::If { .. } => {
-                    self.check_for_unnecessary_else(id, expr, &body);
+                    self.check_for_unnecessary_else(id, expr, db);
+                }
+                Expr::Block { .. } => {
+                    self.validate_block(db, expr);
                 }
                 _ => {}
             }
@@ -162,8 +170,6 @@ impl ExprValidator {
         arms: &[MatchArm],
         db: &dyn HirDatabase,
     ) {
-        let body = db.body(self.owner);
-
         let scrut_ty = &self.infer[scrutinee_expr];
         if scrut_ty.is_unknown() {
             return;
@@ -191,12 +197,12 @@ impl ExprValidator {
                         .as_reference()
                         .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
                         .unwrap_or(false))
-                    && types_of_subpatterns_do_match(arm.pat, &body, &self.infer)
+                    && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
                 {
                     // If we had a NotUsefulMatchArm diagnostic, we could
                     // check the usefulness of each pattern as we added it
                     // to the matrix here.
-                    let pat = self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors);
+                    let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
                     let m_arm = pat_analysis::MatchArm {
                         pat: pattern_arena.alloc(pat),
                         has_guard: arm.guard.is_some(),
@@ -234,20 +240,63 @@ impl ExprValidator {
         if !witnesses.is_empty() {
             self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms {
                 match_expr,
-                uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, arms),
+                uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, m_arms.is_empty()),
             });
         }
     }
 
+    fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
+        let Expr::Block { statements, .. } = expr else { return };
+        let pattern_arena = Arena::new();
+        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db);
+        for stmt in &**statements {
+            let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
+                continue;
+            };
+            let Some(initializer) = initializer else { continue };
+            let ty = &self.infer[initializer];
+
+            let mut have_errors = false;
+            let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
+            let match_arm = rustc_pattern_analysis::MatchArm {
+                pat: pattern_arena.alloc(deconstructed_pat),
+                has_guard: false,
+                arm_data: (),
+            };
+            if have_errors {
+                continue;
+            }
+
+            let report = match compute_match_usefulness(
+                &cx,
+                &[match_arm],
+                ty.clone(),
+                ValidityConstraint::ValidOnly,
+            ) {
+                Ok(v) => v,
+                Err(e) => {
+                    debug!(?e, "match usefulness error");
+                    continue;
+                }
+            };
+            let witnesses = report.non_exhaustiveness_witnesses;
+            if !witnesses.is_empty() {
+                self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet {
+                    pat,
+                    uncovered_patterns: missing_match_arms(&cx, ty, witnesses, false),
+                });
+            }
+        }
+    }
+
     fn lower_pattern<'p>(
         &self,
         cx: &MatchCheckCtx<'p>,
         pat: PatId,
         db: &dyn HirDatabase,
-        body: &Body,
         have_errors: &mut bool,
     ) -> DeconstructedPat<'p> {
-        let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
+        let mut patcx = match_check::PatCtxt::new(db, &self.infer, &self.body);
         let pattern = patcx.lower_pattern(pat);
         let pattern = cx.lower_pat(&pattern);
         if !patcx.errors.is_empty() {
@@ -288,12 +337,12 @@ impl ExprValidator {
         }
     }
 
-    fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, body: &Body) {
+    fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) {
         if let Expr::If { condition: _, then_branch, else_branch } = expr {
             if else_branch.is_none() {
                 return;
             }
-            if let Expr::Block { statements, tail, .. } = &body.exprs[*then_branch] {
+            if let Expr::Block { statements, tail, .. } = &self.body.exprs[*then_branch] {
                 let last_then_expr = tail.or_else(|| match statements.last()? {
                     Statement::Expr { expr, .. } => Some(*expr),
                     _ => None,
@@ -301,6 +350,36 @@ impl ExprValidator {
                 if let Some(last_then_expr) = last_then_expr {
                     let last_then_expr_ty = &self.infer[last_then_expr];
                     if last_then_expr_ty.is_never() {
+                        // Only look at sources if the then branch diverges and we have an else branch.
+                        let (_, source_map) = db.body_with_source_map(self.owner);
+                        let Ok(source_ptr) = source_map.expr_syntax(id) else {
+                            return;
+                        };
+                        let root = source_ptr.file_syntax(db.upcast());
+                        let ast::Expr::IfExpr(if_expr) = source_ptr.value.to_node(&root) else {
+                            return;
+                        };
+                        let mut top_if_expr = if_expr;
+                        loop {
+                            let parent = top_if_expr.syntax().parent();
+                            let has_parent_expr_stmt_or_stmt_list =
+                                parent.as_ref().map_or(false, |node| {
+                                    ast::ExprStmt::can_cast(node.kind())
+                                        | ast::StmtList::can_cast(node.kind())
+                                });
+                            if has_parent_expr_stmt_or_stmt_list {
+                                // Only emit diagnostic if parent or direct ancestor is either
+                                // an expr stmt or a stmt list.
+                                break;
+                            }
+                            let Some(parent_if_expr) = parent.and_then(ast::IfExpr::cast) else {
+                                // Bail if parent is neither an if expr, an expr stmt nor a stmt list.
+                                return;
+                            };
+                            // Check parent if expr.
+                            top_if_expr = parent_if_expr;
+                        }
+
                         self.diagnostics
                             .push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id })
                     }
@@ -448,7 +527,7 @@ fn missing_match_arms<'p>(
     cx: &MatchCheckCtx<'p>,
     scrut_ty: &Ty,
     witnesses: Vec<WitnessPat<'p>>,
-    arms: &[MatchArm],
+    arms_is_empty: bool,
 ) -> String {
     struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>);
     impl fmt::Display for DisplayWitness<'_, '_> {
@@ -463,7 +542,7 @@ fn missing_match_arms<'p>(
         Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
         _ => false,
     };
-    if arms.is_empty() && !non_empty_enum {
+    if arms_is_empty && !non_empty_enum {
         format!("type `{}` is non-empty", scrut_ty.display(cx.db))
     } else {
         let pat_display = |witness| DisplayWitness(witness, cx);
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 1977f00517c..9cea414e1a0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -221,6 +221,9 @@ pub enum InferenceDiagnostic {
     UnresolvedAssocItem {
         id: ExprOrPatId,
     },
+    UnresolvedIdent {
+        expr: ExprId,
+    },
     // FIXME: This should be emitted in body lowering
     BreakOutsideOfLoop {
         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 428ed6748c6..c377a51e7d3 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
@@ -13,7 +13,7 @@ use hir_def::{
         ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
     },
     lang_item::{LangItem, LangItemTarget},
-    path::{GenericArg, GenericArgs},
+    path::{GenericArg, GenericArgs, Path},
     BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, TupleFieldId, TupleId,
 };
 use hir_expand::name::{name, Name};
@@ -439,7 +439,17 @@ impl InferenceContext<'_> {
             }
             Expr::Path(p) => {
                 let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
-                let ty = self.infer_path(p, tgt_expr.into()).unwrap_or_else(|| self.err_ty());
+                let ty = match self.infer_path(p, tgt_expr.into()) {
+                    Some(ty) => ty,
+                    None => {
+                        if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident()) {
+                            self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent {
+                                expr: tgt_expr,
+                            });
+                        }
+                        self.err_ty()
+                    }
+                };
                 self.resolver.reset_to_guard(g);
                 ty
             }
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 fbe6a982d6f..628a1fe2d28 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
@@ -1,12 +1,20 @@
 //! Interpret intrinsics, lang items and `extern "C"` wellknown functions which their implementation
 //! is not available.
-
+//!
 use std::cmp;
 
 use chalk_ir::TyKind;
-use hir_def::builtin_type::{BuiltinInt, BuiltinUint};
+use hir_def::{
+    builtin_type::{BuiltinInt, BuiltinUint},
+    resolver::HasResolver,
+};
 
-use super::*;
+use crate::mir::eval::{
+    name, pad16, static_lifetime, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId,
+    HasModule, HirDisplay, Interned, InternedClosure, Interner, Interval, IntervalAndTy,
+    IntervalOrOwned, ItemContainerId, LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan,
+    ModPath, Mutability, Result, Substitution, Ty, TyBuilder, TyExt,
+};
 
 mod simd;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
index eddfd0acfb9..e229a4ab317 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -2,6 +2,7 @@
 
 use std::cmp::Ordering;
 
+use crate::consteval::try_const_usize;
 use crate::TyKind;
 
 use super::*;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 9fe3d5b77ae..ed316f97268 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -1,6 +1,6 @@
 //! This module generates a polymorphic MIR from a hir body
 
-use std::{fmt::Write, mem};
+use std::{fmt::Write, iter, mem};
 
 use base_db::{salsa::Cycle, FileId};
 use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
@@ -14,27 +14,37 @@ use hir_def::{
     lang_item::{LangItem, LangItemTarget},
     path::Path,
     resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
-    AdtId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
+    AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
     Lookup, TraitId, TupleId, TypeOrConstParamId,
 };
 use hir_expand::name::Name;
+use la_arena::ArenaMap;
+use rustc_hash::FxHashMap;
 use syntax::TextRange;
 use triomphe::Arc;
 
 use crate::{
     consteval::ConstEvalError,
-    db::InternedClosure,
+    db::{HirDatabase, InternedClosure},
+    display::HirDisplay,
     infer::{CaptureKind, CapturedItem, TypeMismatch},
     inhabitedness::is_ty_uninhabited_from,
     layout::LayoutError,
+    mapping::ToChalk,
+    mir::{
+        intern_const_scalar, return_slot, AggregateKind, Arena, BasicBlock, BasicBlockId, BinOp,
+        BorrowKind, CastKind, ClosureId, ConstScalar, Either, Expr, FieldId, Idx, InferenceResult,
+        Interner, Local, LocalId, MemoryMap, MirBody, MirSpan, Mutability, Operand, Place,
+        PlaceElem, PointerCast, ProjectionElem, ProjectionStore, RawIdx, Rvalue, Statement,
+        StatementKind, Substitution, SwitchTargets, Terminator, TerminatorKind, TupleFieldId, Ty,
+        UnOp, VariantId,
+    },
     static_lifetime,
     traits::FnTrait,
     utils::{generics, ClosureSubst},
     Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
 };
 
-use super::*;
-
 mod as_place;
 mod pattern_matching;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 02b1494062f..85c8d1685b8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,10 +1,17 @@
 //! MIR lowering for patterns
 
-use hir_def::AssocItemId;
+use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
 
-use crate::BindingMode;
-
-use super::*;
+use crate::{
+    mir::lower::{
+        BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner,
+        MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place,
+        PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue,
+        Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind,
+        ValueNs, VariantData, VariantId,
+    },
+    BindingMode,
+};
 
 macro_rules! not_supported {
     ($x: expr) => {
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 db14addaf18..879c69c758f 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
@@ -4553,3 +4553,58 @@ fn foo() {
 "#,
     );
 }
+
+#[test]
+fn auto_trait_bound() {
+    check_types(
+        r#"
+//- minicore: sized
+auto trait Send {}
+impl<T> !Send for *const T {}
+
+struct Yes;
+trait IsSend { const IS_SEND: Yes; }
+impl<T: Send> IsSend for T { const IS_SEND: Yes = Yes; }
+
+struct Struct<T>(T);
+enum Enum<T> { A, B(T) }
+union Union<T> { t: T }
+
+#[lang = "phantom_data"]
+struct PhantomData<T: ?Sized>;
+
+fn f<T: Send, U>() {
+    T::IS_SEND;
+  //^^^^^^^^^^Yes
+    U::IS_SEND;
+  //^^^^^^^^^^{unknown}
+    <*const T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^{unknown}
+    Struct::<T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^Yes
+    Struct::<U>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^Yes
+    Struct::<*const T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+    Enum::<T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^Yes
+    Enum::<U>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^Yes
+    Enum::<*const T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+    Union::<T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^Yes
+    Union::<U>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^Yes
+    Union::<*const T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+    PhantomData::<T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+    PhantomData::<U>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
+    PhantomData::<*const T>::IS_SEND;
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 08843a6c999..80cd0c9c794 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -64,6 +64,7 @@ diagnostics![
     MissingUnsafe,
     MovedOutOfRef,
     NeedMut,
+    NonExhaustiveLet,
     NoSuchField,
     PrivateAssocItem,
     PrivateField,
@@ -86,6 +87,7 @@ diagnostics![
     UnresolvedMacroCall,
     UnresolvedMethodCall,
     UnresolvedModule,
+    UnresolvedIdent,
     UnresolvedProcMacro,
     UnusedMut,
     UnusedVariable,
@@ -242,6 +244,11 @@ pub struct UnresolvedAssocItem {
 }
 
 #[derive(Debug)]
+pub struct UnresolvedIdent {
+    pub expr: InFile<AstPtr<ast::Expr>>,
+}
+
+#[derive(Debug)]
 pub struct PrivateField {
     pub expr: InFile<AstPtr<ast::Expr>>,
     pub field: Field,
@@ -281,6 +288,12 @@ pub struct MissingMatchArms {
 }
 
 #[derive(Debug)]
+pub struct NonExhaustiveLet {
+    pub pat: InFile<AstPtr<ast::Pat>>,
+    pub uncovered_patterns: String,
+}
+
+#[derive(Debug)]
 pub struct TypeMismatch {
     pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
     pub expected: Type,
@@ -456,6 +469,22 @@ impl AnyDiagnostic {
                     Err(SyntheticSyntax) => (),
                 }
             }
+            BodyValidationDiagnostic::NonExhaustiveLet { pat, uncovered_patterns } => {
+                match source_map.pat_syntax(pat) {
+                    Ok(source_ptr) => {
+                        if let Some(ast_pat) = source_ptr.value.cast::<ast::Pat>() {
+                            return Some(
+                                NonExhaustiveLet {
+                                    pat: InFile::new(source_ptr.file_id, ast_pat),
+                                    uncovered_patterns,
+                                }
+                                .into(),
+                            );
+                        }
+                    }
+                    Err(SyntheticSyntax) => {}
+                }
+            }
             BodyValidationDiagnostic::RemoveTrailingReturn { return_expr } => {
                 if let Ok(source_ptr) = source_map.expr_syntax(return_expr) {
                     // Filters out desugared return expressions (e.g. desugared try operators).
@@ -565,6 +594,10 @@ impl AnyDiagnostic {
                 };
                 UnresolvedAssocItem { expr_or_pat }.into()
             }
+            &InferenceDiagnostic::UnresolvedIdent { expr } => {
+                let expr = expr_syntax(expr);
+                UnresolvedIdent { expr }.into()
+            }
             &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
                 let expr = expr_syntax(expr);
                 BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 08f7bb14caa..2d8811cf5eb 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -2653,6 +2653,37 @@ impl ItemInNs {
     }
 }
 
+/// Invariant: `inner.as_extern_assoc_item(db).is_some()`
+/// We do not actively enforce this invariant.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum ExternAssocItem {
+    Function(Function),
+    Static(Static),
+    TypeAlias(TypeAlias),
+}
+
+pub trait AsExternAssocItem {
+    fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem>;
+}
+
+impl AsExternAssocItem for Function {
+    fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
+        as_extern_assoc_item(db, ExternAssocItem::Function, self.id)
+    }
+}
+
+impl AsExternAssocItem for Static {
+    fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
+        as_extern_assoc_item(db, ExternAssocItem::Static, self.id)
+    }
+}
+
+impl AsExternAssocItem for TypeAlias {
+    fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
+        as_extern_assoc_item(db, ExternAssocItem::TypeAlias, self.id)
+    }
+}
+
 /// Invariant: `inner.as_assoc_item(db).is_some()`
 /// We do not actively enforce this invariant.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -2727,6 +2758,63 @@ where
     }
 }
 
+fn as_extern_assoc_item<'db, ID, DEF, LOC>(
+    db: &(dyn HirDatabase + 'db),
+    ctor: impl FnOnce(DEF) -> ExternAssocItem,
+    id: ID,
+) -> Option<ExternAssocItem>
+where
+    ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<LOC>>,
+    DEF: From<ID>,
+    LOC: ItemTreeNode,
+{
+    match id.lookup(db.upcast()).container {
+        ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))),
+        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) | ItemContainerId::ModuleId(_) => {
+            None
+        }
+    }
+}
+
+impl ExternAssocItem {
+    pub fn name(self, db: &dyn HirDatabase) -> Name {
+        match self {
+            Self::Function(it) => it.name(db),
+            Self::Static(it) => it.name(db),
+            Self::TypeAlias(it) => it.name(db),
+        }
+    }
+
+    pub fn module(self, db: &dyn HirDatabase) -> Module {
+        match self {
+            Self::Function(f) => f.module(db),
+            Self::Static(c) => c.module(db),
+            Self::TypeAlias(t) => t.module(db),
+        }
+    }
+
+    pub fn as_function(self) -> Option<Function> {
+        match self {
+            Self::Function(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    pub fn as_static(self) -> Option<Static> {
+        match self {
+            Self::Static(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    pub fn as_type_alias(self) -> Option<TypeAlias> {
+        match self {
+            Self::TypeAlias(v) => Some(v),
+            _ => None,
+        }
+    }
+}
+
 impl AssocItem {
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
         match self {
@@ -3798,9 +3886,9 @@ impl Type {
 
                 // For non-phantom_data adts we check variants/fields as well as generic parameters
                 TyKind::Adt(adt_id, substitution)
-                    if !db.struct_datum(krate, *adt_id).flags.phantom_data =>
+                    if !db.adt_datum(krate, *adt_id).flags.phantom_data =>
                 {
-                    let adt_datum = &db.struct_datum(krate, *adt_id);
+                    let adt_datum = &db.adt_datum(krate, *adt_id);
                     let adt_datum_bound =
                         adt_datum.binders.clone().substitute(Interner, substitution);
                     adt_datum_bound
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 666d63ac155..edbf75affe6 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
@@ -281,14 +281,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
                         if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) {
                             return None;
                         }
-                        let fileds = it.fields(db);
+                        let fields = it.fields(db);
                         // Check if all fields are visible, otherwise we cannot fill them
-                        if fileds.iter().any(|it| !it.is_visible_from(db, module)) {
+                        if fields.iter().any(|it| !it.is_visible_from(db, module)) {
                             return None;
                         }
 
                         // Early exit if some param cannot be filled from lookup
-                        let param_exprs: Vec<Vec<Expr>> = fileds
+                        let param_exprs: Vec<Vec<Expr>> = fields
                             .into_iter()
                             .map(|field| lookup.find(db, &field.ty(db)))
                             .collect::<Option<_>>()?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index c2c0641961a..4bab2886851 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -308,7 +308,7 @@ impl CompletionRelevance {
 
                 // When a fn is bumped due to return type:
                 // Bump Constructor or Builder methods with no arguments,
-                // over them tha with self arguments
+                // over them than with self arguments
                 if fn_score > 0 {
                     if !asf.has_params {
                         // bump associated functions
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index 296253aa1ee..2b2df144d6d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -17,7 +17,7 @@ impl RootDatabase {
     pub fn request_cancellation(&mut self) {
         let _p =
             tracing::span!(tracing::Level::INFO, "RootDatabase::request_cancellation").entered();
-        self.salsa_runtime_mut().synthetic_write(Durability::LOW);
+        self.synthetic_write(Durability::LOW);
     }
 
     pub fn apply_change(&mut self, change: Change) {
@@ -124,7 +124,7 @@ impl RootDatabase {
             hir::db::InternCoroutineQuery
             hir::db::AssociatedTyDataQuery
             hir::db::TraitDatumQuery
-            hir::db::StructDatumQuery
+            hir::db::AdtDatumQuery
             hir::db::ImplDatumQuery
             hir::db::FnDefDatumQuery
             hir::db::FnDefVarianceQuery
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 d95d94ec72e..1b6ff8bad53 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -8,11 +8,11 @@
 use arrayvec::ArrayVec;
 use either::Either;
 use hir::{
-    Adt, AsAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate,
-    DefWithBody, DeriveHelper, DocLinkDef, ExternCrateDecl, Field, Function, GenericParam,
-    HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, ModuleDef, Name, PathResolution,
-    Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef,
-    Visibility,
+    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,
 };
 use stdx::{format_to, impl_from};
 use syntax::{
@@ -213,8 +213,8 @@ impl Definition {
         })
     }
 
-    pub fn label(&self, db: &RootDatabase) -> Option<String> {
-        let label = match *self {
+    pub fn label(&self, db: &RootDatabase) -> String {
+        match *self {
             Definition::Macro(it) => it.display(db).to_string(),
             Definition::Field(it) => it.display(db).to_string(),
             Definition::TupleField(it) => it.display(db).to_string(),
@@ -241,7 +241,11 @@ impl Definition {
                 }
             }
             Definition::SelfType(impl_def) => {
-                impl_def.self_ty(db).as_adt().and_then(|adt| Definition::Adt(adt).label(db))?
+                let self_ty = &impl_def.self_ty(db);
+                match self_ty.as_adt() {
+                    Some(it) => it.display(db).to_string(),
+                    None => self_ty.display(db).to_string(),
+                }
             }
             Definition::GenericParam(it) => it.display(db).to_string(),
             Definition::Label(it) => it.name(db).display(db).to_string(),
@@ -249,8 +253,7 @@ impl Definition {
             Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)),
             Definition::ToolModule(it) => it.name(db).to_string(),
             Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)),
-        };
-        Some(label)
+        }
     }
 }
 
@@ -739,6 +742,17 @@ impl AsAssocItem for Definition {
     }
 }
 
+impl AsExternAssocItem for Definition {
+    fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option<ExternAssocItem> {
+        match self {
+            Definition::Function(it) => it.as_extern_assoc_item(db),
+            Definition::Static(it) => it.as_extern_assoc_item(db),
+            Definition::TypeAlias(it) => it.as_extern_assoc_item(db),
+            _ => None,
+        }
+    }
+}
+
 impl From<AssocItem> for Definition {
     fn from(assoc_item: AssocItem) -> Self {
         match assoc_item {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs
index 6b0fecae267..10c285a13fb 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs
@@ -1,4 +1,3 @@
-use hir::PrefixKind;
 use stdx::trim_indent;
 use test_fixture::WithFixture;
 use test_utils::{assert_eq_text, CURSOR_MARKER};
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index 2881748dd47..d31dad514aa 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -280,7 +280,7 @@ impl RootDatabase {
             // hir_db::InternCoroutineQuery
             hir_db::AssociatedTyDataQuery
             hir_db::TraitDatumQuery
-            hir_db::StructDatumQuery
+            hir_db::AdtDatumQuery
             hir_db::ImplDatumQuery
             hir_db::FnDefDatumQuery
             hir_db::FnDefVarianceQuery
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 722161282fe..c65467a4324 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
@@ -394,7 +394,6 @@ impl Query {
 mod tests {
 
     use expect_test::expect_file;
-    use hir::symbols::SymbolCollector;
     use test_fixture::WithFixture;
 
     use super::*;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 7db5ea04fbd..785a42352bf 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -60,6 +60,7 @@ fn f() {
     #[cfg(a)] let x = 0; // let statement
   //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
 
+    fn abc() {}
     abc(#[cfg(a)] 0);
       //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
     let x = Struct {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 5e2541795ca..db28928a24e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -512,7 +512,7 @@ impl BAD_TRAIT for () {
     fn BadFunction() {}
 }
     "#,
-            std::iter::once("unused_variables".to_owned()),
+            &["unused_variables"],
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index c70f39eb286..09daefd084d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -634,7 +634,8 @@ struct TestStruct { one: i32, two: i64 }
 
 fn test_fn() {
     let one = 1;
-    let s = TestStruct{ ..a };
+    let a = TestStruct{ one, two: 2 };
+    let _ = TestStruct{ ..a };
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 7632fdf1d09..8596f5792e0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -18,7 +18,9 @@ pub(crate) fn missing_match_arms(
 #[cfg(test)]
 mod tests {
     use crate::{
-        tests::{check_diagnostics, check_diagnostics_with_config},
+        tests::{
+            check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled,
+        },
         DiagnosticsConfig,
     };
 
@@ -282,7 +284,7 @@ fn main() {
         cov_mark::check_count!(validate_match_bailed_out, 4);
         // Match statements with arms that don't match the
         // expression pattern do not fire this diagnostic.
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 enum Either { A, B }
 enum Either2 { C, D }
@@ -307,6 +309,7 @@ fn main() {
     match Unresolved::Bar { Unresolved::Baz => () }
 }
         "#,
+            &["E0425"],
         );
     }
 
@@ -397,11 +400,11 @@ fn main() {
     match loop {} {
         Either::A => (),
     }
-    match loop { break Foo::A } {
-        //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
+    match loop { break Either::A } {
+        //^^^^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
         Either::A => (),
     }
-    match loop { break Foo::A } {
+    match loop { break Either::A } {
         Either::A => (),
         Either::B => (),
     }
@@ -977,7 +980,7 @@ fn f(ty: Enum) {
     #[test]
     fn unexpected_ty_fndef() {
         cov_mark::check!(validate_match_bailed_out);
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r"
 enum Exp {
     Tuple(()),
@@ -987,6 +990,7 @@ fn f() {
         Exp::Tuple => {}
     }
 }",
+            &["E0425"],
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index bdb55a9d98a..91f1058d65b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -448,7 +448,7 @@ fn main(b: bool) {
     &mut x;
 }
 "#,
-            std::iter::once("remove-unnecessary-else".to_owned()),
+            &["remove-unnecessary-else"],
         );
         check_diagnostics_with_disabled(
             r#"
@@ -463,7 +463,7 @@ fn main(b: bool) {
     &mut x;
 }
 "#,
-            std::iter::once("remove-unnecessary-else".to_owned()),
+            &["remove-unnecessary-else"],
         );
     }
 
@@ -817,7 +817,7 @@ fn f() {
 //- minicore: option
 fn f(_: i32) {}
 fn main() {
-    let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7));
+    let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)) else { return };
              //^^^^^ 💡 warn: variable does not need to be mutable
     f(x);
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
new file mode 100644
index 00000000000..1a4d2877ef2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -0,0 +1,47 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: non-exhaustive-let
+//
+// This diagnostic is triggered if a `let` statement without an `else` branch has a non-exhaustive
+// pattern.
+pub(crate) fn non_exhaustive_let(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::NonExhaustiveLet,
+) -> Diagnostic {
+    Diagnostic::new_with_syntax_node_ptr(
+        ctx,
+        DiagnosticCode::RustcHardError("E0005"),
+        format!("non-exhaustive pattern: {}", d.uncovered_patterns),
+        d.pat.map(Into::into),
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn option_nonexhaustive() {
+        check_diagnostics(
+            r#"
+//- minicore: option
+fn main() {
+    let None = Some(5);
+      //^^^^ error: non-exhaustive pattern: `Some(_)` not covered
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn option_exhaustive() {
+        check_diagnostics(
+            r#"
+//- minicore: option
+fn main() {
+    let Some(_) | None = Some(5);
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index b7667dc318f..7a040e46e33 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -140,7 +140,7 @@ fn foo(x: usize) -> u8 {
     } //^^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
 }
 "#,
-            std::iter::once("remove-unnecessary-else".to_owned()),
+            &["remove-unnecessary-else"],
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index ae8241ec2c6..47844876dc5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -2,7 +2,10 @@ use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt};
 use ide_db::{assists::Assist, source_change::SourceChange};
 use itertools::Itertools;
 use syntax::{
-    ast::{self, edit::IndentLevel},
+    ast::{
+        self,
+        edit::{AstNodeEdit, IndentLevel},
+    },
     AstNode, SyntaxToken, TextRange,
 };
 use text_edit::TextEdit;
@@ -41,10 +44,15 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option<Vec<
         indent = indent + 1;
     }
     let else_replacement = match if_expr.else_branch()? {
-        ast::ElseBranch::Block(ref block) => {
-            block.statements().map(|stmt| format!("\n{indent}{stmt}")).join("")
-        }
-        ast::ElseBranch::IfExpr(ref nested_if_expr) => {
+        ast::ElseBranch::Block(block) => block
+            .statements()
+            .map(|stmt| format!("\n{indent}{stmt}"))
+            .chain(block.tail_expr().map(|tail| format!("\n{indent}{tail}")))
+            .join(""),
+        ast::ElseBranch::IfExpr(mut nested_if_expr) => {
+            if has_parent_if_expr {
+                nested_if_expr = nested_if_expr.indent(IndentLevel(1))
+            }
             format!("\n{indent}{nested_if_expr}")
         }
     };
@@ -87,15 +95,11 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option<Vec<
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
-
-    fn check_diagnostics_with_needless_return_disabled(ra_fixture: &str) {
-        check_diagnostics_with_disabled(ra_fixture, std::iter::once("needless_return".to_owned()));
-    }
+    use crate::tests::{check_diagnostics_with_disabled, check_fix};
 
     #[test]
     fn remove_unnecessary_else_for_return() {
-        check_diagnostics_with_needless_return_disabled(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -106,6 +110,7 @@ fn test() {
     }
 }
 "#,
+            &["needless_return", "E0425"],
         );
         check_fix(
             r#"
@@ -130,7 +135,7 @@ fn test() {
 
     #[test]
     fn remove_unnecessary_else_for_return2() {
-        check_diagnostics_with_needless_return_disabled(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -143,6 +148,7 @@ fn test() {
     }
 }
 "#,
+            &["needless_return", "E0425"],
         );
         check_fix(
             r#"
@@ -172,8 +178,44 @@ fn test() {
     }
 
     #[test]
+    fn remove_unnecessary_else_for_return3() {
+        check_diagnostics_with_disabled(
+            r#"
+fn test(a: bool) -> i32 {
+    if a {
+        return 1;
+    } else {
+    //^^^^ 💡 weak: remove unnecessary else block
+        0
+    }
+}
+"#,
+            &["needless_return", "E0425"],
+        );
+        check_fix(
+            r#"
+fn test(a: bool) -> i32 {
+    if a {
+        return 1;
+    } else$0 {
+        0
+    }
+}
+"#,
+            r#"
+fn test(a: bool) -> i32 {
+    if a {
+        return 1;
+    }
+    0
+}
+"#,
+        );
+    }
+
+    #[test]
     fn remove_unnecessary_else_for_return_in_child_if_expr() {
-        check_diagnostics_with_needless_return_disabled(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -186,6 +228,7 @@ fn test() {
     }
 }
 "#,
+            &["needless_return", "E0425"],
         );
         check_fix(
             r#"
@@ -215,8 +258,43 @@ fn test() {
     }
 
     #[test]
+    fn remove_unnecessary_else_for_return_in_child_if_expr2() {
+        check_fix(
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else if qux {
+        return bar;
+    } else$0 if quux {
+        do_something_else();
+    } else {
+        do_something_else2();
+    }
+}
+"#,
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else {
+        if qux {
+            return bar;
+        }
+        if quux {
+            do_something_else();
+        } else {
+            do_something_else2();
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn remove_unnecessary_else_for_break() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     loop {
@@ -229,6 +307,7 @@ fn test() {
     }
 }
 "#,
+            &["E0425"],
         );
         check_fix(
             r#"
@@ -257,7 +336,7 @@ fn test() {
 
     #[test]
     fn remove_unnecessary_else_for_continue() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     loop {
@@ -270,6 +349,7 @@ fn test() {
     }
 }
 "#,
+            &["E0425"],
         );
         check_fix(
             r#"
@@ -298,7 +378,7 @@ fn test() {
 
     #[test]
     fn remove_unnecessary_else_for_never() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -313,6 +393,7 @@ fn never() -> ! {
     loop {}
 }
 "#,
+            &["E0425"],
         );
         check_fix(
             r#"
@@ -345,7 +426,7 @@ fn never() -> ! {
 
     #[test]
     fn no_diagnostic_if_no_else_branch() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -355,12 +436,13 @@ fn test() {
     do_something_else();
 }
 "#,
+            &["E0425"],
         );
     }
 
     #[test]
     fn no_diagnostic_if_no_divergence() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -370,12 +452,13 @@ fn test() {
     }
 }
 "#,
+            &["E0425"],
         );
     }
 
     #[test]
     fn no_diagnostic_if_no_divergence_in_else_branch() {
-        check_diagnostics_with_needless_return_disabled(
+        check_diagnostics_with_disabled(
             r#"
 fn test() {
     if foo {
@@ -385,6 +468,43 @@ fn test() {
     }
 }
 "#,
+            &["needless_return", "E0425"],
+        );
+    }
+
+    #[test]
+    fn no_diagnostic_if_not_expr_stmt() {
+        check_diagnostics_with_disabled(
+            r#"
+fn test1() {
+    let _x = if a {
+        return;
+    } else {
+        1
+    };
+}
+
+fn test2() {
+    let _x = if a {
+        return;
+    } else if b {
+        return;
+    } else if c {
+        1
+    } else {
+        return;
+    };
+}
+"#,
+            &["needless_return", "E0425"],
+        );
+        check_diagnostics_with_disabled(
+            r#"
+fn test3() -> u8 {
+    foo(if a { return 1 } else { 0 })
+}
+"#,
+            &["E0425"],
         );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 8c97281b783..4c255322280 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -730,7 +730,7 @@ fn f() -> i32 {
 }
 fn g() { return; }
 "#,
-            std::iter::once("needless_return".to_owned()),
+            &["needless_return"],
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index a6a0fdc655f..97943b7e8b3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -38,10 +38,12 @@ fn foo() {
     fn while_let_loop_with_label_in_condition() {
         check_diagnostics(
             r#"
+//- minicore: option
+
 fn foo() {
     let mut optional = Some(0);
 
-    'my_label: while let Some(a) = match optional {
+    'my_label: while let Some(_) = match optional {
         None => break 'my_label,
         Some(val) => Some(val),
     } {
@@ -59,8 +61,8 @@ fn foo() {
             r#"
 //- minicore: iterator
 fn foo() {
-    'xxx: for _ in unknown {
-        'yyy: for _ in unknown {
+    'xxx: for _ in [] {
+        'yyy: for _ in [] {
             break 'xxx;
             continue 'yyy;
             break 'zzz;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 65abfd8a294..4c01a2d155a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -78,7 +78,9 @@ fn method_fix(
 #[cfg(test)]
 mod tests {
     use crate::{
-        tests::{check_diagnostics, check_diagnostics_with_config},
+        tests::{
+            check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled,
+        },
         DiagnosticsConfig,
     };
 
@@ -148,7 +150,7 @@ fn foo() {
 
     #[test]
     fn no_diagnostic_on_unknown() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn foo() {
     x.foo;
@@ -156,6 +158,7 @@ fn foo() {
     (&((x,),),).foo;
 }
 "#,
+            &["E0425"],
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
new file mode 100644
index 00000000000..295c8a2c615
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
@@ -0,0 +1,46 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: unresolved-ident
+//
+// This diagnostic is triggered if an expr-position ident is invalid.
+pub(crate) fn unresolved_ident(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::UnresolvedIdent,
+) -> Diagnostic {
+    Diagnostic::new_with_syntax_node_ptr(
+        ctx,
+        DiagnosticCode::RustcHardError("E0425"),
+        "no such value in this scope",
+        d.expr.map(Into::into),
+    )
+    .experimental()
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn missing() {
+        check_diagnostics(
+            r#"
+fn main() {
+    let _ = x;
+          //^ error: no such value in this scope
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn present() {
+        check_diagnostics(
+            r#"
+fn main() {
+    let x = 5;
+    let _ = x;
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 648d081898c..0614fdc5514 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -335,8 +335,8 @@ fn main() {
             r#"
 struct Foo { bar: i32 }
 fn foo() {
-    Foo { bar: i32 }.bar();
-                  // ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists
+    Foo { bar: 0 }.bar();
+                // ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists
 }
 "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 863a7ab783e..79bcaa0a9c4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -4,7 +4,7 @@ use ide_db::{
     source_change::SourceChange,
 };
 use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxNode};
+use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr};
 use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode};
@@ -43,7 +43,7 @@ pub(crate) fn useless_braces(
                 "Unnecessary braces in use statement".to_owned(),
                 FileRange { file_id, range: use_range },
             )
-            .with_main_node(InFile::new(file_id.into(), node.clone()))
+            .with_main_node(InFile::new(file_id.into(), SyntaxNodePtr::new(node)))
             .with_fixes(Some(vec![fix(
                 "remove_braces",
                 "Remove unnecessary braces",
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 9d21bb4cd9f..9f4368b04e7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -41,6 +41,7 @@ mod handlers {
     pub(crate) mod moved_out_of_ref;
     pub(crate) mod mutability_errors;
     pub(crate) mod no_such_field;
+    pub(crate) mod non_exhaustive_let;
     pub(crate) mod private_assoc_item;
     pub(crate) mod private_field;
     pub(crate) mod remove_trailing_return;
@@ -58,6 +59,7 @@ mod handlers {
     pub(crate) mod unresolved_assoc_item;
     pub(crate) mod unresolved_extern_crate;
     pub(crate) mod unresolved_field;
+    pub(crate) mod unresolved_ident;
     pub(crate) mod unresolved_import;
     pub(crate) mod unresolved_macro_call;
     pub(crate) mod unresolved_method;
@@ -140,7 +142,7 @@ pub struct Diagnostic {
     pub experimental: bool,
     pub fixes: Option<Vec<Assist>>,
     // The node that will be affected by `#[allow]` and similar attributes.
-    pub main_node: Option<InFile<SyntaxNode>>,
+    pub main_node: Option<InFile<SyntaxNodePtr>>,
 }
 
 impl Diagnostic {
@@ -172,9 +174,8 @@ impl Diagnostic {
         message: impl Into<String>,
         node: InFile<SyntaxNodePtr>,
     ) -> Diagnostic {
-        let file_id = node.file_id;
         Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node))
-            .with_main_node(node.map(|x| x.to_node(&ctx.sema.parse_or_expand(file_id))))
+            .with_main_node(node)
     }
 
     fn experimental(mut self) -> Diagnostic {
@@ -182,7 +183,7 @@ impl Diagnostic {
         self
     }
 
-    fn with_main_node(mut self, main_node: InFile<SyntaxNode>) -> Diagnostic {
+    fn with_main_node(mut self, main_node: InFile<SyntaxNodePtr>) -> Diagnostic {
         self.main_node = Some(main_node);
         self
     }
@@ -359,6 +360,7 @@ pub fn diagnostics(
             AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
             AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d),
             AnyDiagnostic::NeedMut(d) => handlers::mutability_errors::need_mut(&ctx, &d),
+            AnyDiagnostic::NonExhaustiveLet(d) => handlers::non_exhaustive_let::non_exhaustive_let(&ctx, &d),
             AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
             AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d),
             AnyDiagnostic::PrivateField(d) => handlers::private_field::private_field(&ctx, &d),
@@ -375,6 +377,7 @@ pub fn diagnostics(
             AnyDiagnostic::UnresolvedAssocItem(d) => handlers::unresolved_assoc_item::unresolved_assoc_item(&ctx, &d),
             AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
             AnyDiagnostic::UnresolvedField(d) => handlers::unresolved_field::unresolved_field(&ctx, &d),
+            AnyDiagnostic::UnresolvedIdent(d) => handlers::unresolved_ident::unresolved_ident(&ctx, &d),
             AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
             AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
             AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d),
@@ -390,8 +393,17 @@ pub fn diagnostics(
         res.push(d)
     }
 
-    let mut diagnostics_of_range =
-        res.iter_mut().filter_map(|x| Some((x.main_node.clone()?, x))).collect::<FxHashMap<_, _>>();
+    let mut diagnostics_of_range = res
+        .iter_mut()
+        .filter_map(|it| {
+            Some((
+                it.main_node
+                    .map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id))))
+                    .clone()?,
+                it,
+            ))
+        })
+        .collect::<FxHashMap<_, _>>();
 
     let mut rustc_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
     let mut clippy_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
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 4e4a851f67e..901ceffbb26 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -198,12 +198,9 @@ pub(crate) fn check_diagnostics(ra_fixture: &str) {
 }
 
 #[track_caller]
-pub(crate) fn check_diagnostics_with_disabled(
-    ra_fixture: &str,
-    disabled: impl Iterator<Item = String>,
-) {
+pub(crate) fn check_diagnostics_with_disabled(ra_fixture: &str, disabled: &[&str]) {
     let mut config = DiagnosticsConfig::test_sample();
-    config.disabled.extend(disabled);
+    config.disabled.extend(disabled.iter().map(|&s| s.to_owned()));
     check_diagnostics_with_config(config, ra_fixture)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 19b181ae3b6..4a7350feb38 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -147,7 +147,7 @@ fn hover_simple(
     if let Some(doc_comment) = token_as_doc_comment(&original_token) {
         cov_mark::hit!(no_highlight_on_comment_hover);
         return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
-            let res = hover_for_definition(sema, file_id, def, &node, config)?;
+            let res = hover_for_definition(sema, file_id, def, &node, config);
             Some(RangeInfo::new(range, res))
         });
     }
@@ -161,7 +161,7 @@ fn hover_simple(
             Definition::from(resolution?),
             &original_token.parent()?,
             config,
-        )?;
+        );
         return Some(RangeInfo::new(range, res));
     }
 
@@ -215,7 +215,7 @@ fn hover_simple(
                 })
                 .flatten()
                 .unique_by(|&(def, _)| def)
-                .filter_map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
+                .map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
                 .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
                     acc.actions.extend(actions);
                     acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
@@ -373,9 +373,9 @@ pub(crate) fn hover_for_definition(
     def: Definition,
     scope_node: &SyntaxNode,
     config: &HoverConfig,
-) -> Option<HoverResult> {
+) -> HoverResult {
     let famous_defs = match &def {
-        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(scope_node)?.krate())),
+        Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())),
         _ => None,
     };
 
@@ -396,20 +396,19 @@ pub(crate) fn hover_for_definition(
     };
     let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
 
-    render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config).map(|markup| {
-        HoverResult {
-            markup: render::process_markup(sema.db, def, &markup, config),
-            actions: [
-                show_implementations_action(sema.db, def),
-                show_fn_references_action(sema.db, def),
-                runnable_action(sema, def, file_id),
-                goto_type_action_for_def(sema.db, def, &notable_traits),
-            ]
-            .into_iter()
-            .flatten()
-            .collect(),
-        }
-    })
+    let markup = render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config);
+    HoverResult {
+        markup: render::process_markup(sema.db, def, &markup, config),
+        actions: [
+            show_implementations_action(sema.db, def),
+            show_fn_references_action(sema.db, def),
+            runnable_action(sema, def, file_id),
+            goto_type_action_for_def(sema.db, def, &notable_traits),
+        ]
+        .into_iter()
+        .flatten()
+        .collect(),
+    }
 }
 
 fn notable_traits(
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 eff055c9599..563e78253a8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -3,8 +3,8 @@ use std::{mem, ops::Not};
 
 use either::Either;
 use hir::{
-    Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name,
-    Semantics, Trait, Type, TypeInfo,
+    Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout,
+    LayoutError, Name, Semantics, Trait, Type, TypeInfo,
 };
 use ide_db::{
     base_db::SourceDatabase,
@@ -264,7 +264,7 @@ pub(super) fn keyword(
     let markup = process_markup(
         sema.db,
         Definition::Module(doc_owner),
-        &markup(Some(docs.into()), description, None)?,
+        &markup(Some(docs.into()), description, None),
         config,
     );
     Some(HoverResult { markup, actions })
@@ -369,12 +369,20 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
     match def {
         Definition::Field(f) => Some(f.parent_def(db).name(db)),
         Definition::Local(l) => l.parent(db).name(db),
-        Definition::Function(f) => match f.as_assoc_item(db)?.container(db) {
-            hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
-            hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
-        },
         Definition::Variant(e) => Some(e.parent_enum(db).name(db)),
-        _ => None,
+
+        d => {
+            if let Some(assoc_item) = d.as_assoc_item(db) {
+                match assoc_item.container(db) {
+                    hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
+                    hir::AssocItemContainer::Impl(i) => {
+                        i.self_ty(db).as_adt().map(|adt| adt.name(db))
+                    }
+                }
+            } else {
+                return d.as_extern_assoc_item(db).map(|_| "<extern>".to_owned());
+            }
+        }
     }
     .map(|name| name.display(db).to_string())
 }
@@ -396,11 +404,11 @@ pub(super) fn definition(
     famous_defs: Option<&FamousDefs<'_, '_>>,
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
     config: &HoverConfig,
-) -> Option<Markup> {
+) -> Markup {
     let mod_path = definition_mod_path(db, &def);
-    let label = def.label(db)?;
+    let label = def.label(db);
     let docs = def.docs(db, famous_defs);
-    let value = match def {
+    let value = (|| match def {
         Definition::Variant(it) => {
             if !it.parent_enum(db).is_data_carrying(db) {
                 match it.eval(db) {
@@ -436,7 +444,7 @@ pub(super) fn definition(
             Some(body.to_string())
         }
         _ => None,
-    };
+    })();
 
     let layout_info = match def {
         Definition::Field(it) => render_memory_layout(
@@ -683,7 +691,7 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
     def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
 }
 
-fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
+fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Markup {
     let mut buf = String::new();
 
     if let Some(mod_path) = mod_path {
@@ -696,7 +704,7 @@ fn markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Optio
     if let Some(doc) = docs {
         format_to!(buf, "\n___\n\n{}", doc);
     }
-    Some(buf.into())
+    buf.into()
 }
 
 fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> {
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 69ddc1e45ef..ead4f91595f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -1202,7 +1202,7 @@ fn main() {
             *C*
 
             ```rust
-            test
+            test::X
             ```
 
             ```rust
@@ -1279,11 +1279,11 @@ impl Thing {
     );
     check(
         r#"
-        enum Thing { A }
-        impl Thing {
-            pub fn thing(a: Self$0) {}
-        }
-        "#,
+enum Thing { A }
+impl Thing {
+    pub fn thing(a: Self$0) {}
+}
+"#,
         expect![[r#"
                 *Self*
 
@@ -1298,6 +1298,42 @@ impl Thing {
                 ```
             "#]],
     );
+    check(
+        r#"
+impl usize {
+    pub fn thing(a: Self$0) {}
+}
+"#,
+        expect![[r#"
+            *Self*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            usize
+            ```
+        "#]],
+    );
+    check(
+        r#"
+impl fn() -> usize {
+    pub fn thing(a: Self$0) {}
+}
+"#,
+        expect![[r#"
+            *Self*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            fn() -> usize
+            ```
+        "#]],
+    );
 }
 
 #[test]
@@ -2241,7 +2277,7 @@ fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } }
             *foo*
 
             ```rust
-            test
+            test::<extern>
             ```
 
             ```rust
@@ -4230,7 +4266,7 @@ fn main() {
             *B*
 
             ```rust
-            test
+            test::T
             ```
 
             ```rust
@@ -4259,7 +4295,7 @@ fn main() {
             *B*
 
             ```rust
-            test
+            test::T
             ```
 
             ```rust
@@ -4291,7 +4327,7 @@ fn main() {
             *B*
 
             ```rust
-            test
+            test::T
             ```
 
             ```rust
@@ -4883,7 +4919,7 @@ fn test() {
             *FOO*
 
             ```rust
-            test
+            test::S
             ```
 
             ```rust
@@ -5248,7 +5284,7 @@ impl T1 for Foo {
             *Bar*
 
             ```rust
-            test::t2
+            test::t2::T2
             ```
 
             ```rust
@@ -5270,7 +5306,7 @@ trait A {
             *Assoc*
 
             ```rust
-            test
+            test::A
             ```
 
             ```rust
@@ -5291,7 +5327,7 @@ trait A {
             *Assoc*
 
             ```rust
-            test
+            test::A
             ```
 
             ```rust
@@ -5310,7 +5346,7 @@ trait A where
             *Assoc*
 
             ```rust
-            test
+            test::A
             ```
 
             ```rust
@@ -6596,7 +6632,7 @@ fn test() {
             *A*
 
             ```rust
-            test
+            test::S
             ```
 
             ```rust
@@ -6625,7 +6661,7 @@ fn test() {
             *A*
 
             ```rust
-            test
+            test::S
             ```
 
             ```rust
@@ -6655,7 +6691,7 @@ mod m {
             *A*
 
             ```rust
-            test
+            test::S
             ```
 
             ```rust
@@ -7202,6 +7238,65 @@ impl Iterator for S {
 }
 
 #[test]
+fn extern_items() {
+    check(
+        r#"
+extern "C" {
+    static STATIC$0: ();
+}
+"#,
+        expect![[r#"
+            *STATIC*
+
+            ```rust
+            test::<extern>
+            ```
+
+            ```rust
+            static STATIC: ()
+            ```
+        "#]],
+    );
+    check(
+        r#"
+extern "C" {
+    fn fun$0();
+}
+"#,
+        expect![[r#"
+            *fun*
+
+            ```rust
+            test::<extern>
+            ```
+
+            ```rust
+            unsafe fn fun()
+            ```
+        "#]],
+    );
+    check(
+        r#"
+extern "C" {
+    type Ty$0;
+}
+"#,
+        expect![[r#"
+            *Ty*
+
+            ```rust
+            test::<extern>
+            ```
+
+            ```rust
+             // size = 0, align = 1
+            type Ty
+            ```
+        "#]],
+    );
+}
+
+#[test]
 fn notable_ranged() {
     check_hover_range(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index fef0ec35ba0..815a4ba7fd7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -303,7 +303,6 @@ fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
 
 #[cfg(test)]
 mod tests {
-    use syntax::SourceFile;
     use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
 
     use super::*;
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index f2eedfa4316..f78153df38b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -9,6 +9,7 @@ use ide_db::{
     base_db::{FileId, FileRange},
     defs::{Definition, NameClass, NameRefClass},
     rename::{bail, format_err, source_edit_from_references, IdentifierKind},
+    source_change::SourceChangeBuilder,
     RootDatabase,
 };
 use itertools::Itertools;
@@ -90,24 +91,60 @@ pub(crate) fn rename(
     let syntax = source_file.syntax();
 
     let defs = find_definitions(&sema, syntax, position)?;
+    let alias_fallback = alias_fallback(syntax, position, new_name);
+
+    let ops: RenameResult<Vec<SourceChange>> = match alias_fallback {
+        Some(_) => defs
+            // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
+            // properly find "direct" usages/references.
+            .map(|(.., def)| {
+                match IdentifierKind::classify(new_name)? {
+                    IdentifierKind::Ident => (),
+                    IdentifierKind::Lifetime => {
+                        bail!("Cannot alias reference to a lifetime identifier")
+                    }
+                    IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"),
+                };
 
-    let ops: RenameResult<Vec<SourceChange>> = defs
-        .map(|(.., def)| {
-            if let Definition::Local(local) = def {
-                if let Some(self_param) = local.as_self_param(sema.db) {
-                    cov_mark::hit!(rename_self_to_param);
-                    return rename_self_to_param(&sema, local, self_param, new_name);
-                }
-                if new_name == "self" {
-                    cov_mark::hit!(rename_to_self);
-                    return rename_to_self(&sema, local);
+                let mut usages = def.usages(&sema).all();
+
+                // FIXME: hack - removes the usage that triggered this rename operation.
+                match usages.references.get_mut(&position.file_id).and_then(|refs| {
+                    refs.iter()
+                        .position(|ref_| ref_.range.contains_inclusive(position.offset))
+                        .map(|idx| refs.remove(idx))
+                }) {
+                    Some(_) => (),
+                    None => never!(),
+                };
+
+                let mut source_change = SourceChange::default();
+                source_change.extend(usages.iter().map(|(&file_id, refs)| {
+                    (file_id, source_edit_from_references(refs, def, new_name))
+                }));
+
+                Ok(source_change)
+            })
+            .collect(),
+        None => defs
+            .map(|(.., def)| {
+                if let Definition::Local(local) = def {
+                    if let Some(self_param) = local.as_self_param(sema.db) {
+                        cov_mark::hit!(rename_self_to_param);
+                        return rename_self_to_param(&sema, local, self_param, new_name);
+                    }
+                    if new_name == "self" {
+                        cov_mark::hit!(rename_to_self);
+                        return rename_to_self(&sema, local);
+                    }
                 }
-            }
-            def.rename(&sema, new_name)
-        })
-        .collect();
+                def.rename(&sema, new_name)
+            })
+            .collect(),
+    };
 
     ops?.into_iter()
+        .chain(alias_fallback)
         .reduce(|acc, elem| acc.merge(elem))
         .ok_or_else(|| format_err!("No references found at position"))
 }
@@ -130,6 +167,38 @@ pub(crate) fn will_rename_file(
     Some(change)
 }
 
+// FIXME: Should support `extern crate`.
+fn alias_fallback(
+    syntax: &SyntaxNode,
+    FilePosition { file_id, offset }: FilePosition,
+    new_name: &str,
+) -> Option<SourceChange> {
+    let use_tree = syntax
+        .token_at_offset(offset)
+        .flat_map(|syntax| syntax.parent_ancestors())
+        .find_map(ast::UseTree::cast)?;
+
+    let last_path_segment = use_tree.path()?.segments().last()?.name_ref()?;
+    if !last_path_segment.syntax().text_range().contains_inclusive(offset) {
+        return None;
+    };
+
+    let mut builder = SourceChangeBuilder::new(file_id);
+
+    match use_tree.rename() {
+        Some(rename) => {
+            let offset = rename.syntax().text_range();
+            builder.replace(offset, format!("as {new_name}"));
+        }
+        None => {
+            let offset = use_tree.syntax().text_range().end();
+            builder.insert(offset, format!(" as {new_name}"));
+        }
+    }
+
+    Some(builder.finish())
+}
+
 fn find_definitions(
     sema: &Semantics<'_, RootDatabase>,
     syntax: &SyntaxNode,
@@ -2626,7 +2695,8 @@ use qux as frob;
 //- /lib.rs crate:lib new_source_root:library
 pub struct S;
 //- /main.rs crate:main deps:lib new_source_root:local
-use lib::S$0;
+use lib::S;
+fn main() { let _: S$0; }
 "#,
             "error: Cannot rename a non-local definition",
         );
@@ -2686,4 +2756,27 @@ fn test() {
 "#,
         );
     }
+
+    #[test]
+    fn rename_path_inside_use_tree() {
+        check(
+            "Baz",
+            r#"
+mod foo { pub struct Foo; }
+mod bar { use super::Foo; }
+
+use foo::Foo$0;
+
+fn main() { let _: Foo; }
+"#,
+            r#"
+mod foo { pub struct Foo; }
+mod bar { use super::Baz; }
+
+use foo::Foo as Baz;
+
+fn main() { let _: Baz; }
+"#,
+        )
+    }
 }
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 5feaf21aa97..2929a7522e5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -186,7 +186,7 @@ impl StaticIndex<'_> {
             } else {
                 let it = self.tokens.insert(TokenStaticData {
                     documentation: documentation_for_definition(&sema, def, &node),
-                    hover: hover_for_definition(&sema, file_id, def, &node, &hover_config),
+                    hover: Some(hover_for_definition(&sema, file_id, def, &node, &hover_config)),
                     definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
                         FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
                     }),
@@ -196,7 +196,7 @@ impl StaticIndex<'_> {
                     enclosing_moniker: current_crate
                         .zip(def.enclosing_definition(self.db))
                         .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)),
-                    signature: def.label(self.db),
+                    signature: Some(def.label(self.db)),
                     kind: def_to_kind(self.db, def),
                 });
                 self.def_map.insert(def, it);
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 8c5592da63e..830d19a709c 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -309,6 +309,10 @@ fn load_crate_graph(
     vfs: &mut vfs::Vfs,
     receiver: &Receiver<vfs::loader::Message>,
 ) -> AnalysisHost {
+    let (ProjectWorkspace::Cargo { toolchain, target_layout, .. }
+    | ProjectWorkspace::Json { toolchain, target_layout, .. }
+    | ProjectWorkspace::DetachedFiles { toolchain, target_layout, .. }) = ws;
+
     let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
     let mut host = AnalysisHost::new(lru_cap);
     let mut analysis_change = Change::new();
@@ -344,14 +348,9 @@ fn load_crate_graph(
     let num_crates = crate_graph.len();
     analysis_change.set_crate_graph(crate_graph);
     analysis_change.set_proc_macros(proc_macros);
-    if let ProjectWorkspace::Cargo { toolchain, target_layout, .. }
-    | ProjectWorkspace::Json { toolchain, target_layout, .. } = ws
-    {
-        analysis_change.set_target_data_layouts(
-            iter::repeat(target_layout.clone()).take(num_crates).collect(),
-        );
-        analysis_change.set_toolchains(iter::repeat(toolchain.clone()).take(num_crates).collect());
-    }
+    analysis_change
+        .set_target_data_layouts(iter::repeat(target_layout.clone()).take(num_crates).collect());
+    analysis_change.set_toolchains(iter::repeat(toolchain.clone()).take(num_crates).collect());
 
     host.apply_change(analysis_change);
     host
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 12eafcea442..72f95643c8b 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
@@ -45,7 +45,7 @@ impl ProcMacroProcessSrv {
             })
         };
         let mut srv = create_srv(true)?;
-        tracing::info!("sending version check");
+        tracing::info!("sending proc-macro server version check");
         match srv.version_check() {
             Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
                 io::ErrorKind::Other,
@@ -55,14 +55,15 @@ impl ProcMacroProcessSrv {
                 ),
             )),
             Ok(v) => {
-                tracing::info!("got version {v}");
+                tracing::info!("Proc-macro server version: {v}");
                 srv = create_srv(false)?;
                 srv.version = v;
-                if srv.version > RUST_ANALYZER_SPAN_SUPPORT {
+                if srv.version >= RUST_ANALYZER_SPAN_SUPPORT {
                     if let Ok(mode) = srv.enable_rust_analyzer_spans() {
                         srv.mode = mode;
                     }
                 }
+                tracing::info!("Proc-macro server span mode: {:?}", srv.mode);
                 Ok(srv)
             }
             Err(e) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
index 3fe968c81ca..686d5b0438a 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs
@@ -64,7 +64,7 @@ impl ProcMacros {
                         &bridge::server::SameThread,
                         S::make_server(call_site, def_site, mixed_site),
                         parsed_body,
-                        false,
+                        cfg!(debug_assertions),
                     );
                     return res
                         .map(|it| it.into_subtree(call_site))
@@ -75,7 +75,7 @@ impl ProcMacros {
                         &bridge::server::SameThread,
                         S::make_server(call_site, def_site, mixed_site),
                         parsed_body,
-                        false,
+                        cfg!(debug_assertions),
                     );
                     return res
                         .map(|it| it.into_subtree(call_site))
@@ -87,7 +87,7 @@ impl ProcMacros {
                         S::make_server(call_site, def_site, mixed_site),
                         parsed_attributes,
                         parsed_body,
-                        false,
+                        cfg!(debug_assertions),
                     );
                     return res
                         .map(|it| it.into_subtree(call_site))
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs
index ff8fd295d88..5a814e23e7a 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs
@@ -93,7 +93,14 @@ impl<S> LiteralFormatter<S> {
                 let hashes = get_hashes_str(n);
                 f(&["br", hashes, "\"", symbol, "\"", hashes, suffix])
             }
-            _ => f(&[symbol, suffix]),
+            bridge::LitKind::CStr => f(&["c\"", symbol, "\"", suffix]),
+            bridge::LitKind::CStrRaw(n) => {
+                let hashes = get_hashes_str(n);
+                f(&["cr", hashes, "\"", symbol, "\"", hashes, suffix])
+            }
+            bridge::LitKind::Integer | bridge::LitKind::Float | bridge::LitKind::ErrWithGuar => {
+                f(&[symbol, suffix])
+            }
         })
     }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
index c6a0a666555..15d260d5182 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
@@ -10,16 +10,16 @@ use std::{
     ops::{Bound, Range},
 };
 
-use ::tt::{TextRange, TextSize};
 use proc_macro::bridge::{self, server};
 use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
+use tt::{TextRange, TextSize};
 
 use crate::server::{
     delim_to_external, delim_to_internal, token_stream::TokenStreamBuilder, LiteralFormatter,
     Symbol, SymbolInternerRef, SYMBOL_INTERNER,
 };
 mod tt {
-    pub use ::tt::*;
+    pub use tt::*;
 
     pub type Subtree = ::tt::Subtree<super::Span>;
     pub type TokenTree = ::tt::TokenTree<super::Span>;
@@ -97,22 +97,33 @@ impl server::FreeFunctions for RaSpanServer {
         }
 
         let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
-        let kind = match kind {
-            LiteralKind::Int { .. } => LitKind::Integer,
-            LiteralKind::Float { .. } => LitKind::Float,
-            LiteralKind::Char { .. } => LitKind::Char,
-            LiteralKind::Byte { .. } => LitKind::Byte,
-            LiteralKind::Str { .. } => LitKind::Str,
-            LiteralKind::ByteStr { .. } => LitKind::ByteStr,
-            LiteralKind::CStr { .. } => LitKind::CStr,
-            LiteralKind::RawStr { n_hashes } => LitKind::StrRaw(n_hashes.unwrap_or_default()),
-            LiteralKind::RawByteStr { n_hashes } => {
-                LitKind::ByteStrRaw(n_hashes.unwrap_or_default())
-            }
-            LiteralKind::RawCStr { n_hashes } => LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+        let (kind, start_offset, end_offset) = match kind {
+            LiteralKind::Int { .. } => (LitKind::Integer, 0, 0),
+            LiteralKind::Float { .. } => (LitKind::Float, 0, 0),
+            LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize),
+            LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize),
+            LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize),
+            LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize),
+            LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize),
+            LiteralKind::RawStr { n_hashes } => (
+                LitKind::StrRaw(n_hashes.unwrap_or_default()),
+                2 + n_hashes.unwrap_or_default() as usize,
+                1 + n_hashes.unwrap_or_default() as usize,
+            ),
+            LiteralKind::RawByteStr { n_hashes } => (
+                LitKind::ByteStrRaw(n_hashes.unwrap_or_default()),
+                3 + n_hashes.unwrap_or_default() as usize,
+                1 + n_hashes.unwrap_or_default() as usize,
+            ),
+            LiteralKind::RawCStr { n_hashes } => (
+                LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+                3 + n_hashes.unwrap_or_default() as usize,
+                1 + n_hashes.unwrap_or_default() as usize,
+            ),
         };
 
         let (lit, suffix) = s.split_at(suffix_start as usize);
+        let lit = &lit[start_offset..lit.len() - end_offset];
         let suffix = match suffix {
             "" | "_" => None,
             suffix => Some(Symbol::intern(self.interner, suffix)),
@@ -248,12 +259,8 @@ impl server::TokenStream for RaSpanServer {
                 }
                 tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                     bridge::TokenTree::Literal(bridge::Literal {
-                        // FIXME: handle literal kinds
-                        kind: bridge::LitKind::Integer, // dummy
-                        symbol: Symbol::intern(self.interner, &lit.text),
-                        // FIXME: handle suffixes
-                        suffix: None,
                         span: lit.span,
+                        ..server::FreeFunctions::literal_from_str(self, &lit.text).unwrap()
                     })
                 }
                 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
index 7e9d8057ac9..f40c850b253 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
@@ -14,7 +14,7 @@ use crate::server::{
 mod tt {
     pub use proc_macro_api::msg::TokenId;
 
-    pub use ::tt::*;
+    pub use tt::*;
 
     pub type Subtree = ::tt::Subtree<TokenId>;
     pub type TokenTree = ::tt::TokenTree<TokenId>;
@@ -89,22 +89,34 @@ impl server::FreeFunctions for TokenIdServer {
         }
 
         let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
-        let kind = match kind {
-            LiteralKind::Int { .. } => LitKind::Integer,
-            LiteralKind::Float { .. } => LitKind::Float,
-            LiteralKind::Char { .. } => LitKind::Char,
-            LiteralKind::Byte { .. } => LitKind::Byte,
-            LiteralKind::Str { .. } => LitKind::Str,
-            LiteralKind::ByteStr { .. } => LitKind::ByteStr,
-            LiteralKind::CStr { .. } => LitKind::CStr,
-            LiteralKind::RawStr { n_hashes } => LitKind::StrRaw(n_hashes.unwrap_or_default()),
-            LiteralKind::RawByteStr { n_hashes } => {
-                LitKind::ByteStrRaw(n_hashes.unwrap_or_default())
-            }
-            LiteralKind::RawCStr { n_hashes } => LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+
+        let (kind, start_offset, end_offset) = match kind {
+            LiteralKind::Int { .. } => (LitKind::Integer, 0, 0),
+            LiteralKind::Float { .. } => (LitKind::Float, 0, 0),
+            LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize),
+            LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize),
+            LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize),
+            LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize),
+            LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize),
+            LiteralKind::RawStr { n_hashes } => (
+                LitKind::StrRaw(n_hashes.unwrap_or_default()),
+                2 + n_hashes.unwrap_or_default() as usize,
+                1 + n_hashes.unwrap_or_default() as usize,
+            ),
+            LiteralKind::RawByteStr { n_hashes } => (
+                LitKind::ByteStrRaw(n_hashes.unwrap_or_default()),
+                3 + n_hashes.unwrap_or_default() as usize,
+                1 + n_hashes.unwrap_or_default() as usize,
+            ),
+            LiteralKind::RawCStr { n_hashes } => (
+                LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+                3 + n_hashes.unwrap_or_default() as usize,
+                1 + n_hashes.unwrap_or_default() as usize,
+            ),
         };
 
         let (lit, suffix) = s.split_at(suffix_start as usize);
+        let lit = &lit[start_offset..lit.len() - end_offset];
         let suffix = match suffix {
             "" | "_" => None,
             suffix => Some(Symbol::intern(self.interner, suffix)),
@@ -233,12 +245,9 @@ impl server::TokenStream for TokenIdServer {
                 }
                 tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                     bridge::TokenTree::Literal(bridge::Literal {
-                        // FIXME: handle literal kinds
-                        kind: bridge::LitKind::Integer, // dummy
-                        symbol: Symbol::intern(self.interner, &lit.text),
-                        // FIXME: handle suffixes
-                        suffix: None,
                         span: lit.span,
+                        ..server::FreeFunctions::literal_from_str(self, &lit.text)
+                            .unwrap_or_else(|_| panic!("`{}`", lit.text))
                     })
                 }
                 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
index 5edaa720fc7..408db60e872 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
@@ -115,8 +115,6 @@ pub(super) mod token_stream {
         }
     }
 
-    type LexError = String;
-
     /// Attempts to break the string into tokens and parse those tokens into a token stream.
     /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters
     /// or characters not existing in the language.
@@ -124,13 +122,10 @@ pub(super) mod token_stream {
     ///
     /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to
     /// change these errors into `LexError`s later.
-    #[rustfmt::skip]
-    impl<S: tt::Span> /*FromStr for*/ TokenStream<S> {
-        // type Err = LexError;
-
-        pub(crate) fn from_str(src: &str, call_site: S) -> Result<TokenStream<S>, LexError> {
+    impl<S: tt::Span> TokenStream<S> {
+        pub(crate) fn from_str(src: &str, call_site: S) -> Result<TokenStream<S>, String> {
             let subtree =
-                mbe::parse_to_token_tree_static_span(call_site, src).ok_or("Failed to parse from mbe")?;
+                mbe::parse_to_token_tree_static_span(call_site, src).ok_or("lexing error")?;
 
             Ok(TokenStream::with_subtree(subtree))
         }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index e5bfe5ee92c..54a20357d26 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -169,7 +169,7 @@ fn test_fn_like_mk_idents() {
 fn test_fn_like_macro_clone_literals() {
     assert_expand(
         "fn_like_clone_tokens",
-        r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##"###,
+        r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##, 'a', b'b', c"null""###,
         expect![[r###"
             SUBTREE $$ 1 1
               LITERAL 1u16 1
@@ -181,11 +181,17 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 1
               LITERAL 3.14f32 1
               PUNCH   , [alone] 1
-              LITERAL ""hello bridge"" 1
+              LITERAL "hello bridge" 1
               PUNCH   , [alone] 1
-              LITERAL ""suffixed""suffix 1
+              LITERAL "suffixed"suffix 1
               PUNCH   , [alone] 1
-              LITERAL r##"r##"raw"##"## 1"###]],
+              LITERAL r##"raw"## 1
+              PUNCH   , [alone] 1
+              LITERAL 'a' 1
+              PUNCH   , [alone] 1
+              LITERAL b'b' 1
+              PUNCH   , [alone] 1
+              LITERAL c"null" 1"###]],
         expect![[r###"
             SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               LITERAL 1u16 SpanData { range: 0..4, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
@@ -197,11 +203,17 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] SpanData { range: 18..19, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               LITERAL 3.14f32 SpanData { range: 20..27, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               PUNCH   , [alone] SpanData { range: 27..28, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
-              LITERAL ""hello bridge"" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL "hello bridge" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               PUNCH   , [alone] SpanData { range: 43..44, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
-              LITERAL ""suffixed""suffix SpanData { range: 45..61, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL "suffixed"suffix SpanData { range: 45..61, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
               PUNCH   , [alone] SpanData { range: 61..62, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
-              LITERAL r##"r##"raw"##"## SpanData { range: 63..73, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"###]],
+              LITERAL r##"raw"## SpanData { range: 63..73, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 73..74, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 'a' SpanData { range: 75..78, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 78..79, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL b'b' SpanData { range: 80..84, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 84..85, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL c"null" SpanData { range: 86..93, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"###]],
     );
 }
 
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 ab72f1fba09..621b6ca3efa 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
@@ -138,7 +138,7 @@ impl WorkspaceBuildScripts {
         toolchain: &Option<Version>,
         sysroot: Option<&Sysroot>,
     ) -> io::Result<WorkspaceBuildScripts> {
-        const RUST_1_62: Version = Version::new(1, 62, 0);
+        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() => {
@@ -162,7 +162,7 @@ impl WorkspaceBuildScripts {
             progress,
         ) {
             Ok(WorkspaceBuildScripts { error: Some(error), .. })
-                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
+                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
@@ -172,7 +172,8 @@ impl WorkspaceBuildScripts {
                     &workspace.workspace_root().to_path_buf(),
                     sysroot,
                 )?;
-                cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
+
+                cmd.args(["--keep-going"]);
                 let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
                 res.error = Some(error);
                 Ok(res)
diff --git a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
index af635dda578..98917351c5e 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/target_data_layout.rs
@@ -32,7 +32,16 @@ pub fn get(
             Sysroot::set_rustup_toolchain_env(&mut cmd, sysroot);
             cmd.envs(extra_env);
             cmd.current_dir(cargo_toml.parent())
-                .args(["rustc", "--", "-Z", "unstable-options", "--print", "target-spec-json"])
+                .args([
+                    "rustc",
+                    "-Z",
+                    "unstable-options",
+                    "--print",
+                    "target-spec-json",
+                    "--",
+                    "-Z",
+                    "unstable-options",
+                ])
                 .env("RUSTC_BOOTSTRAP", "1");
             if let Some(target) = target {
                 cmd.args(["--target", target]);
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 b7ae76be8ce..bcb5dcadb5b 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -100,6 +100,8 @@ pub enum ProjectWorkspace {
         /// Holds cfg flags for the current target. We get those by running
         /// `rustc --print cfg`.
         rustc_cfg: Vec<CfgFlag>,
+        toolchain: Option<Version>,
+        target_layout: TargetLayoutLoadResult,
     },
 }
 
@@ -145,16 +147,24 @@ impl fmt::Debug for ProjectWorkspace {
                     debug_struct.field("n_sysroot_crates", &sysroot.num_packages());
                 }
                 debug_struct
-                    .field("toolchain", &toolchain)
                     .field("n_rustc_cfg", &rustc_cfg.len())
+                    .field("toolchain", &toolchain)
                     .field("data_layout", &data_layout);
                 debug_struct.finish()
             }
-            ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
+            ProjectWorkspace::DetachedFiles {
+                files,
+                sysroot,
+                rustc_cfg,
+                toolchain,
+                target_layout,
+            } => f
                 .debug_struct("DetachedFiles")
                 .field("n_files", &files.len())
                 .field("sysroot", &sysroot.is_ok())
                 .field("n_rustc_cfg", &rustc_cfg.len())
+                .field("toolchain", &toolchain)
+                .field("data_layout", &target_layout)
                 .finish(),
         }
     }
@@ -403,32 +413,54 @@ impl ProjectWorkspace {
         detached_files: Vec<AbsPathBuf>,
         config: &CargoConfig,
     ) -> anyhow::Result<ProjectWorkspace> {
+        let dir = detached_files
+            .first()
+            .and_then(|it| it.parent())
+            .ok_or_else(|| format_err!("No detached files to load"))?;
         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) => {
-                let dir = &detached_files
-                    .first()
-                    .and_then(|it| it.parent())
-                    .ok_or_else(|| format_err!("No detached files to load"))?;
-                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}"
-                        ))
-                    },
-                )
-            }
+            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 rustc_cfg = rustc_cfg::get(
+
+        let sysroot_ref = sysroot.as_ref().ok();
+        let toolchain = match get_toolchain_version(
+            dir,
+            sysroot_ref,
+            toolchain::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,
-            &FxHashMap::default(),
-            RustcCfgConfig::Rustc(sysroot.as_ref().ok()),
+            &config.extra_env,
         );
-        Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
+        Ok(ProjectWorkspace::DetachedFiles {
+            files: detached_files,
+            sysroot,
+            rustc_cfg,
+            toolchain,
+            target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+        })
     }
 
     /// Runs the build scripts for this [`ProjectWorkspace`].
@@ -724,7 +756,13 @@ impl ProjectWorkspace {
                 cfg_overrides,
                 build_scripts,
             ),
-            ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
+            ProjectWorkspace::DetachedFiles {
+                files,
+                sysroot,
+                rustc_cfg,
+                toolchain: _,
+                target_layout: _,
+            } => {
                 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot.as_ref().ok())
             }
         };
@@ -786,9 +824,21 @@ impl ProjectWorkspace {
                     && toolchain == o_toolchain
             }
             (
-                Self::DetachedFiles { files, sysroot, rustc_cfg },
-                Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
-            ) => files == o_files && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg,
+                Self::DetachedFiles { files, sysroot, rustc_cfg, toolchain, target_layout },
+                Self::DetachedFiles {
+                    files: o_files,
+                    sysroot: o_sysroot,
+                    rustc_cfg: o_rustc_cfg,
+                    toolchain: o_toolchain,
+                    target_layout: o_target_layout,
+                },
+            ) => {
+                files == o_files
+                    && sysroot == o_sysroot
+                    && rustc_cfg == o_rustc_cfg
+                    && toolchain == o_toolchain
+                    && target_layout == o_target_layout
+            }
             _ => false,
         }
     }
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 f9f26178259..815a98980b9 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
@@ -208,7 +208,6 @@ fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) {
 mod tests {
     use super::*;
 
-    use cfg::CfgExpr;
     use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
     use syntax::{
         ast::{self, AstNode},
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
index 493e614dce6..3f68c5d053b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
@@ -30,7 +30,7 @@ xflags::xflags! {
 
         default cmd lsp-server {
             /// Print version.
-            optional --version
+            optional -V, --version
 
             /// Dump a LSP config JSON schema.
             optional --print-config-schema
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 64ea246a458..7062b60cbfc 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
@@ -1,11 +1,16 @@
 //! Run all tests in a project, similar to `cargo test`, but using the mir interpreter.
 
+use std::convert::identity;
+use std::thread::Builder;
+use std::time::{Duration, Instant};
 use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf};
 
 use hir::{Change, Crate};
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
+use itertools::Either;
 use profile::StopWatch;
-use project_model::{CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
+use project_model::target_data_layout::RustcDataLayoutConfig;
+use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
 
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
 use rustc_hash::FxHashMap;
@@ -60,15 +65,22 @@ impl Tester {
         std::fs::write(&tmp_file, "")?;
         let cargo_config =
             CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() };
+
+        let sysroot =
+            Ok(Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env, false)
+                .unwrap());
+        let data_layout = target_data_layout::get(
+            RustcDataLayoutConfig::Rustc(sysroot.as_ref().ok()),
+            None,
+            &cargo_config.extra_env,
+        );
+
         let workspace = ProjectWorkspace::DetachedFiles {
             files: vec![tmp_file.clone()],
-            sysroot: Ok(Sysroot::discover(
-                tmp_file.parent().unwrap(),
-                &cargo_config.extra_env,
-                false,
-            )
-            .unwrap()),
+            sysroot,
             rustc_cfg: vec![],
+            toolchain: None,
+            target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
         };
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: false,
@@ -92,6 +104,7 @@ impl Tester {
     }
 
     fn test(&mut self, p: PathBuf) {
+        println!("{}", p.display());
         if p.parent().unwrap().file_name().unwrap() == "auxiliary" {
             // These are not tests
             return;
@@ -124,15 +137,44 @@ impl Tester {
         self.host.apply_change(change);
         let diagnostic_config = DiagnosticsConfig::test_sample();
 
+        let res = std::thread::scope(|s| {
+            let worker = Builder::new()
+                .stack_size(40 * 1024 * 1024)
+                .spawn_scoped(s, {
+                    let diagnostic_config = &diagnostic_config;
+                    let main = std::thread::current();
+                    let analysis = self.host.analysis();
+                    let root_file = self.root_file;
+                    move || {
+                        let res = std::panic::catch_unwind(move || {
+                            analysis.diagnostics(
+                                diagnostic_config,
+                                ide::AssistResolveStrategy::None,
+                                root_file,
+                            )
+                        });
+                        main.unpark();
+                        res
+                    }
+                })
+                .unwrap();
+
+            let timeout = Duration::from_secs(5);
+            let now = Instant::now();
+            while now.elapsed() <= timeout && !worker.is_finished() {
+                std::thread::park_timeout(timeout - now.elapsed());
+            }
+
+            if !worker.is_finished() {
+                // attempt to cancel the worker, won't work for chalk hangs unfortunately
+                self.host.request_cancellation();
+            }
+            worker.join().and_then(identity)
+        });
         let mut actual = FxHashMap::default();
-        let panicked = match std::panic::catch_unwind(|| {
-            self.host
-                .analysis()
-                .diagnostics(&diagnostic_config, ide::AssistResolveStrategy::None, self.root_file)
-                .unwrap()
-        }) {
-            Err(e) => Some(e),
-            Ok(diags) => {
+        let panicked = match res {
+            Err(e) => Some(Either::Left(e)),
+            Ok(Ok(diags)) => {
                 for diag in diags {
                     if !matches!(diag.code, DiagnosticCode::RustcHardError(_)) {
                         continue;
@@ -144,6 +186,7 @@ impl Tester {
                 }
                 None
             }
+            Ok(Err(e)) => Some(Either::Right(e)),
         };
         // Ignore tests with diagnostics that we don't emit.
         ignore_test |= expected.keys().any(|k| !SUPPORTED_DIAGNOSTICS.contains(k));
@@ -151,14 +194,19 @@ impl Tester {
             println!("{p:?} IGNORE");
             self.ignore_count += 1;
         } else if let Some(panic) = panicked {
-            if let Some(msg) = panic
-                .downcast_ref::<String>()
-                .map(String::as_str)
-                .or_else(|| panic.downcast_ref::<&str>().copied())
-            {
-                println!("{msg:?} ")
+            match panic {
+                Either::Left(panic) => {
+                    if let Some(msg) = panic
+                        .downcast_ref::<String>()
+                        .map(String::as_str)
+                        .or_else(|| panic.downcast_ref::<&str>().copied())
+                    {
+                        println!("{msg:?} ")
+                    }
+                    println!("{p:?} PANIC");
+                }
+                Either::Right(_) => println!("{p:?} CANCELLED"),
             }
-            println!("PANIC");
             self.fail_count += 1;
         } else if actual == expected {
             println!("{p:?} PASS");
@@ -228,6 +276,7 @@ impl flags::RustcTests {
     pub fn run(self) -> Result<()> {
         let mut tester = Tester::new()?;
         let walk_dir = WalkDir::new(self.rustc_repo.join("tests/ui"));
+        eprintln!("Running tests for tests/ui");
         for i in walk_dir {
             let i = i?;
             let p = i.into_path();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 2d56830c87f..27869a5a7e6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -324,7 +324,7 @@ fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
 #[cfg(test)]
 mod test {
     use super::*;
-    use ide::{AnalysisHost, FilePosition, StaticIndex, TextSize};
+    use ide::{AnalysisHost, FilePosition, TextSize};
     use scip::symbol::format_symbol;
     use test_fixture::ChangeFixture;
 
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 293807a383b..b2d507491b1 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
@@ -301,19 +301,12 @@ impl GlobalState {
                 if let Some(path) = vfs_path.as_path() {
                     let path = path.to_path_buf();
                     if reload::should_refresh_for_change(&path, file.kind()) {
-                        workspace_structure_change = Some((
-                            path.clone(),
-                            false,
-                            AsRef::<std::path::Path>::as_ref(&path).ends_with("build.rs"),
-                        ));
+                        workspace_structure_change = Some((path.clone(), false));
                     }
                     if file.is_created_or_deleted() {
                         has_structure_changes = true;
-                        workspace_structure_change = Some((
-                            path,
-                            self.crate_graph_file_dependencies.contains(vfs_path),
-                            false,
-                        ));
+                        workspace_structure_change =
+                            Some((path, self.crate_graph_file_dependencies.contains(vfs_path)));
                     } else if path.extension() == Some("rs".as_ref()) {
                         modified_rust_files.push(file.file_id);
                     }
@@ -365,16 +358,11 @@ impl GlobalState {
             // FIXME: ideally we should only trigger a workspace fetch for non-library changes
             // 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, build_scripts_touched)) =
-                workspace_structure_change
-            {
+            if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
                 self.fetch_workspaces_queue.request_op(
                     format!("workspace vfs file change: {path}"),
                     force_crate_graph_reload,
                 );
-                if build_scripts_touched {
-                    self.fetch_build_data_queue.request_op(format!("build.rs changed: {path}"), ());
-                }
             }
         }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index eb9d4bf0f02..04a04395429 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
@@ -16,6 +16,7 @@ use ide::{
     ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
 };
 use ide_db::SymbolKind;
+use itertools::Itertools;
 use lsp_server::ErrorCode;
 use lsp_types::{
     CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
@@ -1055,9 +1056,8 @@ pub(crate) fn handle_references(
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
     let exclude_tests = snap.config.find_all_refs_exclude_tests();
 
-    let refs = match snap.analysis.find_all_refs(position, None)? {
-        None => return Ok(None),
-        Some(refs) => refs,
+    let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
+        return Ok(None);
     };
 
     let include_declaration = params.context.include_declaration;
@@ -1084,6 +1084,7 @@ pub(crate) fn handle_references(
                 })
                 .chain(decl)
         })
+        .unique()
         .filter_map(|frange| to_proto::location(&snap, frange).ok())
         .collect();
 
@@ -1802,10 +1803,10 @@ fn show_ref_command_link(
                 .into_iter()
                 .flat_map(|res| res.references)
                 .flat_map(|(file_id, ranges)| {
-                    ranges.into_iter().filter_map(move |(range, _)| {
-                        to_proto::location(snap, FileRange { file_id, range }).ok()
-                    })
+                    ranges.into_iter().map(move |(range, _)| FileRange { file_id, range })
                 })
+                .unique()
+                .filter_map(|range| to_proto::location(snap, range).ok())
                 .collect();
             let title = to_proto::reference_title(locations.len());
             let command = to_proto::command::show_references(title, &uri, position, locations);
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 727007bba08..481ebfefd4e 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
@@ -904,15 +904,16 @@ pub(crate) fn goto_definition_response(
     if snap.config.location_link() {
         let links = targets
             .into_iter()
+            .unique_by(|nav| (nav.file_id, nav.full_range, nav.focus_range))
             .map(|nav| location_link(snap, src, nav))
             .collect::<Cancellable<Vec<_>>>()?;
         Ok(links.into())
     } else {
         let locations = targets
             .into_iter()
-            .map(|nav| {
-                location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
-            })
+            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
+            .unique()
+            .map(|range| location(snap, range))
             .collect::<Cancellable<Vec<_>>>()?;
         Ok(locations.into())
     }
@@ -1001,10 +1002,8 @@ fn merge_text_and_snippet_edits(
             let mut new_text = current_indel.insert;
 
             // find which snippet bits need to be escaped
-            let escape_places = new_text
-                .rmatch_indices(['\\', '$', '{', '}'])
-                .map(|(insert, _)| insert)
-                .collect_vec();
+            let escape_places =
+                new_text.rmatch_indices(['\\', '$', '}']).map(|(insert, _)| insert).collect_vec();
             let mut escape_places = escape_places.into_iter().peekable();
             let mut escape_prior_bits = |new_text: &mut String, up_to: usize| {
                 for before in escape_places.peeking_take_while(|insert| *insert >= up_to) {
@@ -2175,7 +2174,7 @@ fn bar(_: usize) {}
                                 character: 0,
                             },
                         },
-                        new_text: "\\$${1:ab\\{\\}\\$c\\\\d}ef",
+                        new_text: "\\$${1:ab{\\}\\$c\\\\d}ef",
                         insert_text_format: Some(
                             Snippet,
                         ),
@@ -2271,7 +2270,7 @@ struct ProcMacro {
                                 character: 5,
                             },
                         },
-                        new_text: "$0disabled = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        new_text: "$0disabled = false;\n    ProcMacro {\n        disabled,\n    \\}",
                         insert_text_format: Some(
                             Snippet,
                         ),
@@ -2335,7 +2334,7 @@ struct P {
                                 character: 5,
                             },
                         },
-                        new_text: "$0disabled = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        new_text: "$0disabled = false;\n    ProcMacro {\n        disabled,\n    \\}",
                         insert_text_format: Some(
                             Snippet,
                         ),
@@ -2400,7 +2399,7 @@ struct ProcMacro {
                                 character: 5,
                             },
                         },
-                        new_text: "${0:disabled} = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        new_text: "${0:disabled} = false;\n    ProcMacro {\n        disabled,\n    \\}",
                         insert_text_format: Some(
                             Snippet,
                         ),
@@ -2465,7 +2464,7 @@ struct P {
                                 character: 5,
                             },
                         },
-                        new_text: "${0:disabled} = false;\n    ProcMacro \\{\n        disabled,\n    \\}",
+                        new_text: "${0:disabled} = false;\n    ProcMacro {\n        disabled,\n    \\}",
                         insert_text_format: Some(
                             Snippet,
                         ),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
index 10335cb1453..800c0eee53a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
@@ -134,6 +134,7 @@ impl GlobalState {
         let token = lsp_types::ProgressToken::String(
             cancel_token.unwrap_or_else(|| format!("rustAnalyzer/{title}")),
         );
+        tracing::debug!(?token, ?state, "report_progress {message:?}");
         let work_done_progress = match state {
             Progress::Begin => {
                 self.send_request::<lsp_types::request::WorkDoneProgressCreate>(
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 5895459d1fc..f6bc032c019 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -411,10 +411,7 @@ impl GlobalState {
                 if *force_reload_crate_graph {
                     self.recreate_crate_graph(cause);
                 }
-                if self.build_deps_changed && self.config.run_build_scripts() {
-                    self.build_deps_changed = false;
-                    self.fetch_build_data_queue.request_op("build_deps_changed".to_owned(), ());
-                }
+
                 // Current build scripts do not match the version of the active
                 // workspace, so there's nothing for us to update.
                 return;
@@ -424,7 +421,7 @@ impl GlobalState {
 
             // Here, we completely changed the workspace (Cargo.toml edit), so
             // we don't care about build-script results, they are stale.
-            // FIXME: can we abort the build scripts here?
+            // FIXME: can we abort the build scripts here if they are already running?
             self.workspaces = Arc::new(workspaces);
 
             if self.config.run_build_scripts() {
@@ -525,13 +522,14 @@ impl GlobalState {
     }
 
     fn recreate_crate_graph(&mut self, cause: String) {
-        {
+        // crate graph construction relies on these paths, record them so when one of them gets
+        // deleted or created we trigger a reconstruction of the crate graph
+        let mut crate_graph_file_dependencies = FxHashSet::default();
+
+        let (crate_graph, proc_macro_paths, layouts, toolchains) = {
             // Create crate graph from all the workspaces
             let vfs = &mut self.vfs.write().0;
             let loader = &mut self.loader;
-            // crate graph construction relies on these paths, record them so when one of them gets
-            // deleted or created we trigger a reconstruction of the crate graph
-            let mut crate_graph_file_dependencies = FxHashSet::default();
 
             let load = |path: &AbsPath| {
                 let _p = tracing::span!(tracing::Level::DEBUG, "switch_workspaces::load").entered();
@@ -548,25 +546,24 @@ impl GlobalState {
                 }
             };
 
-            let (crate_graph, proc_macro_paths, layouts, toolchains) =
-                ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load);
-
-            let mut change = Change::new();
-            if self.config.expand_proc_macros() {
-                change.set_proc_macros(
-                    crate_graph
-                        .iter()
-                        .map(|id| (id, Err("Proc-macros have not been built yet".to_owned())))
-                        .collect(),
-                );
-                self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths);
-            }
-            change.set_crate_graph(crate_graph);
-            change.set_target_data_layouts(layouts);
-            change.set_toolchains(toolchains);
-            self.analysis_host.apply_change(change);
-            self.crate_graph_file_dependencies = crate_graph_file_dependencies;
+            ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load)
+        };
+        let mut change = Change::new();
+        if self.config.expand_proc_macros() {
+            change.set_proc_macros(
+                crate_graph
+                    .iter()
+                    .map(|id| (id, Err("Proc-macros have not been built yet".to_owned())))
+                    .collect(),
+            );
+            self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths);
         }
+        change.set_crate_graph(crate_graph);
+        change.set_target_data_layouts(layouts);
+        change.set_toolchains(toolchains);
+        self.analysis_host.apply_change(change);
+        self.crate_graph_file_dependencies = crate_graph_file_dependencies;
+
         self.process_changes();
         self.reload_flycheck();
     }
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 392a7170207..dfd25abc70f 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
@@ -243,7 +243,7 @@ impl Server {
                             to_string_pretty(actual_part).unwrap(),
                         );
                 } else {
-                    tracing::debug!("sucessfully matched notification");
+                    tracing::debug!("successfully matched notification");
                     return;
                 }
             } else {
diff --git a/src/tools/rust-analyzer/crates/salsa/Cargo.toml b/src/tools/rust-analyzer/crates/salsa/Cargo.toml
index 4ccbc3de846..9eec21f6a15 100644
--- a/src/tools/rust-analyzer/crates/salsa/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/salsa/Cargo.toml
@@ -21,6 +21,7 @@ rustc-hash = "1.0"
 smallvec = "1.0.0"
 oorandom = "11"
 triomphe = "0.1.11"
+itertools.workspace = true
 
 salsa-macros = { version = "0.0.0", path = "salsa-macros" }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
index 0ec75bb043d..223da9b5290 100644
--- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
@@ -154,8 +154,8 @@ pub(crate) fn database(args: TokenStream, input: TokenStream) -> TokenStream {
                 self.#db_storage_field.salsa_runtime()
             }
 
-            fn ops_salsa_runtime_mut(&mut self) -> &mut salsa::Runtime {
-                self.#db_storage_field.salsa_runtime_mut()
+            fn synthetic_write(&mut self, durability: salsa::Durability) {
+                self.#db_storage_field.salsa_runtime_mut().synthetic_write(durability)
             }
 
             fn fmt_index(
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
index 5d1678ef120..a868d920b66 100644
--- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
@@ -526,7 +526,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
         fmt_ops.extend(quote! {
             #query_index => {
                 salsa::plumbing::QueryStorageOps::fmt_index(
-                    &*self.#fn_name, db, input, fmt,
+                    &*self.#fn_name, db, input.key_index(), fmt,
                 )
             }
         });
@@ -537,7 +537,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
         maybe_changed_ops.extend(quote! {
             #query_index => {
                 salsa::plumbing::QueryStorageOps::maybe_changed_after(
-                    &*self.#fn_name, db, input, revision
+                    &*self.#fn_name, db, input.key_index(), revision
                 )
             }
         });
diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived.rs b/src/tools/rust-analyzer/crates/salsa/src/derived.rs
index d6316710058..153df999f53 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/derived.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/derived.rs
@@ -102,13 +102,13 @@ where
 
         let mut write = self.slot_map.write();
         let entry = write.entry(key.clone());
-        let key_index = u32::try_from(entry.index()).unwrap();
+        let key_index = entry.index() as u32;
         let database_key_index = DatabaseKeyIndex {
             group_index: self.group_index,
             query_index: Q::QUERY_INDEX,
             key_index,
         };
-        entry.or_insert_with(|| Arc::new(Slot::new(key.clone(), database_key_index))).clone()
+        entry.or_insert_with(|| Arc::new(Slot::new(database_key_index))).clone()
     }
 }
 
@@ -131,34 +131,36 @@ where
     fn fmt_index(
         &self,
         _db: &<Q as QueryDb<'_>>::DynDb,
-        index: DatabaseKeyIndex,
+        index: u32,
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result {
-        assert_eq!(index.group_index, self.group_index);
-        assert_eq!(index.query_index, Q::QUERY_INDEX);
         let slot_map = self.slot_map.read();
-        let key = slot_map.get_index(index.key_index as usize).unwrap().0;
+        let key = slot_map.get_index(index as usize).unwrap().0;
         write!(fmt, "{}({:?})", Q::QUERY_NAME, key)
     }
 
     fn maybe_changed_after(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        input: DatabaseKeyIndex,
+        index: u32,
         revision: Revision,
     ) -> bool {
-        assert_eq!(input.group_index, self.group_index);
-        assert_eq!(input.query_index, Q::QUERY_INDEX);
         debug_assert!(revision < db.salsa_runtime().current_revision());
-        let slot = self.slot_map.read().get_index(input.key_index as usize).unwrap().1.clone();
-        slot.maybe_changed_after(db, revision)
+        let read = self.slot_map.read();
+        let Some((key, slot)) = read.get_index(index as usize) else {
+            return false;
+        };
+        let (key, slot) = (key.clone(), slot.clone());
+        // note: this drop is load-bearing. removing it would causes deadlocks.
+        drop(read);
+        slot.maybe_changed_after(db, revision, &key)
     }
 
     fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
         db.unwind_if_cancelled();
 
         let slot = self.slot(key);
-        let StampedValue { value, durability, changed_at } = slot.read(db);
+        let StampedValue { value, durability, changed_at } = slot.read(db, key);
 
         if let Some(evicted) = self.lru_list.record_use(&slot) {
             evicted.evict();
@@ -182,7 +184,7 @@ where
         C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
     {
         let slot_map = self.slot_map.read();
-        slot_map.values().filter_map(|slot| slot.as_table_entry()).collect()
+        slot_map.iter().filter_map(|(key, slot)| slot.as_table_entry(key)).collect()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs b/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs
index 4fad791a26a..75204c8ff60 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs
@@ -26,8 +26,8 @@ where
     Q: QueryFunction,
     MP: MemoizationPolicy<Q>,
 {
-    key: Q::Key,
-    database_key_index: DatabaseKeyIndex,
+    key_index: u32,
+    group_index: u16,
     state: RwLock<QueryState<Q>>,
     policy: PhantomData<MP>,
     lru_index: LruIndex,
@@ -110,10 +110,10 @@ where
     Q: QueryFunction,
     MP: MemoizationPolicy<Q>,
 {
-    pub(super) fn new(key: Q::Key, database_key_index: DatabaseKeyIndex) -> Self {
+    pub(super) fn new(database_key_index: DatabaseKeyIndex) -> Self {
         Self {
-            key,
-            database_key_index,
+            key_index: database_key_index.key_index,
+            group_index: database_key_index.group_index,
             state: RwLock::new(QueryState::NotComputed),
             lru_index: LruIndex::default(),
             policy: PhantomData,
@@ -121,10 +121,18 @@ where
     }
 
     pub(super) fn database_key_index(&self) -> DatabaseKeyIndex {
-        self.database_key_index
+        DatabaseKeyIndex {
+            group_index: self.group_index,
+            query_index: Q::QUERY_INDEX,
+            key_index: self.key_index,
+        }
     }
 
-    pub(super) fn read(&self, db: &<Q as QueryDb<'_>>::DynDb) -> StampedValue<Q::Value> {
+    pub(super) fn read(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        key: &Q::Key,
+    ) -> StampedValue<Q::Value> {
         let runtime = db.salsa_runtime();
 
         // NB: We don't need to worry about people modifying the
@@ -147,7 +155,7 @@ where
             }
         }
 
-        self.read_upgrade(db, revision_now)
+        self.read_upgrade(db, key, revision_now)
     }
 
     /// Second phase of a read operation: acquires an upgradable-read
@@ -157,6 +165,7 @@ where
     fn read_upgrade(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
+        key: &Q::Key,
         revision_now: Revision,
     ) -> StampedValue<Q::Value> {
         let runtime = db.salsa_runtime();
@@ -186,8 +195,8 @@ where
             }
         };
 
-        let panic_guard = PanicGuard::new(self.database_key_index, self, runtime);
-        let active_query = runtime.push_query(self.database_key_index);
+        let panic_guard = PanicGuard::new(self, runtime);
+        let active_query = runtime.push_query(self.database_key_index());
 
         // If we have an old-value, it *may* now be stale, since there
         // has been a new revision since the last time we checked. So,
@@ -200,7 +209,7 @@ where
                 db.salsa_event(Event {
                     runtime_id: runtime.id(),
                     kind: EventKind::DidValidateMemoizedValue {
-                        database_key: self.database_key_index,
+                        database_key: self.database_key_index(),
                     },
                 });
 
@@ -210,7 +219,7 @@ where
             }
         }
 
-        self.execute(db, runtime, revision_now, active_query, panic_guard, old_memo)
+        self.execute(db, runtime, revision_now, active_query, panic_guard, old_memo, key)
     }
 
     fn execute(
@@ -221,22 +230,23 @@ where
         active_query: ActiveQueryGuard<'_>,
         panic_guard: PanicGuard<'_, Q, MP>,
         old_memo: Option<Memo<Q::Value>>,
+        key: &Q::Key,
     ) -> StampedValue<Q::Value> {
-        tracing::info!("{:?}: executing query", self.database_key_index.debug(db));
+        tracing::info!("{:?}: executing query", self.database_key_index().debug(db));
 
         db.salsa_event(Event {
             runtime_id: db.salsa_runtime().id(),
-            kind: EventKind::WillExecute { database_key: self.database_key_index },
+            kind: EventKind::WillExecute { database_key: self.database_key_index() },
         });
 
         // Query was not previously executed, or value is potentially
         // stale, or value is absent. Let's execute!
-        let value = match Cycle::catch(|| Q::execute(db, self.key.clone())) {
+        let value = match Cycle::catch(|| Q::execute(db, key.clone())) {
             Ok(v) => v,
             Err(cycle) => {
                 tracing::debug!(
                     "{:?}: caught cycle {:?}, have strategy {:?}",
-                    self.database_key_index.debug(db),
+                    self.database_key_index().debug(db),
                     cycle,
                     Q::CYCLE_STRATEGY,
                 );
@@ -248,12 +258,12 @@ where
                     crate::plumbing::CycleRecoveryStrategy::Fallback => {
                         if let Some(c) = active_query.take_cycle() {
                             assert!(c.is(&cycle));
-                            Q::cycle_fallback(db, &cycle, &self.key)
+                            Q::cycle_fallback(db, &cycle, key)
                         } else {
                             // we are not a participant in this cycle
                             debug_assert!(!cycle
                                 .participant_keys()
-                                .any(|k| k == self.database_key_index));
+                                .any(|k| k == self.database_key_index()));
                             cycle.throw()
                         }
                     }
@@ -303,7 +313,7 @@ where
         };
 
         let memo_value =
-            if self.should_memoize_value(&self.key) { Some(new_value.value.clone()) } else { None };
+            if self.should_memoize_value(key) { Some(new_value.value.clone()) } else { None };
 
         debug!("read_upgrade({:?}): result.revisions = {:#?}", self, revisions,);
 
@@ -395,13 +405,11 @@ where
         }
     }
 
-    pub(super) fn as_table_entry(&self) -> Option<TableEntry<Q::Key, Q::Value>> {
+    pub(super) fn as_table_entry(&self, key: &Q::Key) -> Option<TableEntry<Q::Key, Q::Value>> {
         match &*self.state.read() {
             QueryState::NotComputed => None,
-            QueryState::InProgress { .. } => Some(TableEntry::new(self.key.clone(), None)),
-            QueryState::Memoized(memo) => {
-                Some(TableEntry::new(self.key.clone(), memo.value.clone()))
-            }
+            QueryState::InProgress { .. } => Some(TableEntry::new(key.clone(), None)),
+            QueryState::Memoized(memo) => Some(TableEntry::new(key.clone(), memo.value.clone())),
         }
     }
 
@@ -436,6 +444,7 @@ where
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
         revision: Revision,
+        key: &Q::Key,
     ) -> bool {
         let runtime = db.salsa_runtime();
         let revision_now = runtime.current_revision();
@@ -458,7 +467,7 @@ where
                 MaybeChangedSinceProbeState::ChangedAt(changed_at) => return changed_at > revision,
                 MaybeChangedSinceProbeState::Stale(state) => {
                     drop(state);
-                    return self.maybe_changed_after_upgrade(db, revision);
+                    return self.maybe_changed_after_upgrade(db, revision, key);
                 }
             }
         }
@@ -495,6 +504,7 @@ where
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
         revision: Revision,
+        key: &Q::Key,
     ) -> bool {
         let runtime = db.salsa_runtime();
         let revision_now = runtime.current_revision();
@@ -513,7 +523,9 @@ where
             // If another thread was active, then the cache line is going to be
             // either verified or cleared out. Just recurse to figure out which.
             // Note that we don't need an upgradable read.
-            MaybeChangedSinceProbeState::Retry => return self.maybe_changed_after(db, revision),
+            MaybeChangedSinceProbeState::Retry => {
+                return self.maybe_changed_after(db, revision, key)
+            }
 
             MaybeChangedSinceProbeState::Stale(state) => {
                 type RwLockUpgradableReadGuard<'a, T> =
@@ -527,8 +539,8 @@ where
             }
         };
 
-        let panic_guard = PanicGuard::new(self.database_key_index, self, runtime);
-        let active_query = runtime.push_query(self.database_key_index);
+        let panic_guard = PanicGuard::new(self, runtime);
+        let active_query = runtime.push_query(self.database_key_index());
 
         if old_memo.verify_revisions(db.ops_database(), revision_now, &active_query) {
             let maybe_changed = old_memo.revisions.changed_at > revision;
@@ -538,8 +550,15 @@ where
             // We found that this memoized value may have changed
             // but we have an old value. We can re-run the code and
             // actually *check* if it has changed.
-            let StampedValue { changed_at, .. } =
-                self.execute(db, runtime, revision_now, active_query, panic_guard, Some(old_memo));
+            let StampedValue { changed_at, .. } = self.execute(
+                db,
+                runtime,
+                revision_now,
+                active_query,
+                panic_guard,
+                Some(old_memo),
+                key,
+            );
             changed_at > revision
         } else {
             // We found that inputs to this memoized value may have chanced
@@ -560,7 +579,7 @@ where
     ) {
         runtime.block_on_or_unwind(
             db.ops_database(),
-            self.database_key_index,
+            self.database_key_index(),
             other_id,
             mutex_guard,
         )
@@ -585,7 +604,6 @@ where
     Q: QueryFunction,
     MP: MemoizationPolicy<Q>,
 {
-    database_key_index: DatabaseKeyIndex,
     slot: &'me Slot<Q, MP>,
     runtime: &'me Runtime,
 }
@@ -595,12 +613,8 @@ where
     Q: QueryFunction,
     MP: MemoizationPolicy<Q>,
 {
-    fn new(
-        database_key_index: DatabaseKeyIndex,
-        slot: &'me Slot<Q, MP>,
-        runtime: &'me Runtime,
-    ) -> Self {
-        Self { database_key_index, slot, runtime }
+    fn new(slot: &'me Slot<Q, MP>, runtime: &'me Runtime) -> Self {
+        Self { slot, runtime }
     }
 
     /// Indicates that we have concluded normally (without panicking).
@@ -616,17 +630,18 @@ where
     /// inserted; if others were blocked, waiting for us to finish,
     /// then notify them.
     fn overwrite_placeholder(&mut self, wait_result: WaitResult, opt_memo: Option<Memo<Q::Value>>) {
-        let mut write = self.slot.state.write();
-
-        let old_value = match opt_memo {
-            // Replace the `InProgress` marker that we installed with the new
-            // memo, thus releasing our unique access to this key.
-            Some(memo) => std::mem::replace(&mut *write, QueryState::Memoized(memo)),
-
-            // We had installed an `InProgress` marker, but we panicked before
-            // it could be removed. At this point, we therefore "own" unique
-            // access to our slot, so we can just remove the key.
-            None => std::mem::replace(&mut *write, QueryState::NotComputed),
+        let old_value = {
+            let mut write = self.slot.state.write();
+            match opt_memo {
+                // Replace the `InProgress` marker that we installed with the new
+                // memo, thus releasing our unique access to this key.
+                Some(memo) => std::mem::replace(&mut *write, QueryState::Memoized(memo)),
+
+                // We had installed an `InProgress` marker, but we panicked before
+                // it could be removed. At this point, we therefore "own" unique
+                // access to our slot, so we can just remove the key.
+                None => std::mem::replace(&mut *write, QueryState::NotComputed),
+            }
         };
 
         match old_value {
@@ -638,7 +653,8 @@ where
                 // acquire a mutex; the mutex will guarantee that all writes
                 // we are interested in are visible.
                 if anyone_waiting.load(Ordering::Relaxed) {
-                    self.runtime.unblock_queries_blocked_on(self.database_key_index, wait_result);
+                    self.runtime
+                        .unblock_queries_blocked_on(self.slot.database_key_index(), wait_result);
                 }
             }
             _ => panic!(
@@ -692,10 +708,10 @@ where
             return None;
         }
         if self.verify_revisions(db, revision_now, active_query) {
-            Some(StampedValue {
+            self.value.clone().map(|value| StampedValue {
                 durability: self.revisions.durability,
                 changed_at: self.revisions.changed_at,
-                value: self.value.as_ref().unwrap().clone(),
+                value,
             })
         } else {
             None
@@ -748,7 +764,7 @@ where
             // input changed *again*.
             QueryInputs::Tracked { inputs } => {
                 let changed_input =
-                    inputs.iter().find(|&&input| db.maybe_changed_after(input, verified_at));
+                    inputs.slice.iter().find(|&&input| db.maybe_changed_after(input, verified_at));
                 if let Some(input) = changed_input {
                     debug!("validate_memoized_value: `{:?}` may have changed", input);
 
@@ -788,7 +804,7 @@ where
     MP: MemoizationPolicy<Q>,
 {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(fmt, "{:?}({:?})", Q::default(), self.key)
+        write!(fmt, "{:?}", Q::default())
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/durability.rs b/src/tools/rust-analyzer/crates/salsa/src/durability.rs
index 0c82f6345ab..44abae3170f 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/durability.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/durability.rs
@@ -42,9 +42,9 @@ impl Durability {
     pub(crate) const MAX: Durability = Self::HIGH;
 
     /// Number of durability levels.
-    pub(crate) const LEN: usize = 3;
+    pub(crate) const LEN: usize = Self::MAX.index() + 1;
 
-    pub(crate) fn index(self) -> usize {
+    pub(crate) const fn index(self) -> usize {
         self.0 as usize
     }
 }
diff --git a/src/tools/rust-analyzer/crates/salsa/src/input.rs b/src/tools/rust-analyzer/crates/salsa/src/input.rs
index c2539570e0f..922ec5a7752 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/input.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/input.rs
@@ -29,7 +29,7 @@ where
 }
 
 struct Slot<V> {
-    database_key_index: DatabaseKeyIndex,
+    key_index: u32,
     stamped_value: RwLock<StampedValue<V>>,
 }
 
@@ -54,27 +54,25 @@ where
     fn fmt_index(
         &self,
         _db: &<Q as QueryDb<'_>>::DynDb,
-        index: DatabaseKeyIndex,
+        index: u32,
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result {
-        assert_eq!(index.group_index, self.group_index);
-        assert_eq!(index.query_index, Q::QUERY_INDEX);
         let slot_map = self.slots.read();
-        let key = slot_map.get_index(index.key_index as usize).unwrap().0;
+        let key = slot_map.get_index(index as usize).unwrap().0;
         write!(fmt, "{}({:?})", Q::QUERY_NAME, key)
     }
 
     fn maybe_changed_after(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        input: DatabaseKeyIndex,
+        index: u32,
         revision: Revision,
     ) -> bool {
-        assert_eq!(input.group_index, self.group_index);
-        assert_eq!(input.query_index, Q::QUERY_INDEX);
         debug_assert!(revision < db.salsa_runtime().current_revision());
         let slots = &self.slots.read();
-        let slot = slots.get_index(input.key_index as usize).unwrap().1;
+        let Some((_, slot)) = slots.get_index(index as usize) else {
+            return true;
+        };
 
         debug!("maybe_changed_after(slot={:?}, revision={:?})", Q::default(), revision,);
 
@@ -96,7 +94,11 @@ where
         let StampedValue { value, durability, changed_at } = slot.stamped_value.read().clone();
 
         db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
-            slot.database_key_index,
+            DatabaseKeyIndex {
+                group_index: self.group_index,
+                query_index: Q::QUERY_INDEX,
+                key_index: slot.key_index,
+            },
             durability,
             changed_at,
         );
@@ -174,16 +176,8 @@ where
                 }
 
                 Entry::Vacant(entry) => {
-                    let key_index = u32::try_from(entry.index()).unwrap();
-                    let database_key_index = DatabaseKeyIndex {
-                        group_index: self.group_index,
-                        query_index: Q::QUERY_INDEX,
-                        key_index,
-                    };
-                    entry.insert(Slot {
-                        database_key_index,
-                        stamped_value: RwLock::new(stamped_value),
-                    });
+                    let key_index = entry.index() as u32;
+                    entry.insert(Slot { key_index, stamped_value: RwLock::new(stamped_value) });
                     None
                 }
             }
@@ -196,7 +190,6 @@ pub struct UnitInputStorage<Q>
 where
     Q: Query<Key = ()>,
 {
-    group_index: u16,
     slot: UnitSlot<Q::Value>,
 }
 
@@ -222,36 +215,32 @@ where
     fn new(group_index: u16) -> Self {
         let database_key_index =
             DatabaseKeyIndex { group_index, query_index: Q::QUERY_INDEX, key_index: 0 };
-        UnitInputStorage {
-            group_index,
-            slot: UnitSlot { database_key_index, stamped_value: RwLock::new(None) },
-        }
+        UnitInputStorage { slot: UnitSlot { database_key_index, stamped_value: RwLock::new(None) } }
     }
 
     fn fmt_index(
         &self,
         _db: &<Q as QueryDb<'_>>::DynDb,
-        index: DatabaseKeyIndex,
+        _index: u32,
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result {
-        assert_eq!(index.group_index, self.group_index);
-        assert_eq!(index.query_index, Q::QUERY_INDEX);
         write!(fmt, "{}", Q::QUERY_NAME)
     }
 
     fn maybe_changed_after(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        input: DatabaseKeyIndex,
+        _index: u32,
         revision: Revision,
     ) -> bool {
-        assert_eq!(input.group_index, self.group_index);
-        assert_eq!(input.query_index, Q::QUERY_INDEX);
         debug_assert!(revision < db.salsa_runtime().current_revision());
 
         debug!("maybe_changed_after(slot={:?}, revision={:?})", Q::default(), revision,);
 
-        let changed_at = self.slot.stamped_value.read().as_ref().unwrap().changed_at;
+        let Some(value) = &*self.slot.stamped_value.read() else {
+            return true;
+        };
+        let changed_at = value.changed_at;
 
         debug!("maybe_changed_after: changed_at = {:?}", changed_at);
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/interned.rs b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
index 822219f5185..c065e7e2bde 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/interned.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
@@ -265,12 +265,10 @@ where
     fn fmt_index(
         &self,
         _db: &<Q as QueryDb<'_>>::DynDb,
-        index: DatabaseKeyIndex,
+        index: u32,
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result {
-        assert_eq!(index.group_index, self.group_index);
-        assert_eq!(index.query_index, Q::QUERY_INDEX);
-        let intern_id = InternId::from(index.key_index);
+        let intern_id = InternId::from(index);
         let slot = self.lookup_value(intern_id);
         write!(fmt, "{}({:?})", Q::QUERY_NAME, slot.value)
     }
@@ -278,13 +276,11 @@ where
     fn maybe_changed_after(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        input: DatabaseKeyIndex,
+        input: u32,
         revision: Revision,
     ) -> bool {
-        assert_eq!(input.group_index, self.group_index);
-        assert_eq!(input.query_index, Q::QUERY_INDEX);
         debug_assert!(revision < db.salsa_runtime().current_revision());
-        let intern_id = InternId::from(input.key_index);
+        let intern_id = InternId::from(input);
         let slot = self.lookup_value(intern_id);
         slot.maybe_changed_after(revision)
     }
@@ -388,7 +384,7 @@ where
     fn fmt_index(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        index: DatabaseKeyIndex,
+        index: u32,
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result {
         let group_storage =
@@ -400,7 +396,7 @@ where
     fn maybe_changed_after(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        input: DatabaseKeyIndex,
+        input: u32,
         revision: Revision,
     ) -> bool {
         let group_storage =
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
index 668dcfd925d..fe807598873 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
@@ -54,7 +54,7 @@ pub trait Database: plumbing::DatabaseOps {
     /// runtime. It permits the database to be customized and to
     /// inject logging or other custom behavior.
     fn salsa_event(&self, event_fn: Event) {
-        #![allow(unused_variables)]
+        _ = event_fn;
     }
 
     /// Starts unwinding the stack if the current revision is cancelled.
@@ -96,11 +96,16 @@ pub trait Database: plumbing::DatabaseOps {
         self.ops_salsa_runtime()
     }
 
-    /// Gives access to the underlying salsa runtime.
+    /// A "synthetic write" causes the system to act *as though* some
+    /// input of durability `durability` has changed. This is mostly
+    /// useful for profiling scenarios.
     ///
-    /// This method should not be overridden by `Database` implementors.
-    fn salsa_runtime_mut(&mut self) -> &mut Runtime {
-        self.ops_salsa_runtime_mut()
+    /// **WARNING:** Just like an ordinary write, this method triggers
+    /// cancellation. If you invoke it while a snapshot exists, it
+    /// will block until that snapshot is dropped -- if that snapshot
+    /// is owned by the current thread, this could trigger deadlock.
+    fn synthetic_write(&mut self, durability: Durability) {
+        plumbing::DatabaseOps::synthetic_write(self, durability)
     }
 }
 
@@ -456,12 +461,12 @@ pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> {
     /// Name of the query method (e.g., `foo`)
     const QUERY_NAME: &'static str;
 
-    /// Extact storage for this query from the storage for its group.
+    /// Extract storage for this query from the storage for its group.
     fn query_storage<'a>(
         group_storage: &'a <Self as QueryDb<'_>>::GroupStorage,
     ) -> &'a std::sync::Arc<Self::Storage>;
 
-    /// Extact storage for this query from the storage for its group.
+    /// Extract storage for this query from the storage for its group.
     fn query_storage_mut<'a>(
         group_storage: &'a <Self as QueryDb<'_>>::GroupStorage,
     ) -> &'a std::sync::Arc<Self::Storage>;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lru.rs b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
index c6b9778f20a..1ff85a3ea45 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lru.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
@@ -40,7 +40,7 @@ pub(crate) trait LruNode: Sized + Debug {
 
 #[derive(Debug)]
 pub(crate) struct LruIndex {
-    /// Index in the approprate LRU list, or std::usize::MAX if not a
+    /// Index in the appropriate LRU list, or std::usize::MAX if not a
     /// member.
     index: AtomicUsize,
 }
diff --git a/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs b/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs
index 71332e39cad..1a8ff33b2ef 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs
@@ -38,8 +38,15 @@ pub trait DatabaseOps {
     /// Gives access to the underlying salsa runtime.
     fn ops_salsa_runtime(&self) -> &Runtime;
 
-    /// Gives access to the underlying salsa runtime.
-    fn ops_salsa_runtime_mut(&mut self) -> &mut Runtime;
+    /// A "synthetic write" causes the system to act *as though* some
+    /// input of durability `durability` has changed. This is mostly
+    /// useful for profiling scenarios.
+    ///
+    /// **WARNING:** Just like an ordinary write, this method triggers
+    /// cancellation. If you invoke it while a snapshot exists, it
+    /// will block until that snapshot is dropped -- if that snapshot
+    /// is owned by the current thread, this could trigger deadlock.
+    fn synthetic_write(&mut self, durability: Durability);
 
     /// Formats a database key index in a human readable fashion.
     fn fmt_index(
@@ -166,7 +173,7 @@ where
     fn fmt_index(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        index: DatabaseKeyIndex,
+        index: u32,
         fmt: &mut std::fmt::Formatter<'_>,
     ) -> std::fmt::Result;
 
@@ -179,7 +186,7 @@ where
     fn maybe_changed_after(
         &self,
         db: &<Q as QueryDb<'_>>::DynDb,
-        input: DatabaseKeyIndex,
+        index: u32,
         revision: Revision,
     ) -> bool;
     // ANCHOR_END:maybe_changed_after
diff --git a/src/tools/rust-analyzer/crates/salsa/src/revision.rs b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
index d97aaf9deba..559b0338608 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/revision.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
@@ -46,7 +46,7 @@ pub(crate) struct AtomicRevision {
 }
 
 impl AtomicRevision {
-    pub(crate) fn start() -> Self {
+    pub(crate) const fn start() -> Self {
         Self { data: AtomicU32::new(START) }
     }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs
index 40b8856991f..a7d5a245782 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs
@@ -4,13 +4,14 @@ use crate::hash::FxIndexSet;
 use crate::plumbing::CycleRecoveryStrategy;
 use crate::revision::{AtomicRevision, Revision};
 use crate::{Cancelled, Cycle, Database, DatabaseKeyIndex, Event, EventKind};
+use itertools::Itertools;
 use parking_lot::lock_api::{RawRwLock, RawRwLockRecursive};
 use parking_lot::{Mutex, RwLock};
 use std::hash::Hash;
 use std::panic::panic_any;
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::{AtomicU32, Ordering};
 use tracing::debug;
-use triomphe::Arc;
+use triomphe::{Arc, ThinArc};
 
 mod dependency_graph;
 use dependency_graph::DependencyGraph;
@@ -297,8 +298,7 @@ impl Runtime {
             // (at least for this execution, not necessarily across executions),
             // no matter where it started on the stack. Find the minimum
             // key and rotate it to the front.
-            let min = v.iter().min().unwrap();
-            let index = v.iter().position(|p| p == min).unwrap();
+            let index = v.iter().position_min().unwrap_or_default();
             v.rotate_left(index);
 
             // No need to store extra memory.
@@ -440,7 +440,7 @@ impl Runtime {
 /// State that will be common to all threads (when we support multiple threads)
 struct SharedState {
     /// Stores the next id to use for a snapshotted runtime (starts at 1).
-    next_id: AtomicUsize,
+    next_id: AtomicU32,
 
     /// Whenever derived queries are executing, they acquire this lock
     /// in read mode. Mutating inputs (and thus creating a new
@@ -457,50 +457,46 @@ struct SharedState {
     /// revision is cancelled).
     pending_revision: AtomicRevision,
 
-    /// Stores the "last change" revision for values of each duration.
+    /// Stores the "last change" revision for values of each Durability.
     /// This vector is always of length at least 1 (for Durability 0)
-    /// but its total length depends on the number of durations. The
+    /// but its total length depends on the number of Durabilities. The
     /// element at index 0 is special as it represents the "current
     /// revision".  In general, we have the invariant that revisions
     /// in here are *declining* -- that is, `revisions[i] >=
     /// revisions[i + 1]`, for all `i`. This is because when you
     /// modify a value with durability D, that implies that values
     /// with durability less than D may have changed too.
-    revisions: Vec<AtomicRevision>,
+    revisions: [AtomicRevision; Durability::LEN],
 
     /// The dependency graph tracks which runtimes are blocked on one
     /// another, waiting for queries to terminate.
     dependency_graph: Mutex<DependencyGraph>,
 }
 
-impl SharedState {
-    fn with_durabilities(durabilities: usize) -> Self {
-        SharedState {
-            next_id: AtomicUsize::new(1),
-            query_lock: Default::default(),
-            revisions: (0..durabilities).map(|_| AtomicRevision::start()).collect(),
-            pending_revision: AtomicRevision::start(),
-            dependency_graph: Default::default(),
-        }
-    }
-}
-
 impl std::panic::RefUnwindSafe for SharedState {}
 
 impl Default for SharedState {
     fn default() -> Self {
-        Self::with_durabilities(Durability::LEN)
+        #[allow(clippy::declare_interior_mutable_const)]
+        const START: AtomicRevision = AtomicRevision::start();
+        SharedState {
+            next_id: AtomicU32::new(1),
+            query_lock: Default::default(),
+            revisions: [START; Durability::LEN],
+            pending_revision: START,
+            dependency_graph: Default::default(),
+        }
     }
 }
 
 impl std::fmt::Debug for SharedState {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let query_lock = if self.query_lock.try_write().is_some() {
-            "<unlocked>"
-        } else if self.query_lock.try_read().is_some() {
+        let query_lock = if self.query_lock.is_locked_exclusive() {
+            "<wlocked>"
+        } else if self.query_lock.is_locked() {
             "<rlocked>"
         } else {
-            "<wlocked>"
+            "<unlocked>"
         };
         fmt.debug_struct("SharedState")
             .field("query_lock", &query_lock)
@@ -570,7 +566,9 @@ impl ActiveQuery {
                 if dependencies.is_empty() {
                     QueryInputs::NoInputs
                 } else {
-                    QueryInputs::Tracked { inputs: dependencies.iter().copied().collect() }
+                    QueryInputs::Tracked {
+                        inputs: ThinArc::from_header_and_iter((), dependencies.iter().copied()),
+                    }
                 }
             }
         };
@@ -616,7 +614,7 @@ impl ActiveQuery {
 /// complete, its `RuntimeId` may potentially be re-used.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct RuntimeId {
-    counter: usize,
+    counter: u32,
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs
index e41eb280dee..dd223eeeba9 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs
@@ -12,7 +12,7 @@ type QueryStack = Vec<ActiveQuery>;
 
 #[derive(Debug, Default)]
 pub(super) struct DependencyGraph {
-    /// A `(K -> V)` pair in this map indicates that the the runtime
+    /// A `(K -> V)` pair in this map indicates that the runtime
     /// `K` is blocked on some query executing in the runtime `V`.
     /// This encodes a graph that must be acyclic (or else deadlock
     /// will result).
diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs
index 91b95dffe78..7ac21dec1a8 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs
@@ -1,5 +1,6 @@
 //!
 use tracing::debug;
+use triomphe::ThinArc;
 
 use crate::durability::Durability;
 use crate::runtime::ActiveQuery;
@@ -7,7 +8,6 @@ use crate::runtime::Revision;
 use crate::Cycle;
 use crate::DatabaseKeyIndex;
 use std::cell::RefCell;
-use triomphe::Arc;
 
 /// State that is specific to a single execution thread.
 ///
@@ -43,7 +43,7 @@ pub(crate) struct QueryRevisions {
 #[derive(Debug, Clone)]
 pub(crate) enum QueryInputs {
     /// Non-empty set of inputs, fully known
-    Tracked { inputs: Arc<[DatabaseKeyIndex]> },
+    Tracked { inputs: ThinArc<(), DatabaseKeyIndex> },
 
     /// Empty set of inputs, fully known.
     NoInputs,
@@ -145,8 +145,7 @@ impl LocalState {
     /// the current thread is blocking. The stack must be restored
     /// with [`Self::restore_query_stack`] when the thread unblocks.
     pub(super) fn take_query_stack(&self) -> Vec<ActiveQuery> {
-        assert!(self.query_stack.borrow().is_some(), "query stack already taken");
-        self.query_stack.take().unwrap()
+        self.query_stack.take().expect("query stack already taken")
     }
 
     /// Restores a query stack taken with [`Self::take_query_stack`] once
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs
index 6dc5030063b..3dcc32eece3 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs
@@ -58,7 +58,7 @@ fn revalidate() {
 
     // Second generation: volatile will change (to 1) but memoized1
     // will not (still 0, as 1/2 = 0)
-    query.salsa_runtime_mut().synthetic_write(Durability::LOW);
+    query.synthetic_write(Durability::LOW);
     query.memoized2();
     query.assert_log(&["Volatile invoked", "Memoized1 invoked"]);
     query.memoized2();
@@ -67,7 +67,7 @@ fn revalidate() {
     // Third generation: volatile will change (to 2) and memoized1
     // will too (to 1).  Therefore, after validating that Memoized1
     // changed, we now invoke Memoized2.
-    query.salsa_runtime_mut().synthetic_write(Durability::LOW);
+    query.synthetic_write(Durability::LOW);
 
     query.memoized2();
     query.assert_log(&["Volatile invoked", "Memoized1 invoked", "Memoized2 invoked"]);
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs
index 5d0e4866442..677d633ee7c 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs
@@ -111,7 +111,7 @@ fn on_demand_input_durability() {
         }
     "#]].assert_debug_eq(&events);
 
-    db.salsa_runtime_mut().synthetic_write(Durability::LOW);
+    db.synthetic_write(Durability::LOW);
     events.replace(vec![]);
     assert_eq!(db.c(1), 10);
     assert_eq!(db.c(2), 20);
@@ -128,7 +128,7 @@ fn on_demand_input_durability() {
         }
     "#]].assert_debug_eq(&events);
 
-    db.salsa_runtime_mut().synthetic_write(Durability::HIGH);
+    db.synthetic_write(Durability::HIGH);
     events.replace(vec![]);
     assert_eq!(db.c(1), 10);
     assert_eq!(db.c(2), 20);
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs
index f75c7c142fe..8e2f9b03cb9 100644
--- a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs
+++ b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs
@@ -20,7 +20,7 @@ fn volatile_twice() {
     let v2 = db.volatile(); // volatiles are cached, so 2nd read returns the same
     assert_eq!(v1, v2);
 
-    db.salsa_runtime_mut().synthetic_write(Durability::LOW); // clears volatile caches
+    db.synthetic_write(Durability::LOW); // clears volatile caches
 
     let v3 = db.volatile(); // will re-increment the counter
     let v4 = db.volatile(); // second call will be cached
@@ -40,7 +40,7 @@ fn intermingled() {
     assert_eq!(v1, v3);
     assert_eq!(v2, v4);
 
-    db.salsa_runtime_mut().synthetic_write(Durability::LOW); // clears volatile caches
+    db.synthetic_write(Durability::LOW); // clears volatile caches
 
     let v5 = db.memoized(); // re-executes volatile, caches new result
     let v6 = db.memoized(); // re-use cached result
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 9a9ebae74e8..0504ca50b88 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -302,6 +302,22 @@ pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> {
     (0..this.len()).map(|i| &this[i..])
 }
 
+pub trait IsNoneOr {
+    type Type;
+    #[allow(clippy::wrong_self_convention)]
+    fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool;
+}
+#[allow(unstable_name_collisions)]
+impl<T> IsNoneOr for Option<T> {
+    type Type = T;
+    fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
+        match self {
+            Some(v) => f(v),
+            None => true,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index 3d33d255ad4..849fae5cf24 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -4,7 +4,11 @@ import * as ra from "./lsp_ext";
 import * as path from "path";
 
 import type { Ctx, Cmd, CtxInit } from "./ctx";
-import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
+import {
+    applySnippetWorkspaceEdit,
+    applySnippetTextEdits,
+    type SnippetTextDocumentEdit,
+} from "./snippets";
 import { spawnSync } from "child_process";
 import { type RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
 import { AstInspector } from "./ast_inspector";
@@ -1006,7 +1010,6 @@ export function resolveCodeAction(ctx: CtxInit): Cmd {
             return;
         }
         const itemEdit = item.edit;
-        const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
         // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
         // snippet edits on our own
         const lcFileSystemEdit = {
@@ -1017,16 +1020,71 @@ export function resolveCodeAction(ctx: CtxInit): Cmd {
             lcFileSystemEdit,
         );
         await vscode.workspace.applyEdit(fileSystemEdit);
-        await applySnippetWorkspaceEdit(edit);
+
+        // replace all text edits so that we can convert snippet text edits into `vscode.SnippetTextEdit`s
+        // FIXME: this is a workaround until vscode-languageclient supports doing the SnippeTextEdit conversion itself
+        // also need to carry the snippetTextDocumentEdits separately, since we can't retrieve them again using WorkspaceEdit.entries
+        const [workspaceTextEdit, snippetTextDocumentEdits] = asWorkspaceSnippetEdit(ctx, itemEdit);
+        await applySnippetWorkspaceEdit(workspaceTextEdit, snippetTextDocumentEdits);
         if (item.command != null) {
             await vscode.commands.executeCommand(item.command.command, item.command.arguments);
         }
     };
 }
 
+function asWorkspaceSnippetEdit(
+    ctx: CtxInit,
+    item: lc.WorkspaceEdit,
+): [vscode.WorkspaceEdit, SnippetTextDocumentEdit[]] {
+    const client = ctx.client;
+
+    // partially borrowed from https://github.com/microsoft/vscode-languageserver-node/blob/295aaa393fda8ecce110c38880a00466b9320e63/client/src/common/protocolConverter.ts#L1060-L1101
+    const result = new vscode.WorkspaceEdit();
+
+    if (item.documentChanges) {
+        const snippetTextDocumentEdits: SnippetTextDocumentEdit[] = [];
+
+        for (const change of item.documentChanges) {
+            if (lc.TextDocumentEdit.is(change)) {
+                const uri = client.protocol2CodeConverter.asUri(change.textDocument.uri);
+                const snippetTextEdits: (vscode.TextEdit | vscode.SnippetTextEdit)[] = [];
+
+                for (const edit of change.edits) {
+                    if (
+                        "insertTextFormat" in edit &&
+                        edit.insertTextFormat === lc.InsertTextFormat.Snippet
+                    ) {
+                        // is a snippet text edit
+                        snippetTextEdits.push(
+                            new vscode.SnippetTextEdit(
+                                client.protocol2CodeConverter.asRange(edit.range),
+                                new vscode.SnippetString(edit.newText),
+                            ),
+                        );
+                    } else {
+                        // always as a text document edit
+                        snippetTextEdits.push(
+                            vscode.TextEdit.replace(
+                                client.protocol2CodeConverter.asRange(edit.range),
+                                edit.newText,
+                            ),
+                        );
+                    }
+                }
+
+                snippetTextDocumentEdits.push([uri, snippetTextEdits]);
+            }
+        }
+        return [result, snippetTextDocumentEdits];
+    } else {
+        // we don't handle WorkspaceEdit.changes since it's not relevant for code actions
+        return [result, []];
+    }
+}
+
 export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd {
     return async (edit: vscode.WorkspaceEdit) => {
-        await applySnippetWorkspaceEdit(edit);
+        await applySnippetWorkspaceEdit(edit, edit.entries());
     };
 }
 
diff --git a/src/tools/rust-analyzer/editors/code/src/snippets.ts b/src/tools/rust-analyzer/editors/code/src/snippets.ts
index d81765649ff..b3982bdf2be 100644
--- a/src/tools/rust-analyzer/editors/code/src/snippets.ts
+++ b/src/tools/rust-analyzer/editors/code/src/snippets.ts
@@ -3,20 +3,28 @@ import * as vscode from "vscode";
 import { assert } from "./util";
 import { unwrapUndefinable } from "./undefinable";
 
-export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
-    if (edit.entries().length === 1) {
-        const [uri, edits] = unwrapUndefinable(edit.entries()[0]);
+export type SnippetTextDocumentEdit = [vscode.Uri, (vscode.TextEdit | vscode.SnippetTextEdit)[]];
+
+export async function applySnippetWorkspaceEdit(
+    edit: vscode.WorkspaceEdit,
+    editEntries: SnippetTextDocumentEdit[],
+) {
+    if (editEntries.length === 1) {
+        const [uri, edits] = unwrapUndefinable(editEntries[0]);
         const editor = await editorFromUri(uri);
-        if (editor) await applySnippetTextEdits(editor, edits);
+        if (editor) {
+            edit.set(uri, removeLeadingWhitespace(editor, edits));
+            await vscode.workspace.applyEdit(edit);
+        }
         return;
     }
-    for (const [uri, edits] of edit.entries()) {
+    for (const [uri, edits] of editEntries) {
         const editor = await editorFromUri(uri);
         if (editor) {
             await editor.edit((builder) => {
                 for (const indel of edits) {
                     assert(
-                        !parseSnippet(indel.newText),
+                        !(indel instanceof vscode.SnippetTextEdit),
                         `bad ws edit: snippet received with multiple edits: ${JSON.stringify(
                             edit,
                         )}`,
@@ -39,53 +47,97 @@ async function editorFromUri(uri: vscode.Uri): Promise<vscode.TextEditor | undef
 }
 
 export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vscode.TextEdit[]) {
-    const selections: vscode.Selection[] = [];
-    let lineDelta = 0;
-    await editor.edit((builder) => {
-        for (const indel of edits) {
-            const parsed = parseSnippet(indel.newText);
-            if (parsed) {
-                const [newText, [placeholderStart, placeholderLength]] = parsed;
-                const prefix = newText.substr(0, placeholderStart);
-                const lastNewline = prefix.lastIndexOf("\n");
+    const edit = new vscode.WorkspaceEdit();
+    const snippetEdits = toSnippetTextEdits(edits);
+    edit.set(editor.document.uri, removeLeadingWhitespace(editor, snippetEdits));
+    await vscode.workspace.applyEdit(edit);
+}
 
-                const startLine = indel.range.start.line + lineDelta + countLines(prefix);
-                const startColumn =
-                    lastNewline === -1
-                        ? indel.range.start.character + placeholderStart
-                        : prefix.length - lastNewline - 1;
-                const endColumn = startColumn + placeholderLength;
-                selections.push(
-                    new vscode.Selection(
-                        new vscode.Position(startLine, startColumn),
-                        new vscode.Position(startLine, endColumn),
-                    ),
+function hasSnippet(snip: string): boolean {
+    const m = snip.match(/\$\d+|\{\d+:[^}]*\}/);
+    return m != null;
+}
+
+function toSnippetTextEdits(
+    edits: vscode.TextEdit[],
+): (vscode.TextEdit | vscode.SnippetTextEdit)[] {
+    return edits.map((textEdit) => {
+        // Note: text edits without any snippets are returned as-is instead of
+        // being wrapped in a SnippetTextEdit, as otherwise it would be
+        // treated as if it had a tab stop at the end.
+        if (hasSnippet(textEdit.newText)) {
+            return new vscode.SnippetTextEdit(
+                textEdit.range,
+                new vscode.SnippetString(textEdit.newText),
+            );
+        } else {
+            return textEdit;
+        }
+    });
+}
+
+/**
+ * Removes the leading whitespace from snippet edits, so as to not double up
+ * on indentation.
+ *
+ * Snippet edits by default adjust any multi-line snippets to match the
+ * indentation of the line to insert at. Unfortunately, we (the server) also
+ * include the required indentation to match what we line insert at, so we end
+ * up doubling up the indentation. Since there isn't any way to tell vscode to
+ * not fixup indentation for us, we instead opt to remove the indentation and
+ * then let vscode add it back in.
+ *
+ * This assumes that the source snippet text edits have the required
+ * indentation, but that's okay as even without this workaround and the problem
+ * to workaround, those snippet edits would already be inserting at the wrong
+ * indentation.
+ */
+function removeLeadingWhitespace(
+    editor: vscode.TextEditor,
+    edits: (vscode.TextEdit | vscode.SnippetTextEdit)[],
+) {
+    return edits.map((edit) => {
+        if (edit instanceof vscode.SnippetTextEdit) {
+            const snippetEdit: vscode.SnippetTextEdit = edit;
+            const firstLineEnd = snippetEdit.snippet.value.indexOf("\n");
+
+            if (firstLineEnd !== -1) {
+                // Is a multi-line snippet, remove the indentation which
+                // would be added back in by vscode.
+                const startLine = editor.document.lineAt(snippetEdit.range.start.line);
+                const leadingWhitespace = getLeadingWhitespace(
+                    startLine.text,
+                    0,
+                    startLine.firstNonWhitespaceCharacterIndex,
                 );
-                builder.replace(indel.range, newText);
-            } else {
-                builder.replace(indel.range, indel.newText);
+
+                const [firstLine, rest] = splitAt(snippetEdit.snippet.value, firstLineEnd + 1);
+                const unindentedLines = rest
+                    .split("\n")
+                    .map((line) => line.replace(leadingWhitespace, ""))
+                    .join("\n");
+
+                snippetEdit.snippet.value = firstLine + unindentedLines;
             }
-            lineDelta +=
-                countLines(indel.newText) - (indel.range.end.line - indel.range.start.line);
+
+            return snippetEdit;
+        } else {
+            return edit;
         }
     });
-    if (selections.length > 0) editor.selections = selections;
-    if (selections.length === 1) {
-        const selection = unwrapUndefinable(selections[0]);
-        editor.revealRange(selection, vscode.TextEditorRevealType.InCenterIfOutsideViewport);
-    }
 }
 
-function parseSnippet(snip: string): [string, [number, number]] | undefined {
-    const m = snip.match(/\$(0|\{0:([^}]*)\})/);
-    if (!m) return undefined;
-    const placeholder = m[2] ?? "";
-    if (m.index == null) return undefined;
-    const range: [number, number] = [m.index, placeholder.length];
-    const insert = snip.replace(m[0], placeholder);
-    return [insert, range];
+// based on https://github.com/microsoft/vscode/blob/main/src/vs/base/common/strings.ts#L284
+function getLeadingWhitespace(str: string, start: number = 0, end: number = str.length): string {
+    for (let i = start; i < end; i++) {
+        const chCode = str.charCodeAt(i);
+        if (chCode !== " ".charCodeAt(0) && chCode !== " ".charCodeAt(0)) {
+            return str.substring(start, i);
+        }
+    }
+    return str.substring(start, end);
 }
 
-function countLines(text: string): number {
-    return (text.match(/\n/g) || []).length;
+function splitAt(str: string, index: number): [string, string] {
+    return [str.substring(0, index), str.substring(index)];
 }
diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs
index 2efafa10a82..285abb9efcb 100644
--- a/src/tools/rust-analyzer/xtask/src/metrics.rs
+++ b/src/tools/rust-analyzer/xtask/src/metrics.rs
@@ -86,7 +86,11 @@ impl Metrics {
     fn measure_rustc_tests(&mut self, sh: &Shell) -> anyhow::Result<()> {
         eprintln!("\nMeasuring rustc tests");
 
-        cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust").run()?;
+        cmd!(
+            sh,
+            "git clone --depth=1 --branch 1.76.0 https://github.com/rust-lang/rust.git --single-branch"
+        )
+        .run()?;
 
         let output = cmd!(sh, "./target/release/rust-analyzer rustc-tests ./rust").read()?;
         for (metric, value, unit) in parse_metrics(&output) {
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 902b2ec6907..4e840dbfbb4 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -1,11 +1,12 @@
 use anyhow::{Context, Error};
 use flate2::{read::GzDecoder, write::GzEncoder};
 use rayon::prelude::*;
-use std::{convert::TryFrom, fmt, io::Read, io::Write, path::Path, str::FromStr};
+use std::{fmt, io::Read, io::Write, path::Path, str::FromStr};
 use xz2::{read::XzDecoder, write::XzEncoder};
 
 #[derive(Default, Debug, Copy, Clone)]
 pub enum CompressionProfile {
+    NoOp,
     Fast,
     #[default]
     Balanced,
@@ -20,6 +21,7 @@ impl FromStr for CompressionProfile {
             "fast" => Self::Fast,
             "balanced" => Self::Balanced,
             "best" => Self::Best,
+            "no-op" => Self::NoOp,
             other => anyhow::bail!("invalid compression profile: {other}"),
         })
     }
@@ -31,6 +33,7 @@ impl fmt::Display for CompressionProfile {
             CompressionProfile::Fast => f.write_str("fast"),
             CompressionProfile::Balanced => f.write_str("balanced"),
             CompressionProfile::Best => f.write_str("best"),
+            CompressionProfile::NoOp => f.write_str("no-op"),
         }
     }
 }
@@ -78,10 +81,16 @@ impl CompressionFormat {
                     CompressionProfile::Fast => flate2::Compression::fast(),
                     CompressionProfile::Balanced => flate2::Compression::new(6),
                     CompressionProfile::Best => flate2::Compression::best(),
+                    CompressionProfile::NoOp => panic!(
+                        "compression profile 'no-op' should not call `CompressionFormat::encode`."
+                    ),
                 },
             )),
             CompressionFormat::Xz => {
                 let encoder = match profile {
+                    CompressionProfile::NoOp => panic!(
+                        "compression profile 'no-op' should not call `CompressionFormat::encode`."
+                    ),
                     CompressionProfile::Fast => {
                         xz2::stream::MtStreamBuilder::new().threads(6).preset(1).encoder().unwrap()
                     }
diff --git a/src/tools/rust-installer/src/main.rs b/src/tools/rust-installer/src/main.rs
index 99acecdd43c..efb4c5bcb83 100644
--- a/src/tools/rust-installer/src/main.rs
+++ b/src/tools/rust-installer/src/main.rs
@@ -1,5 +1,5 @@
 use anyhow::{Context, Result};
-use clap::{self, Parser};
+use clap::Parser;
 
 #[derive(Parser)]
 struct CommandLine {
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index 7572dc6dcf8..e5a925b2cbf 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -38,6 +38,10 @@ actor! {
 impl Tarballer {
     /// Generates the actual tarballs
     pub fn run(self) -> Result<()> {
+        if let CompressionProfile::NoOp = self.compression_profile {
+            return Ok(());
+        }
+
         let tarball_name = self.output.clone() + ".tar";
         let encoder = CombinedEncoder::new(
             self.compression_formats
diff --git a/tests/assembly/option-nonzero-eq.rs b/tests/assembly/option-nonzero-eq.rs
index d6ec586d938..b04cf63fd78 100644
--- a/tests/assembly/option-nonzero-eq.rs
+++ b/tests/assembly/option-nonzero-eq.rs
@@ -5,7 +5,6 @@
 //@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
 //@ only-x86_64
 //@ ignore-sgx
-//@ ignore-debug
 
 use std::cmp::Ordering;
 
diff --git a/tests/assembly/slice-is_ascii.rs b/tests/assembly/slice-is_ascii.rs
index 0b764395214..3a050347d89 100644
--- a/tests/assembly/slice-is_ascii.rs
+++ b/tests/assembly/slice-is_ascii.rs
@@ -5,7 +5,6 @@
 //@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
 //@ only-x86_64
 //@ ignore-sgx
-//@ ignore-debug
 
 #![feature(str_internals)]
 
diff --git a/tests/assembly/static-relocation-model.rs b/tests/assembly/static-relocation-model.rs
index 975818bf94f..50527b85345 100644
--- a/tests/assembly/static-relocation-model.rs
+++ b/tests/assembly/static-relocation-model.rs
@@ -6,7 +6,6 @@
 //@ [A64] needs-llvm-components: aarch64
 //@ [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
 //@ [ppc64le] needs-llvm-components: powerpc
-//@ ignore-debug: alignment checks insert panics that we don't have a lang item for
 
 #![feature(no_core, lang_items)]
 #![no_core]
diff --git a/tests/codegen/align-offset.rs b/tests/codegen/align-offset.rs
index 9819dc20966..15b11f413cb 100644
--- a/tests/codegen/align-offset.rs
+++ b/tests/codegen/align-offset.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug (debug assertions in `slice::from_raw_parts` block optimizations)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs
index b356f8f33f9..743a15989f7 100644
--- a/tests/codegen/array-map.rs
+++ b/tests/codegen/array-map.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3
 //@ only-x86_64
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs
index 30f285096ed..fab9f8632fc 100644
--- a/tests/codegen/ascii-char.rs
+++ b/tests/codegen/ascii-char.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -C opt-level=1
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 #![feature(ascii_char)]
diff --git a/tests/codegen/binary-search-index-no-bound-check.rs b/tests/codegen/binary-search-index-no-bound-check.rs
index d2627d67142..96f6bb54b3f 100644
--- a/tests/codegen/binary-search-index-no-bound-check.rs
+++ b/tests/codegen/binary-search-index-no-bound-check.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
 
 // Make sure no bounds checks are emitted when slicing or indexing
diff --git a/tests/codegen/constant-branch.rs b/tests/codegen/constant-branch.rs
new file mode 100644
index 00000000000..3328b1eb4a8
--- /dev/null
+++ b/tests/codegen/constant-branch.rs
@@ -0,0 +1,67 @@
+//@ compile-flags: -Zmir-opt-level=0 -C no-prepopulate-passes -Copt-level=0
+// make sure that branching on a constant does not emit a conditional
+// branch or a switch
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @if_bool
+#[no_mangle]
+pub fn if_bool() {
+    // CHECK: br label %{{.+}}
+    _ = if true {
+        0
+    } else {
+        1
+    };
+
+    // CHECK: br label %{{.+}}
+    _ = if false {
+        0
+    } else {
+        1
+    };
+}
+
+// CHECK-LABEL: @if_constant_int_eq
+#[no_mangle]
+pub fn if_constant_int_eq() {
+    let val = 0;
+    // CHECK: br label %{{.+}}
+    _ = if val == 0 {
+        0
+    } else {
+        1
+    };
+
+    // CHECK: br label %{{.+}}
+    _ = if val == 1 {
+        0
+    } else {
+        1
+    };
+}
+
+// CHECK-LABEL: @if_constant_match
+#[no_mangle]
+pub fn if_constant_match() {
+    // CHECK: br label %{{.+}}
+    _ = match 1 {
+        1 => 2,
+        2 => 3,
+        _ => 4
+    };
+
+    // CHECK: br label %{{.+}}
+    _ = match 1 {
+        2 => 3,
+        _ => 4
+    };
+
+    // CHECK: br label %[[MINUS1:.+]]
+    _ = match -1 {
+    // CHECK: [[MINUS1]]:
+    // CHECK: store i32 1
+        -1 => 1,
+        _ => 0,
+    }
+}
diff --git a/tests/codegen/infallible-unwrap-in-opt-z.rs b/tests/codegen/infallible-unwrap-in-opt-z.rs
index cbcba03ad0a..3756fafe384 100644
--- a/tests/codegen/infallible-unwrap-in-opt-z.rs
+++ b/tests/codegen/infallible-unwrap-in-opt-z.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -C opt-level=z --edition=2021
-//@ ignore-debug
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issue-97217.rs b/tests/codegen/issue-97217.rs
index 93dd1228ce1..a0dfff2ef2e 100644
--- a/tests/codegen/issue-97217.rs
+++ b/tests/codegen/issue-97217.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -C opt-level=3
-//@ ignore-debug: the debug assertions get in the way
 //@ min-llvm-version: 17.0.2
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs
index 7c96f9a34f8..550d267a98f 100644
--- a/tests/codegen/issues/issue-101082.rs
+++ b/tests/codegen/issues/issue-101082.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs
index 6175d80c9cd..e3843e9edb0 100644
--- a/tests/codegen/issues/issue-101814.rs
+++ b/tests/codegen/issues/issue-101814.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issues/issue-106369.rs b/tests/codegen/issues/issue-106369.rs
index 5120c5f4e49..fd375e4e605 100644
--- a/tests/codegen/issues/issue-106369.rs
+++ b/tests/codegen/issues/issue-106369.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issues/issue-116878.rs b/tests/codegen/issues/issue-116878.rs
index 2c561d7be79..a09fac42c01 100644
--- a/tests/codegen/issues/issue-116878.rs
+++ b/tests/codegen/issues/issue-116878.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
 
 /// Make sure no bounds checks are emitted after a `get_unchecked`.
diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs
index 3f750157a81..756a75e2f0e 100644
--- a/tests/codegen/issues/issue-37945.rs
+++ b/tests/codegen/issues/issue-37945.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O -Zmerge-functions=disabled
 //@ ignore-32bit LLVM has a bug with them
-//@ ignore-debug
 
 // Check that LLVM understands that `Iter` pointer is not null. Issue #37945.
 
diff --git a/tests/codegen/issues/issue-45222.rs b/tests/codegen/issues/issue-45222.rs
index 8fa9d87f497..d2c1ba421c4 100644
--- a/tests/codegen/issues/issue-45222.rs
+++ b/tests/codegen/issues/issue-45222.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issues/issue-45466.rs b/tests/codegen/issues/issue-45466.rs
index 165bc3ca411..fc714247dfb 100644
--- a/tests/codegen/issues/issue-45466.rs
+++ b/tests/codegen/issues/issue-45466.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type="rlib"]
 
diff --git a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs
index c9bc7fc316e..b7568bea4d0 100644
--- a/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs
+++ b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs
@@ -2,7 +2,6 @@
 // prevent optimizing away bounds checks
 
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type="rlib"]
 
diff --git a/tests/codegen/issues/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs
index f96a8e9da4b..c014a1c1b1d 100644
--- a/tests/codegen/issues/issue-69101-bounds-check.rs
+++ b/tests/codegen/issues/issue-69101-bounds-check.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
 
 // Make sure no bounds checks are emitted in the loop when upfront slicing
diff --git a/tests/codegen/issues/issue-73258.rs b/tests/codegen/issues/issue-73258.rs
index bc71e15a41f..48f14fe2dfe 100644
--- a/tests/codegen/issues/issue-73258.rs
+++ b/tests/codegen/issues/issue-73258.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs
index db91a85474d..ef4538ac84e 100644
--- a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs
+++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
 
 // Make sure no bounds checks are emitted when slicing or indexing
diff --git a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs
index 9f65222b386..40827e32a01 100644
--- a/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs
+++ b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs
@@ -1,4 +1,3 @@
-//@ ignore-debug: The debug assertions get in the way
 //@ compile-flags: -O
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs
index d0838a3e860..31020b77984 100644
--- a/tests/codegen/iter-repeat-n-trivial-drop.rs
+++ b/tests/codegen/iter-repeat-n-trivial-drop.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O
 //@ only-x86_64
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 #![feature(iter_repeat_n)]
diff --git a/tests/codegen/layout-size-checks.rs b/tests/codegen/layout-size-checks.rs
index 55c2e86b40b..901f8f822f3 100644
--- a/tests/codegen/layout-size-checks.rs
+++ b/tests/codegen/layout-size-checks.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O
 //@ only-x86_64
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/lib-optimizations/iter-sum.rs b/tests/codegen/lib-optimizations/iter-sum.rs
index 6b6d61a3066..b563a6debb5 100644
--- a/tests/codegen/lib-optimizations/iter-sum.rs
+++ b/tests/codegen/lib-optimizations/iter-sum.rs
@@ -1,4 +1,3 @@
-//@ ignore-debug: the debug assertions get in the way
 //@ compile-flags: -O
 //@ only-x86_64 (vectorization varies between architectures)
 #![crate_type = "lib"]
diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs
index 0234b63aba5..c71cbbd08f9 100644
--- a/tests/codegen/mem-replace-big-type.rs
+++ b/tests/codegen/mem-replace-big-type.rs
@@ -4,7 +4,7 @@
 // known to be `1` after inlining).
 
 //@ compile-flags: -C no-prepopulate-passes -Zinline-mir=no
-//@ ignore-debug: the debug assertions get in the way
+//@ ignore-debug: precondition checks in ptr::read make them a bad candidate for MIR inlining
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs
index b6885aad9e4..b00fbad05d9 100644
--- a/tests/codegen/mem-replace-simple-type.rs
+++ b/tests/codegen/mem-replace-simple-type.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -O -C no-prepopulate-passes
 //@ only-x86_64 (to not worry about usize differing)
-//@ ignore-debug (the debug assertions get in the way)
+//@ ignore-debug: precondition checks make mem::replace not a candidate for MIR inlining
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/ptr-arithmetic.rs b/tests/codegen/ptr-arithmetic.rs
index 3a8bfee84ec..6f115d33d8d 100644
--- a/tests/codegen/ptr-arithmetic.rs
+++ b/tests/codegen/ptr-arithmetic.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O -Z merge-functions=disabled
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs
index 622a1cec4ac..4c623dee5e1 100644
--- a/tests/codegen/ptr-read-metadata.rs
+++ b/tests/codegen/ptr-read-metadata.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O -Z merge-functions=disabled
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/simd/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs
index 010500139e5..2edee552ca6 100644
--- a/tests/codegen/simd/simd-wide-sum.rs
+++ b/tests/codegen/simd/simd-wide-sum.rs
@@ -1,7 +1,6 @@
 //@ revisions: llvm mir-opt3
 //@ compile-flags: -C opt-level=3 -Z merge-functions=disabled --edition=2021
 //@ only-x86_64
-//@ ignore-debug: the debug assertions get in the way
 //@ [mir-opt3]compile-flags: -Zmir-opt-level=3
 //@ [mir-opt3]build-pass
 
diff --git a/tests/codegen/simd/swap-simd-types.rs b/tests/codegen/simd/swap-simd-types.rs
index e03e2d4ff8d..32e75220d69 100644
--- a/tests/codegen/simd/swap-simd-types.rs
+++ b/tests/codegen/simd/swap-simd-types.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O -C target-feature=+avx
 //@ only-x86_64
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/slice-as_chunks.rs b/tests/codegen/slice-as_chunks.rs
index c9cd482a9a4..631d18d7809 100644
--- a/tests/codegen/slice-as_chunks.rs
+++ b/tests/codegen/slice-as_chunks.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O
 //@ only-64bit (because the LLVM type of i64 for usize shows up)
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 #![feature(slice_as_chunks)]
diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs
index 52714a76a8d..ecce9201071 100644
--- a/tests/codegen/slice-indexing.rs
+++ b/tests/codegen/slice-indexing.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O
 //@ only-64bit (because the LLVM type of i64 for usize shows up)
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/slice-iter-fold.rs b/tests/codegen/slice-iter-fold.rs
index 5a9d789b984..1770cd4a119 100644
--- a/tests/codegen/slice-iter-fold.rs
+++ b/tests/codegen/slice-iter-fold.rs
@@ -1,4 +1,3 @@
-//@ ignore-debug: the debug assertions get in the way
 //@ compile-flags: -O
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs
index 43c64511e52..b2a4b2495b6 100644
--- a/tests/codegen/slice-iter-len-eq-zero.rs
+++ b/tests/codegen/slice-iter-len-eq-zero.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions add extra comparisons
 #![crate_type = "lib"]
 
 type Demo = [u8; 3];
diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs
index c82ae3b61b4..c960688b00c 100644
--- a/tests/codegen/slice-iter-nonnull.rs
+++ b/tests/codegen/slice-iter-nonnull.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug (these add extra checks that make it hard to verify)
 #![crate_type = "lib"]
 #![feature(exact_size_is_empty)]
 
diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs
index d34aecd1903..371e685ec6c 100644
--- a/tests/codegen/slice-ref-equality.rs
+++ b/tests/codegen/slice-ref-equality.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O -Zmerge-functions=disabled
-//@ ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/slice-reverse.rs b/tests/codegen/slice-reverse.rs
index 40bc89bc9d0..21add929f05 100644
--- a/tests/codegen/slice-reverse.rs
+++ b/tests/codegen/slice-reverse.rs
@@ -1,6 +1,6 @@
 //@ compile-flags: -O
 //@ only-x86_64
-//@ ignore-debug: the debug assertions in from_raw_parts get in the way
+//@ ignore-debug: debug assertions prevent generating shufflevector
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/slice_as_from_ptr_range.rs b/tests/codegen/slice_as_from_ptr_range.rs
index cc811e8f589..47c60461c0e 100644
--- a/tests/codegen/slice_as_from_ptr_range.rs
+++ b/tests/codegen/slice_as_from_ptr_range.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O
 //@ only-64bit (because we're using [ui]size)
-//@ ignore-debug (because the assertions get in the way)
 
 #![crate_type = "lib"]
 #![feature(slice_from_ptr_range)]
diff --git a/tests/codegen/swap-large-types.rs b/tests/codegen/swap-large-types.rs
index 20697890814..b182f3ed947 100644
--- a/tests/codegen/swap-large-types.rs
+++ b/tests/codegen/swap-large-types.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O
 //@ only-x86_64
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs
index 8d7f9f49eef..5fdf4a5804a 100644
--- a/tests/codegen/swap-small-types.rs
+++ b/tests/codegen/swap-small-types.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O -Z merge-functions=disabled
 //@ only-x86_64
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs
index 43d2a55c995..9217def76b5 100644
--- a/tests/codegen/transmute-optimized.rs
+++ b/tests/codegen/transmute-optimized.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O -Z merge-functions=disabled
-//@ ignore-debug
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/unchecked_shifts.rs b/tests/codegen/unchecked_shifts.rs
index 4e351d8d333..9cf2f2b0cb6 100644
--- a/tests/codegen/unchecked_shifts.rs
+++ b/tests/codegen/unchecked_shifts.rs
@@ -1,5 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug (because unchecked is checked in debug)
 
 #![crate_type = "lib"]
 #![feature(unchecked_shifts)]
diff --git a/tests/codegen/unwind-landingpad-inline.rs b/tests/codegen/unwind-landingpad-inline.rs
index 953ba5e901a..77ef8d2a5fe 100644
--- a/tests/codegen/unwind-landingpad-inline.rs
+++ b/tests/codegen/unwind-landingpad-inline.rs
@@ -1,6 +1,5 @@
 //@ min-llvm-version: 17.0.2
 //@ compile-flags: -Copt-level=3
-//@ ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
 
 // This test checks that we can inline drop_in_place in
diff --git a/tests/codegen/vec-calloc.rs b/tests/codegen/vec-calloc.rs
index bae344ab01d..f88ed7ae8a5 100644
--- a/tests/codegen/vec-calloc.rs
+++ b/tests/codegen/vec-calloc.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -O -Z merge-functions=disabled
 //@ only-x86_64
-//@ ignore-debug
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs
index 3ac2ec13d47..7a175dc4f7e 100644
--- a/tests/codegen/vec-in-place.rs
+++ b/tests/codegen/vec-in-place.rs
@@ -1,4 +1,4 @@
-//@ ignore-debug: the debug assertions get in the way
+//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata
 //@ compile-flags: -O -Z merge-functions=disabled
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs
index 0c225abd326..e4242c57402 100644
--- a/tests/codegen/vec-iter-collect-len.rs
+++ b/tests/codegen/vec-iter-collect-len.rs
@@ -1,4 +1,3 @@
-//@ ignore-debug: the debug assertions get in the way
 //@ compile-flags: -O
 #![crate_type="lib"]
 
diff --git a/tests/codegen/vec-iter.rs b/tests/codegen/vec-iter.rs
index 47e11af5bc3..310680969c4 100644
--- a/tests/codegen/vec-iter.rs
+++ b/tests/codegen/vec-iter.rs
@@ -1,4 +1,3 @@
-//@ ignore-debug: the debug assertions get in the way
 //@ compile-flags: -O
 #![crate_type = "lib"]
 #![feature(exact_size_is_empty)]
diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs
index 9cbfbc115b0..77a94b0b429 100644
--- a/tests/codegen/vec-optimizes-away.rs
+++ b/tests/codegen/vec-optimizes-away.rs
@@ -1,4 +1,3 @@
-//@ ignore-debug: the debug assertions get in the way
 //@ compile-flags: -O
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vec-reserve-extend.rs b/tests/codegen/vec-reserve-extend.rs
index 12795937bc8..1f00f7d2063 100644
--- a/tests/codegen/vec-reserve-extend.rs
+++ b/tests/codegen/vec-reserve-extend.rs
@@ -1,6 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug
-// (with debug assertions turned on, `assert_unchecked` generates a real assertion)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs
index 33b70300bf4..4e996b234f9 100644
--- a/tests/codegen/vec-shrink-panik.rs
+++ b/tests/codegen/vec-shrink-panik.rs
@@ -4,7 +4,7 @@
 //@ [old]ignore-llvm-version: 17 - 99
 //@ [new]min-llvm-version: 17
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
+//@ ignore-debug: plain old debug assertions
 //@ needs-unwind
 #![crate_type = "lib"]
 #![feature(shrink_to)]
diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs
index 5a2009b01d7..83765d10854 100644
--- a/tests/codegen/vec_pop_push_noop.rs
+++ b/tests/codegen/vec_pop_push_noop.rs
@@ -1,6 +1,4 @@
 //@ compile-flags: -O
-//@ ignore-debug
-// (with debug assertions turned on, `assert_unchecked` generates a real assertion)
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs
index cd549f8ebd4..31fcf035f11 100644
--- a/tests/codegen/vecdeque-drain.rs
+++ b/tests/codegen/vecdeque-drain.rs
@@ -1,7 +1,7 @@
 // Check that draining at the front or back doesn't copy memory.
 
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
+//@ ignore-debug: FIXME: checks for call detect scoped noalias metadata
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vecdeque-nonempty-get-no-panic.rs b/tests/codegen/vecdeque-nonempty-get-no-panic.rs
index 1128b4ed7a4..3f802de9eee 100644
--- a/tests/codegen/vecdeque-nonempty-get-no-panic.rs
+++ b/tests/codegen/vecdeque-nonempty-get-no-panic.rs
@@ -1,7 +1,6 @@
 // Guards against regression for optimization discussed in issue #80836
 
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vecdeque_no_panic.rs b/tests/codegen/vecdeque_no_panic.rs
index 57b6b2abbea..be2c4810ebc 100644
--- a/tests/codegen/vecdeque_no_panic.rs
+++ b/tests/codegen/vecdeque_no_panic.rs
@@ -1,7 +1,7 @@
 // This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic.
 
 //@ compile-flags: -O
-//@ ignore-debug: the debug assertions get in the way
+//@ ignore-debug: plain old debug assertions
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs
index bf4a74085ed..6c391d9114b 100644
--- a/tests/codegen/virtual-function-elimination.rs
+++ b/tests/codegen/virtual-function-elimination.rs
@@ -1,6 +1,5 @@
 //@ compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0
 //@ ignore-32bit
-//@ ignore-debug
 
 // CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
 // CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff
new file mode 100644
index 00000000000..dd79cff1dcf
--- /dev/null
+++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-abort.diff
@@ -0,0 +1,19 @@
+- // MIR for `caller` before Inline
++ // MIR for `caller` after Inline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = callee() -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..4506a338edd
--- /dev/null
+++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.Inline.panic-unwind.diff
@@ -0,0 +1,19 @@
+- // MIR for `caller` before Inline
++ // MIR for `caller` after Inline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = callee() -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir
new file mode 100644
index 00000000000..d0772e51a07
--- /dev/null
+++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-abort.mir
@@ -0,0 +1,14 @@
+// MIR for `caller` after PreCodegen
+
+fn caller() -> () {
+    let mut _0: ();
+    let _1: ();
+
+    bb0: {
+        _1 = callee() -> [return: bb1, unwind unreachable];
+    }
+
+    bb1: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir
new file mode 100644
index 00000000000..39ad4f1010b
--- /dev/null
+++ b/tests/mir-opt/inline/rustc_no_mir_inline.caller.PreCodegen.after.panic-unwind.mir
@@ -0,0 +1,14 @@
+// MIR for `caller` after PreCodegen
+
+fn caller() -> () {
+    let mut _0: ();
+    let _1: ();
+
+    bb0: {
+        _1 = callee() -> [return: bb1, unwind continue];
+    }
+
+    bb1: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/inline/rustc_no_mir_inline.rs b/tests/mir-opt/inline/rustc_no_mir_inline.rs
new file mode 100644
index 00000000000..b008df32726
--- /dev/null
+++ b/tests/mir-opt/inline/rustc_no_mir_inline.rs
@@ -0,0 +1,17 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+//@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
+
+#[inline]
+#[rustc_no_mir_inline]
+pub fn callee() {}
+
+// EMIT_MIR rustc_no_mir_inline.caller.Inline.diff
+// EMIT_MIR rustc_no_mir_inline.caller.PreCodegen.after.mir
+pub fn caller() {
+    // CHECK-LABEL: fn caller(
+    // CHECK: callee()
+    callee();
+}
diff --git a/tests/mir-opt/pre-codegen/slice_filter.rs b/tests/mir-opt/pre-codegen/slice_filter.rs
index 45686f0bf88..35881ff2b18 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.rs
+++ b/tests/mir-opt/pre-codegen/slice_filter.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=2
-//@ ignore-debug: standard library debug assertions add a panic that breaks this optimization
 
 #![crate_type = "lib"]
 
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
index 7370da5629c..65cac0a81ef 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
@@ -1,6 +1,6 @@
 // MIR for `variant_a::{closure#0}` after PreCodegen
 
-fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:8:25: 8:39}, _2: &&(usize, usize, usize, usize)) -> bool {
+fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2: &&(usize, usize, usize, usize)) -> bool {
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
     let _4: &usize;
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
index 5477796512c..d9e118d879a 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
@@ -1,6 +1,6 @@
 // MIR for `variant_b::{closure#0}` after PreCodegen
 
-fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:12:25: 12:41}, _2: &&(usize, usize, usize, usize)) -> bool {
+fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41}, _2: &&(usize, usize, usize, usize)) -> bool {
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
     let _4: usize;
diff --git a/tests/ui/cfg/cfg-target-abi.rs b/tests/ui/cfg/cfg-target-abi.rs
index 5d13337c1c3..306ae077325 100644
--- a/tests/ui/cfg/cfg-target-abi.rs
+++ b/tests/ui/cfg/cfg-target-abi.rs
@@ -1,5 +1,4 @@
 //@ run-pass
-#![feature(cfg_target_abi)]
 
 #[cfg(target_abi = "eabihf")]
 pub fn main() {
diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs
index 0c55e35a993..859a36c604c 100644
--- a/tests/ui/check-cfg/well-known-values.rs
+++ b/tests/ui/check-cfg/well-known-values.rs
@@ -10,7 +10,6 @@
 #![feature(cfg_overflow_checks)]
 #![feature(cfg_relocation_model)]
 #![feature(cfg_sanitize)]
-#![feature(cfg_target_abi)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
 #![feature(cfg_target_thread_local)]
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 6535cd9a1a1..5f52421fef5 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:26:5
+  --> $DIR/well-known-values.rs:25:5
    |
 LL |     clippy = "_UNEXPECTED_VALUE",
    |     ^^^^^^----------------------
@@ -11,7 +11,7 @@ LL |     clippy = "_UNEXPECTED_VALUE",
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:28:5
+  --> $DIR/well-known-values.rs:27:5
    |
 LL |     debug_assertions = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^----------------------
@@ -22,7 +22,7 @@ LL |     debug_assertions = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:30:5
+  --> $DIR/well-known-values.rs:29:5
    |
 LL |     doc = "_UNEXPECTED_VALUE",
    |     ^^^----------------------
@@ -33,7 +33,7 @@ LL |     doc = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:32:5
+  --> $DIR/well-known-values.rs:31:5
    |
 LL |     doctest = "_UNEXPECTED_VALUE",
    |     ^^^^^^^----------------------
@@ -44,7 +44,7 @@ LL |     doctest = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:34:5
+  --> $DIR/well-known-values.rs:33:5
    |
 LL |     miri = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -55,7 +55,7 @@ LL |     miri = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:36:5
+  --> $DIR/well-known-values.rs:35:5
    |
 LL |     overflow_checks = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^----------------------
@@ -66,7 +66,7 @@ LL |     overflow_checks = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:38:5
+  --> $DIR/well-known-values.rs:37:5
    |
 LL |     panic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL |     panic = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:40:5
+  --> $DIR/well-known-values.rs:39:5
    |
 LL |     proc_macro = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^----------------------
@@ -86,7 +86,7 @@ LL |     proc_macro = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:42:5
+  --> $DIR/well-known-values.rs:41:5
    |
 LL |     relocation_model = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL |     relocation_model = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:44:5
+  --> $DIR/well-known-values.rs:43:5
    |
 LL |     sanitize = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |     sanitize = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:46:5
+  --> $DIR/well-known-values.rs:45:5
    |
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -113,7 +113,7 @@ LL |     target_abi = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:48:5
+  --> $DIR/well-known-values.rs:47:5
    |
 LL |     target_arch = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -122,7 +122,7 @@ LL |     target_arch = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:50:5
+  --> $DIR/well-known-values.rs:49:5
    |
 LL |     target_endian = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -131,16 +131,16 @@ LL |     target_endian = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:52:5
+  --> $DIR/well-known-values.rs:51:5
    |
 LL |     target_env = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_env` are: ``, `eabihf`, `gnu`, `gnueabihf`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `psx`, `relibc`, `sgx`, `uclibc`
+   = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `psx`, `relibc`, `sgx`, `uclibc`
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:54:5
+  --> $DIR/well-known-values.rs:53:5
    |
 LL |     target_family = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -149,7 +149,7 @@ LL |     target_family = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:56:5
+  --> $DIR/well-known-values.rs:55:5
    |
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -158,7 +158,7 @@ LL |     target_feature = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:58:5
+  --> $DIR/well-known-values.rs:57:5
    |
 LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -167,7 +167,7 @@ LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:60:5
+  --> $DIR/well-known-values.rs:59:5
    |
 LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -176,7 +176,7 @@ LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:62:5
+  --> $DIR/well-known-values.rs:61:5
    |
 LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -185,7 +185,7 @@ LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:64:5
+  --> $DIR/well-known-values.rs:63:5
    |
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -194,7 +194,7 @@ LL |     target_os = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:66:5
+  --> $DIR/well-known-values.rs:65:5
    |
 LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -203,7 +203,7 @@ LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:68:5
+  --> $DIR/well-known-values.rs:67:5
    |
 LL |     target_thread_local = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^----------------------
@@ -214,7 +214,7 @@ LL |     target_thread_local = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:70:5
+  --> $DIR/well-known-values.rs:69:5
    |
 LL |     target_vendor = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -223,7 +223,7 @@ LL |     target_vendor = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:72:5
+  --> $DIR/well-known-values.rs:71:5
    |
 LL |     test = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -234,7 +234,7 @@ LL |     test = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:74:5
+  --> $DIR/well-known-values.rs:73:5
    |
 LL |     unix = "_UNEXPECTED_VALUE",
    |     ^^^^----------------------
@@ -245,7 +245,7 @@ LL |     unix = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
-  --> $DIR/well-known-values.rs:76:5
+  --> $DIR/well-known-values.rs:75:5
    |
 LL |     windows = "_UNEXPECTED_VALUE",
    |     ^^^^^^^----------------------
@@ -256,7 +256,7 @@ LL |     windows = "_UNEXPECTED_VALUE",
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `linuz`
-  --> $DIR/well-known-values.rs:82:7
+  --> $DIR/well-known-values.rs:81:7
    |
 LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    |       ^^^^^^^^^^^^-------
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs
index 048fca762d5..62efce64876 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.rs
+++ b/tests/ui/consts/const_in_pattern/issue-65466.rs
@@ -1,7 +1,3 @@
-#![deny(indirect_structural_match)]
-
-//@ check-pass
-
 #[derive(PartialEq, Eq)]
 enum O<T> {
     Some(*const T), // Can also use PhantomData<T>
@@ -15,8 +11,7 @@ const C: &[O<B>] = &[O::None];
 fn main() {
     let x = O::None;
     match &[x][..] {
-        C => (), //~WARN: the type must implement `PartialEq`
-        //~| previously accepted
+        C => (), //~ERROR: the type must implement `PartialEq`
         _ => (),
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr
index 9c80cb3a849..7d5e5b5b0c6 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr
@@ -1,23 +1,8 @@
-warning: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
-  --> $DIR/issue-65466.rs:18:9
+error: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
+  --> $DIR/issue-65466.rs:14:9
    |
 LL |         C => (),
    |         ^
-   |
-   = 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 #116122 <https://github.com/rust-lang/rust/issues/116122>
-   = note: `#[warn(const_patterns_without_partial_eq)]` on by default
-
-warning: 1 warning emitted
 
-Future incompatibility report: Future breakage diagnostic:
-warning: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
-  --> $DIR/issue-65466.rs:18:9
-   |
-LL |         C => (),
-   |         ^
-   |
-   = 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 #116122 <https://github.com/rust-lang/rust/issues/116122>
-   = note: `#[warn(const_patterns_without_partial_eq)]` on by default
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs
index 907617052f1..47a06e8a72b 100644
--- a/tests/ui/consts/promote-not.rs
+++ b/tests/ui/consts/promote-not.rs
@@ -49,6 +49,10 @@ fn main() {
     // No promotion of fallible operations.
     let _val: &'static _ = &(1/0); //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &(1/(1-1)); //~ ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &((1+1)/(1-1)); //~ ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &(i32::MIN/-1); //~ ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &(i32::MIN/(0-1)); //~ ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &(-128i8/-1); //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr
index 524d6981721..67ac5922efd 100644
--- a/tests/ui/consts/promote-not.stderr
+++ b/tests/ui/consts/promote-not.stderr
@@ -105,6 +105,50 @@ LL | }
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/promote-not.rs:52:29
    |
+LL |     let _val: &'static _ = &((1+1)/(1-1));
+   |               ----------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:53:29
+   |
+LL |     let _val: &'static _ = &(i32::MIN/-1);
+   |               ----------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:54:29
+   |
+LL |     let _val: &'static _ = &(i32::MIN/(0-1));
+   |               ----------    ^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:55:29
+   |
+LL |     let _val: &'static _ = &(-128i8/-1);
+   |               ----------    ^^^^^^^^^^^ creates a temporary value which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:56:29
+   |
 LL |     let _val: &'static _ = &(1%0);
    |               ----------    ^^^^^ creates a temporary value which is freed while still in use
    |               |
@@ -114,7 +158,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:53:29
+  --> $DIR/promote-not.rs:57:29
    |
 LL |     let _val: &'static _ = &(1%(1-1));
    |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -125,7 +169,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:54:29
+  --> $DIR/promote-not.rs:58:29
    |
 LL |     let _val: &'static _ = &([1,2,3][4]+1);
    |               ----------    ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -136,7 +180,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:57:29
+  --> $DIR/promote-not.rs:61:29
    |
 LL |     let _val: &'static _ = &TEST_DROP;
    |               ----------    ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -147,7 +191,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:59:29
+  --> $DIR/promote-not.rs:63:29
    |
 LL |     let _val: &'static _ = &&TEST_DROP;
    |               ----------    ^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -158,7 +202,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:59:30
+  --> $DIR/promote-not.rs:63:30
    |
 LL |     let _val: &'static _ = &&TEST_DROP;
    |               ----------     ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -169,7 +213,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:62:29
+  --> $DIR/promote-not.rs:66:29
    |
 LL |     let _val: &'static _ = &(&TEST_DROP,);
    |               ----------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -180,7 +224,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:62:31
+  --> $DIR/promote-not.rs:66:31
    |
 LL |     let _val: &'static _ = &(&TEST_DROP,);
    |               ----------      ^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -191,7 +235,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:65:29
+  --> $DIR/promote-not.rs:69:29
    |
 LL |     let _val: &'static _ = &[&TEST_DROP; 1];
    |               ----------    ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -202,7 +246,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:65:31
+  --> $DIR/promote-not.rs:69:31
    |
 LL |     let _val: &'static _ = &[&TEST_DROP; 1];
    |               ----------      ^^^^^^^^^    - temporary value is freed at the end of this statement
@@ -210,6 +254,6 @@ LL |     let _val: &'static _ = &[&TEST_DROP; 1];
    |               |               creates a temporary value which is freed while still in use
    |               type annotation requires that borrow lasts for `'static`
 
-error: aborting due to 20 previous errors
+error: aborting due to 24 previous errors
 
 For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/consts/promotion.rs b/tests/ui/consts/promotion.rs
index 211dcf8a4e8..b18495a4a6b 100644
--- a/tests/ui/consts/promotion.rs
+++ b/tests/ui/consts/promotion.rs
@@ -28,8 +28,11 @@ fn main() {
     // make sure that this does not cause trouble despite overflowing
     assert_static(&(0-1));
 
-    // div-by-non-0 is okay
+    // div-by-non-0 (and also not MIN/-1) is okay
     assert_static(&(1/1));
+    assert_static(&(0/1));
+    assert_static(&(1/-1));
+    assert_static(&(i32::MIN/1));
     assert_static(&(1%1));
 
     // in-bounds array access is okay
diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-abi.rs b/tests/ui/feature-gates/feature-gate-cfg-target-abi.rs
deleted file mode 100644
index d005dc3ad45..00000000000
--- a/tests/ui/feature-gates/feature-gate-cfg-target-abi.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#[cfg(target_abi = "x")] //~ ERROR `cfg(target_abi)` is experimental
-struct Foo(u64, u64);
-
-#[cfg_attr(target_abi = "x", x)] //~ ERROR `cfg(target_abi)` is experimental
-struct Bar(u64, u64);
-
-#[cfg(not(any(all(target_abi = "x"))))] //~ ERROR `cfg(target_abi)` is experimental
-fn foo() {}
-
-fn main() {
-    cfg!(target_abi = "x");
-    //~^ ERROR `cfg(target_abi)` is experimental and subject to change
-}
diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr b/tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr
deleted file mode 100644
index 4829f8572cc..00000000000
--- a/tests/ui/feature-gates/feature-gate-cfg-target-abi.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:1:7
-   |
-LL | #[cfg(target_abi = "x")]
-   |       ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #80970 <https://github.com/rust-lang/rust/issues/80970> for more information
-   = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:4:12
-   |
-LL | #[cfg_attr(target_abi = "x", x)]
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #80970 <https://github.com/rust-lang/rust/issues/80970> for more information
-   = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:7:19
-   |
-LL | #[cfg(not(any(all(target_abi = "x"))))]
-   |                   ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #80970 <https://github.com/rust-lang/rust/issues/80970> for more information
-   = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:11:10
-   |
-LL |     cfg!(target_abi = "x");
-   |          ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #80970 <https://github.com/rust-lang/rust/issues/80970> for more information
-   = help: add `#![feature(cfg_target_abi)]` 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 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
index 79a86b0a3ae..15aa3cf54bb 100644
--- a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
+++ b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
@@ -6,8 +6,6 @@ LL |     async fn foo() -> &'static impl T;
    |     |
    |     the associated type `<Self as MyTrait>::{opaque#0}` must be valid for the static lifetime...
    |     ...so that the reference type `&'static impl T` does not outlive the data it points at
-   |
-   = help: consider adding an explicit lifetime bound `<Self as MyTrait>::{opaque#0}: 'static`...
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs
new file mode 100644
index 00000000000..a36799c3ebd
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs
@@ -0,0 +1,16 @@
+trait Original {
+    fn f() -> impl Fn();
+}
+
+trait Erased {
+    fn f(&self) -> Box<dyn Fn()>;
+}
+
+impl<T: Original> Erased for T {
+    fn f(&self) -> Box<dyn Fn()> {
+        Box::new(<T as Original>::f())
+        //~^ ERROR the associated type `<T as Original>::{opaque#0}` may not live long enough
+    }
+}
+
+fn main () {}
diff --git a/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr
new file mode 100644
index 00000000000..5ec0ee38347
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr
@@ -0,0 +1,12 @@
+error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough
+  --> $DIR/missing-static-bound-from-impl.rs:11:9
+   |
+LL |         Box::new(<T as Original>::f())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime...
+   |         ...so that the type `impl Fn()` will meet its required lifetime bounds
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/lint/lint-overflowing-ops.noopt.stderr b/tests/ui/lint/lint-overflowing-ops.noopt.stderr
index f89ee8569c6..1b7b73cec38 100644
--- a/tests/ui/lint/lint-overflowing-ops.noopt.stderr
+++ b/tests/ui/lint/lint-overflowing-ops.noopt.stderr
@@ -876,498 +876,353 @@ error: this operation will panic at runtime
 LL |     let _n = &(i8::MIN / -1);
    |               ^^^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:251:15
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |               ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:251:14
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |              ^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:254:14
+  --> $DIR/lint-overflowing-ops.rs:253:14
    |
 LL |     let _n = 1i16 / 0;
    |              ^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:255:15
+  --> $DIR/lint-overflowing-ops.rs:254:15
    |
 LL |     let _n = &(1i16 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:256:14
+  --> $DIR/lint-overflowing-ops.rs:255:14
    |
 LL |     let _n = i16::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:257:15
+  --> $DIR/lint-overflowing-ops.rs:256:15
    |
 LL |     let _n = &(i16::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:257:15
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:257:14
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:260:14
+  --> $DIR/lint-overflowing-ops.rs:258:14
    |
 LL |     let _n = 1i32 / 0;
    |              ^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:261:15
+  --> $DIR/lint-overflowing-ops.rs:259:15
    |
 LL |     let _n = &(1i32 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:262:14
+  --> $DIR/lint-overflowing-ops.rs:260:14
    |
 LL |     let _n = i32::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:263:15
+  --> $DIR/lint-overflowing-ops.rs:261:15
    |
 LL |     let _n = &(i32::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:263:15
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:263:14
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:266:14
+  --> $DIR/lint-overflowing-ops.rs:263:14
    |
 LL |     let _n = 1i64 / 0;
    |              ^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:267:15
+  --> $DIR/lint-overflowing-ops.rs:264:15
    |
 LL |     let _n = &(1i64 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:268:14
+  --> $DIR/lint-overflowing-ops.rs:265:14
    |
 LL |     let _n = i64::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:269:15
+  --> $DIR/lint-overflowing-ops.rs:266:15
    |
 LL |     let _n = &(i64::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:269:15
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:269:14
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:272:14
+  --> $DIR/lint-overflowing-ops.rs:268:14
    |
 LL |     let _n = 1i128 / 0;
    |              ^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:273:15
+  --> $DIR/lint-overflowing-ops.rs:269:15
    |
 LL |     let _n = &(1i128 / 0);
    |               ^^^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:274:14
+  --> $DIR/lint-overflowing-ops.rs:270:14
    |
 LL |     let _n = i128::MIN / -1;
    |              ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:275:15
+  --> $DIR/lint-overflowing-ops.rs:271:15
    |
 LL |     let _n = &(i128::MIN / -1);
    |               ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:275:15
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |               ^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:275:14
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:278:14
+  --> $DIR/lint-overflowing-ops.rs:273:14
    |
 LL |     let _n = 1isize / 0;
    |              ^^^^^^^^^^ attempt to divide `1_isize` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:279:15
+  --> $DIR/lint-overflowing-ops.rs:274:15
    |
 LL |     let _n = &(1isize / 0);
    |               ^^^^^^^^^^^^ attempt to divide `1_isize` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:280:14
+  --> $DIR/lint-overflowing-ops.rs:275:14
    |
 LL |     let _n = isize::MIN / -1;
    |              ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:281:15
+  --> $DIR/lint-overflowing-ops.rs:276:15
    |
 LL |     let _n = &(isize::MIN / -1);
    |               ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:281:15
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |               ^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:281:14
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:286:14
+  --> $DIR/lint-overflowing-ops.rs:280:14
    |
 LL |     let _n = 1u8 % 0;
    |              ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:287:15
+  --> $DIR/lint-overflowing-ops.rs:281:15
    |
 LL |     let _n = &(1u8 % 0);
    |               ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:289:14
+  --> $DIR/lint-overflowing-ops.rs:283:14
    |
 LL |     let _n = 1u16 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:290:15
+  --> $DIR/lint-overflowing-ops.rs:284:15
    |
 LL |     let _n = &(1u16 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:292:14
+  --> $DIR/lint-overflowing-ops.rs:286:14
    |
 LL |     let _n = 1u32 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:293:15
+  --> $DIR/lint-overflowing-ops.rs:287:15
    |
 LL |     let _n = &(1u32 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:295:14
+  --> $DIR/lint-overflowing-ops.rs:289:14
    |
 LL |     let _n = 1u64 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:296:15
+  --> $DIR/lint-overflowing-ops.rs:290:15
    |
 LL |     let _n = &(1u64 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:298:14
+  --> $DIR/lint-overflowing-ops.rs:292:14
    |
 LL |     let _n = 1u128 % 0;
    |              ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:299:15
+  --> $DIR/lint-overflowing-ops.rs:293:15
    |
 LL |     let _n = &(1u128 % 0);
    |               ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:301:14
+  --> $DIR/lint-overflowing-ops.rs:295:14
    |
 LL |     let _n = 1usize % 0;
    |              ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:302:15
+  --> $DIR/lint-overflowing-ops.rs:296:15
    |
 LL |     let _n = &(1usize % 0);
    |               ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:304:14
+  --> $DIR/lint-overflowing-ops.rs:298:14
    |
 LL |     let _n = 1i8 % 0;
    |              ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:305:15
+  --> $DIR/lint-overflowing-ops.rs:299:15
    |
 LL |     let _n = &(1i8 % 0);
    |               ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:306:14
+  --> $DIR/lint-overflowing-ops.rs:300:14
    |
 LL |     let _n = i8::MIN % -1;
    |              ^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:307:15
+  --> $DIR/lint-overflowing-ops.rs:301:15
    |
 LL |     let _n = &(i8::MIN % -1);
    |               ^^^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:307:15
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |               ^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:307:14
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |              ^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:310:14
+  --> $DIR/lint-overflowing-ops.rs:303:14
    |
 LL |     let _n = 1i16 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:311:15
+  --> $DIR/lint-overflowing-ops.rs:304:15
    |
 LL |     let _n = &(1i16 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:312:14
+  --> $DIR/lint-overflowing-ops.rs:305:14
    |
 LL |     let _n = i16::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:313:15
+  --> $DIR/lint-overflowing-ops.rs:306:15
    |
 LL |     let _n = &(i16::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:313:15
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:313:14
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:316:14
+  --> $DIR/lint-overflowing-ops.rs:308:14
    |
 LL |     let _n = 1i32 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:317:15
+  --> $DIR/lint-overflowing-ops.rs:309:15
    |
 LL |     let _n = &(1i32 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:318:14
+  --> $DIR/lint-overflowing-ops.rs:310:14
    |
 LL |     let _n = i32::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:319:15
+  --> $DIR/lint-overflowing-ops.rs:311:15
    |
 LL |     let _n = &(i32::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:319:15
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:319:14
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:322:14
+  --> $DIR/lint-overflowing-ops.rs:313:14
    |
 LL |     let _n = 1i64 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:323:15
+  --> $DIR/lint-overflowing-ops.rs:314:15
    |
 LL |     let _n = &(1i64 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:324:14
+  --> $DIR/lint-overflowing-ops.rs:315:14
    |
 LL |     let _n = i64::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:325:15
+  --> $DIR/lint-overflowing-ops.rs:316:15
    |
 LL |     let _n = &(i64::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:325:15
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:325:14
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:328:14
+  --> $DIR/lint-overflowing-ops.rs:318:14
    |
 LL |     let _n = 1i128 % 0;
    |              ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:329:15
+  --> $DIR/lint-overflowing-ops.rs:319:15
    |
 LL |     let _n = &(1i128 % 0);
    |               ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:330:14
+  --> $DIR/lint-overflowing-ops.rs:320:14
    |
 LL |     let _n = i128::MIN % -1;
    |              ^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:331:15
+  --> $DIR/lint-overflowing-ops.rs:321:15
    |
 LL |     let _n = &(i128::MIN % -1);
    |               ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:331:15
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |               ^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:331:14
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:334:14
+  --> $DIR/lint-overflowing-ops.rs:323:14
    |
 LL |     let _n = 1isize % 0;
    |              ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:335:15
+  --> $DIR/lint-overflowing-ops.rs:324:15
    |
 LL |     let _n = &(1isize % 0);
    |               ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:336:14
+  --> $DIR/lint-overflowing-ops.rs:325:14
    |
 LL |     let _n = isize::MIN % -1;
    |              ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:337:15
+  --> $DIR/lint-overflowing-ops.rs:326:15
    |
 LL |     let _n = &(isize::MIN % -1);
    |               ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:337:15
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |               ^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:337:14
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:341:14
+  --> $DIR/lint-overflowing-ops.rs:329:14
    |
 LL |     let _n = [1, 2, 3][4];
    |              ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:342:15
+  --> $DIR/lint-overflowing-ops.rs:330:15
    |
 LL |     let _n = &([1, 2, 3][4]);
    |               ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
 
-error: aborting due to 215 previous errors
+error: aborting due to 203 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/lint/lint-overflowing-ops.opt.stderr b/tests/ui/lint/lint-overflowing-ops.opt.stderr
index 7ac5c4e0d76..1b7b73cec38 100644
--- a/tests/ui/lint/lint-overflowing-ops.opt.stderr
+++ b/tests/ui/lint/lint-overflowing-ops.opt.stderr
@@ -876,594 +876,353 @@ error: this operation will panic at runtime
 LL |     let _n = &(i8::MIN / -1);
    |               ^^^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:251:15
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |               ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:251:14
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |              ^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:251:14
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |              ^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:254:14
+  --> $DIR/lint-overflowing-ops.rs:253:14
    |
 LL |     let _n = 1i16 / 0;
    |              ^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:255:15
+  --> $DIR/lint-overflowing-ops.rs:254:15
    |
 LL |     let _n = &(1i16 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:256:14
+  --> $DIR/lint-overflowing-ops.rs:255:14
    |
 LL |     let _n = i16::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:257:15
+  --> $DIR/lint-overflowing-ops.rs:256:15
    |
 LL |     let _n = &(i16::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:257:15
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:257:14
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:257:14
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:260:14
+  --> $DIR/lint-overflowing-ops.rs:258:14
    |
 LL |     let _n = 1i32 / 0;
    |              ^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:261:15
+  --> $DIR/lint-overflowing-ops.rs:259:15
    |
 LL |     let _n = &(1i32 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:262:14
+  --> $DIR/lint-overflowing-ops.rs:260:14
    |
 LL |     let _n = i32::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:263:15
+  --> $DIR/lint-overflowing-ops.rs:261:15
    |
 LL |     let _n = &(i32::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:263:15
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:263:14
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:263:14
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:266:14
+  --> $DIR/lint-overflowing-ops.rs:263:14
    |
 LL |     let _n = 1i64 / 0;
    |              ^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:267:15
+  --> $DIR/lint-overflowing-ops.rs:264:15
    |
 LL |     let _n = &(1i64 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:268:14
+  --> $DIR/lint-overflowing-ops.rs:265:14
    |
 LL |     let _n = i64::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:269:15
+  --> $DIR/lint-overflowing-ops.rs:266:15
    |
 LL |     let _n = &(i64::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:269:15
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:269:14
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:269:14
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:272:14
+  --> $DIR/lint-overflowing-ops.rs:268:14
    |
 LL |     let _n = 1i128 / 0;
    |              ^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:273:15
+  --> $DIR/lint-overflowing-ops.rs:269:15
    |
 LL |     let _n = &(1i128 / 0);
    |               ^^^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:274:14
+  --> $DIR/lint-overflowing-ops.rs:270:14
    |
 LL |     let _n = i128::MIN / -1;
    |              ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:275:15
+  --> $DIR/lint-overflowing-ops.rs:271:15
    |
 LL |     let _n = &(i128::MIN / -1);
    |               ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:275:15
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |               ^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:275:14
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:275:14
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:278:14
+  --> $DIR/lint-overflowing-ops.rs:273:14
    |
 LL |     let _n = 1isize / 0;
    |              ^^^^^^^^^^ attempt to divide `1_isize` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:279:15
+  --> $DIR/lint-overflowing-ops.rs:274:15
    |
 LL |     let _n = &(1isize / 0);
    |               ^^^^^^^^^^^^ attempt to divide `1_isize` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:280:14
+  --> $DIR/lint-overflowing-ops.rs:275:14
    |
 LL |     let _n = isize::MIN / -1;
    |              ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:281:15
+  --> $DIR/lint-overflowing-ops.rs:276:15
    |
 LL |     let _n = &(isize::MIN / -1);
    |               ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:281:15
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |               ^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:281:14
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:281:14
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:286:14
+  --> $DIR/lint-overflowing-ops.rs:280:14
    |
 LL |     let _n = 1u8 % 0;
    |              ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:287:15
+  --> $DIR/lint-overflowing-ops.rs:281:15
    |
 LL |     let _n = &(1u8 % 0);
    |               ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:289:14
+  --> $DIR/lint-overflowing-ops.rs:283:14
    |
 LL |     let _n = 1u16 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:290:15
+  --> $DIR/lint-overflowing-ops.rs:284:15
    |
 LL |     let _n = &(1u16 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:292:14
+  --> $DIR/lint-overflowing-ops.rs:286:14
    |
 LL |     let _n = 1u32 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:293:15
+  --> $DIR/lint-overflowing-ops.rs:287:15
    |
 LL |     let _n = &(1u32 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:295:14
+  --> $DIR/lint-overflowing-ops.rs:289:14
    |
 LL |     let _n = 1u64 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:296:15
+  --> $DIR/lint-overflowing-ops.rs:290:15
    |
 LL |     let _n = &(1u64 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:298:14
+  --> $DIR/lint-overflowing-ops.rs:292:14
    |
 LL |     let _n = 1u128 % 0;
    |              ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:299:15
+  --> $DIR/lint-overflowing-ops.rs:293:15
    |
 LL |     let _n = &(1u128 % 0);
    |               ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:301:14
+  --> $DIR/lint-overflowing-ops.rs:295:14
    |
 LL |     let _n = 1usize % 0;
    |              ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:302:15
+  --> $DIR/lint-overflowing-ops.rs:296:15
    |
 LL |     let _n = &(1usize % 0);
    |               ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:304:14
+  --> $DIR/lint-overflowing-ops.rs:298:14
    |
 LL |     let _n = 1i8 % 0;
    |              ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:305:15
+  --> $DIR/lint-overflowing-ops.rs:299:15
    |
 LL |     let _n = &(1i8 % 0);
    |               ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:306:14
+  --> $DIR/lint-overflowing-ops.rs:300:14
    |
 LL |     let _n = i8::MIN % -1;
    |              ^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:307:15
+  --> $DIR/lint-overflowing-ops.rs:301:15
    |
 LL |     let _n = &(i8::MIN % -1);
    |               ^^^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:307:15
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |               ^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:307:14
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |              ^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:307:14
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |              ^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:310:14
+  --> $DIR/lint-overflowing-ops.rs:303:14
    |
 LL |     let _n = 1i16 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:311:15
+  --> $DIR/lint-overflowing-ops.rs:304:15
    |
 LL |     let _n = &(1i16 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:312:14
+  --> $DIR/lint-overflowing-ops.rs:305:14
    |
 LL |     let _n = i16::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:313:15
+  --> $DIR/lint-overflowing-ops.rs:306:15
    |
 LL |     let _n = &(i16::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:313:15
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:313:14
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:313:14
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:316:14
+  --> $DIR/lint-overflowing-ops.rs:308:14
    |
 LL |     let _n = 1i32 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:317:15
+  --> $DIR/lint-overflowing-ops.rs:309:15
    |
 LL |     let _n = &(1i32 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:318:14
+  --> $DIR/lint-overflowing-ops.rs:310:14
    |
 LL |     let _n = i32::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:319:15
+  --> $DIR/lint-overflowing-ops.rs:311:15
    |
 LL |     let _n = &(i32::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:319:15
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:319:14
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:319:14
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:322:14
+  --> $DIR/lint-overflowing-ops.rs:313:14
    |
 LL |     let _n = 1i64 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:323:15
+  --> $DIR/lint-overflowing-ops.rs:314:15
    |
 LL |     let _n = &(1i64 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:324:14
+  --> $DIR/lint-overflowing-ops.rs:315:14
    |
 LL |     let _n = i64::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:325:15
+  --> $DIR/lint-overflowing-ops.rs:316:15
    |
 LL |     let _n = &(i64::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:325:15
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:325:14
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:325:14
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:328:14
+  --> $DIR/lint-overflowing-ops.rs:318:14
    |
 LL |     let _n = 1i128 % 0;
    |              ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:329:15
+  --> $DIR/lint-overflowing-ops.rs:319:15
    |
 LL |     let _n = &(1i128 % 0);
    |               ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:330:14
+  --> $DIR/lint-overflowing-ops.rs:320:14
    |
 LL |     let _n = i128::MIN % -1;
    |              ^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:331:15
+  --> $DIR/lint-overflowing-ops.rs:321:15
    |
 LL |     let _n = &(i128::MIN % -1);
    |               ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:331:15
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |               ^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:331:14
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:331:14
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:334:14
+  --> $DIR/lint-overflowing-ops.rs:323:14
    |
 LL |     let _n = 1isize % 0;
    |              ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:335:15
+  --> $DIR/lint-overflowing-ops.rs:324:15
    |
 LL |     let _n = &(1isize % 0);
    |               ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:336:14
+  --> $DIR/lint-overflowing-ops.rs:325:14
    |
 LL |     let _n = isize::MIN % -1;
    |              ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:337:15
+  --> $DIR/lint-overflowing-ops.rs:326:15
    |
 LL |     let _n = &(isize::MIN % -1);
    |               ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:337:15
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |               ^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:337:14
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:337:14
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:341:14
+  --> $DIR/lint-overflowing-ops.rs:329:14
    |
 LL |     let _n = [1, 2, 3][4];
    |              ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:342:15
+  --> $DIR/lint-overflowing-ops.rs:330:15
    |
 LL |     let _n = &([1, 2, 3][4]);
    |               ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
 
-error: aborting due to 215 previous errors
+error: aborting due to 203 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr b/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr
index f89ee8569c6..1b7b73cec38 100644
--- a/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr
+++ b/tests/ui/lint/lint-overflowing-ops.opt_with_overflow_checks.stderr
@@ -876,498 +876,353 @@ error: this operation will panic at runtime
 LL |     let _n = &(i8::MIN / -1);
    |               ^^^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:251:15
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |               ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:251:14
-   |
-LL |     let _n = &(i8::MIN / -1);
-   |              ^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:254:14
+  --> $DIR/lint-overflowing-ops.rs:253:14
    |
 LL |     let _n = 1i16 / 0;
    |              ^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:255:15
+  --> $DIR/lint-overflowing-ops.rs:254:15
    |
 LL |     let _n = &(1i16 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:256:14
+  --> $DIR/lint-overflowing-ops.rs:255:14
    |
 LL |     let _n = i16::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:257:15
+  --> $DIR/lint-overflowing-ops.rs:256:15
    |
 LL |     let _n = &(i16::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:257:15
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:257:14
-   |
-LL |     let _n = &(i16::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:260:14
+  --> $DIR/lint-overflowing-ops.rs:258:14
    |
 LL |     let _n = 1i32 / 0;
    |              ^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:261:15
+  --> $DIR/lint-overflowing-ops.rs:259:15
    |
 LL |     let _n = &(1i32 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:262:14
+  --> $DIR/lint-overflowing-ops.rs:260:14
    |
 LL |     let _n = i32::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:263:15
+  --> $DIR/lint-overflowing-ops.rs:261:15
    |
 LL |     let _n = &(i32::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:263:15
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:263:14
-   |
-LL |     let _n = &(i32::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:266:14
+  --> $DIR/lint-overflowing-ops.rs:263:14
    |
 LL |     let _n = 1i64 / 0;
    |              ^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:267:15
+  --> $DIR/lint-overflowing-ops.rs:264:15
    |
 LL |     let _n = &(1i64 / 0);
    |               ^^^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:268:14
+  --> $DIR/lint-overflowing-ops.rs:265:14
    |
 LL |     let _n = i64::MIN / -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:269:15
+  --> $DIR/lint-overflowing-ops.rs:266:15
    |
 LL |     let _n = &(i64::MIN / -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:269:15
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:269:14
-   |
-LL |     let _n = &(i64::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:272:14
+  --> $DIR/lint-overflowing-ops.rs:268:14
    |
 LL |     let _n = 1i128 / 0;
    |              ^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:273:15
+  --> $DIR/lint-overflowing-ops.rs:269:15
    |
 LL |     let _n = &(1i128 / 0);
    |               ^^^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:274:14
+  --> $DIR/lint-overflowing-ops.rs:270:14
    |
 LL |     let _n = i128::MIN / -1;
    |              ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:275:15
+  --> $DIR/lint-overflowing-ops.rs:271:15
    |
 LL |     let _n = &(i128::MIN / -1);
    |               ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:275:15
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |               ^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:275:14
-   |
-LL |     let _n = &(i128::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:278:14
+  --> $DIR/lint-overflowing-ops.rs:273:14
    |
 LL |     let _n = 1isize / 0;
    |              ^^^^^^^^^^ attempt to divide `1_isize` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:279:15
+  --> $DIR/lint-overflowing-ops.rs:274:15
    |
 LL |     let _n = &(1isize / 0);
    |               ^^^^^^^^^^^^ attempt to divide `1_isize` by zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:280:14
+  --> $DIR/lint-overflowing-ops.rs:275:14
    |
 LL |     let _n = isize::MIN / -1;
    |              ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:281:15
+  --> $DIR/lint-overflowing-ops.rs:276:15
    |
 LL |     let _n = &(isize::MIN / -1);
    |               ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:281:15
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |               ^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:281:14
-   |
-LL |     let _n = &(isize::MIN / -1);
-   |              ^^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:286:14
+  --> $DIR/lint-overflowing-ops.rs:280:14
    |
 LL |     let _n = 1u8 % 0;
    |              ^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:287:15
+  --> $DIR/lint-overflowing-ops.rs:281:15
    |
 LL |     let _n = &(1u8 % 0);
    |               ^^^^^^^^^ attempt to calculate the remainder of `1_u8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:289:14
+  --> $DIR/lint-overflowing-ops.rs:283:14
    |
 LL |     let _n = 1u16 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:290:15
+  --> $DIR/lint-overflowing-ops.rs:284:15
    |
 LL |     let _n = &(1u16 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:292:14
+  --> $DIR/lint-overflowing-ops.rs:286:14
    |
 LL |     let _n = 1u32 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:293:15
+  --> $DIR/lint-overflowing-ops.rs:287:15
    |
 LL |     let _n = &(1u32 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:295:14
+  --> $DIR/lint-overflowing-ops.rs:289:14
    |
 LL |     let _n = 1u64 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:296:15
+  --> $DIR/lint-overflowing-ops.rs:290:15
    |
 LL |     let _n = &(1u64 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_u64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:298:14
+  --> $DIR/lint-overflowing-ops.rs:292:14
    |
 LL |     let _n = 1u128 % 0;
    |              ^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:299:15
+  --> $DIR/lint-overflowing-ops.rs:293:15
    |
 LL |     let _n = &(1u128 % 0);
    |               ^^^^^^^^^^^ attempt to calculate the remainder of `1_u128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:301:14
+  --> $DIR/lint-overflowing-ops.rs:295:14
    |
 LL |     let _n = 1usize % 0;
    |              ^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:302:15
+  --> $DIR/lint-overflowing-ops.rs:296:15
    |
 LL |     let _n = &(1usize % 0);
    |               ^^^^^^^^^^^^ attempt to calculate the remainder of `1_usize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:304:14
+  --> $DIR/lint-overflowing-ops.rs:298:14
    |
 LL |     let _n = 1i8 % 0;
    |              ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:305:15
+  --> $DIR/lint-overflowing-ops.rs:299:15
    |
 LL |     let _n = &(1i8 % 0);
    |               ^^^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:306:14
+  --> $DIR/lint-overflowing-ops.rs:300:14
    |
 LL |     let _n = i8::MIN % -1;
    |              ^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:307:15
+  --> $DIR/lint-overflowing-ops.rs:301:15
    |
 LL |     let _n = &(i8::MIN % -1);
    |               ^^^^^^^^^^^^^^ attempt to compute `i8::MIN % -1_i8`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:307:15
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |               ^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:307:14
-   |
-LL |     let _n = &(i8::MIN % -1);
-   |              ^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:310:14
+  --> $DIR/lint-overflowing-ops.rs:303:14
    |
 LL |     let _n = 1i16 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:311:15
+  --> $DIR/lint-overflowing-ops.rs:304:15
    |
 LL |     let _n = &(1i16 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:312:14
+  --> $DIR/lint-overflowing-ops.rs:305:14
    |
 LL |     let _n = i16::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:313:15
+  --> $DIR/lint-overflowing-ops.rs:306:15
    |
 LL |     let _n = &(i16::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i16::MIN % -1_i16`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:313:15
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:313:14
-   |
-LL |     let _n = &(i16::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:316:14
+  --> $DIR/lint-overflowing-ops.rs:308:14
    |
 LL |     let _n = 1i32 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:317:15
+  --> $DIR/lint-overflowing-ops.rs:309:15
    |
 LL |     let _n = &(1i32 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:318:14
+  --> $DIR/lint-overflowing-ops.rs:310:14
    |
 LL |     let _n = i32::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:319:15
+  --> $DIR/lint-overflowing-ops.rs:311:15
    |
 LL |     let _n = &(i32::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:319:15
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:319:14
-   |
-LL |     let _n = &(i32::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:322:14
+  --> $DIR/lint-overflowing-ops.rs:313:14
    |
 LL |     let _n = 1i64 % 0;
    |              ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:323:15
+  --> $DIR/lint-overflowing-ops.rs:314:15
    |
 LL |     let _n = &(1i64 % 0);
    |               ^^^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:324:14
+  --> $DIR/lint-overflowing-ops.rs:315:14
    |
 LL |     let _n = i64::MIN % -1;
    |              ^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:325:15
+  --> $DIR/lint-overflowing-ops.rs:316:15
    |
 LL |     let _n = &(i64::MIN % -1);
    |               ^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:325:15
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |               ^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:325:14
-   |
-LL |     let _n = &(i64::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:328:14
+  --> $DIR/lint-overflowing-ops.rs:318:14
    |
 LL |     let _n = 1i128 % 0;
    |              ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:329:15
+  --> $DIR/lint-overflowing-ops.rs:319:15
    |
 LL |     let _n = &(1i128 % 0);
    |               ^^^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:330:14
+  --> $DIR/lint-overflowing-ops.rs:320:14
    |
 LL |     let _n = i128::MIN % -1;
    |              ^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:331:15
+  --> $DIR/lint-overflowing-ops.rs:321:15
    |
 LL |     let _n = &(i128::MIN % -1);
    |               ^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN % -1_i128`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:331:15
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |               ^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:331:14
-   |
-LL |     let _n = &(i128::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:334:14
+  --> $DIR/lint-overflowing-ops.rs:323:14
    |
 LL |     let _n = 1isize % 0;
    |              ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:335:15
+  --> $DIR/lint-overflowing-ops.rs:324:15
    |
 LL |     let _n = &(1isize % 0);
    |               ^^^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:336:14
+  --> $DIR/lint-overflowing-ops.rs:325:14
    |
 LL |     let _n = isize::MIN % -1;
    |              ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:337:15
+  --> $DIR/lint-overflowing-ops.rs:326:15
    |
 LL |     let _n = &(isize::MIN % -1);
    |               ^^^^^^^^^^^^^^^^^ attempt to compute `isize::MIN % -1_isize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
-  --> $DIR/lint-overflowing-ops.rs:337:15
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |               ^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1)
-
-note: erroneous constant encountered
-  --> $DIR/lint-overflowing-ops.rs:337:14
-   |
-LL |     let _n = &(isize::MIN % -1);
-   |              ^^^^^^^^^^^^^^^^^^
-
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:341:14
+  --> $DIR/lint-overflowing-ops.rs:329:14
    |
 LL |     let _n = [1, 2, 3][4];
    |              ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
 
 error: this operation will panic at runtime
-  --> $DIR/lint-overflowing-ops.rs:342:15
+  --> $DIR/lint-overflowing-ops.rs:330:15
    |
 LL |     let _n = &([1, 2, 3][4]);
    |               ^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
 
-error: aborting due to 215 previous errors
+error: aborting due to 203 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/lint/lint-overflowing-ops.rs b/tests/ui/lint/lint-overflowing-ops.rs
index 4ef99f6c5fa..3aadf773243 100644
--- a/tests/ui/lint/lint-overflowing-ops.rs
+++ b/tests/ui/lint/lint-overflowing-ops.rs
@@ -249,37 +249,31 @@ fn main() {
     let _n = &(1i8 / 0);   //~ ERROR: this operation will panic at runtime
     let _n = i8::MIN / -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i8::MIN / -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i16 / 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i16 / 0); //~ ERROR: this operation will panic at runtime
     let _n = i16::MIN / -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i16::MIN / -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i32 / 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i32 / 0); //~ ERROR: this operation will panic at runtime
     let _n = i32::MIN / -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i32::MIN / -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i64 / 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i64 / 0); //~ ERROR: this operation will panic at runtime
     let _n = i64::MIN / -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i64::MIN / -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i128 / 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i128 / 0); //~ ERROR: this operation will panic at runtime
     let _n = i128::MIN / -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i128::MIN / -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1isize / 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1isize / 0); //~ ERROR: this operation will panic at runtime
     let _n = isize::MIN / -1; //~ ERROR: this operation will panic at runtime
     let _n = &(isize::MIN / -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
 
     // Modulus
@@ -305,37 +299,31 @@ fn main() {
     let _n = &(1i8 % 0);   //~ ERROR: this operation will panic at runtime
     let _n = i8::MIN % -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i8::MIN % -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i16 % 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i16 % 0); //~ ERROR: this operation will panic at runtime
     let _n = i16::MIN % -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i16::MIN % -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i32 % 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i32 % 0); //~ ERROR: this operation will panic at runtime
     let _n = i32::MIN % -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i32::MIN % -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i64 % 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i64 % 0); //~ ERROR: this operation will panic at runtime
     let _n = i64::MIN % -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i64::MIN % -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1i128 % 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1i128 % 0); //~ ERROR: this operation will panic at runtime
     let _n = i128::MIN % -1; //~ ERROR: this operation will panic at runtime
     let _n = &(i128::MIN % -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     let _n = 1isize % 0; //~ ERROR: this operation will panic at runtime
     let _n = &(1isize % 0); //~ ERROR: this operation will panic at runtime
     let _n = isize::MIN % -1; //~ ERROR: this operation will panic at runtime
     let _n = &(isize::MIN % -1); //~ ERROR: this operation will panic at runtime
-    //~^ERROR: evaluation of constant value failed
 
     // Out of bounds access
     let _n = [1, 2, 3][4]; //~ ERROR: this operation will panic at runtime
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.rs b/tests/ui/match/issue-72896-non-partial-eq-const.rs
index d4972714608..f15eae83896 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.rs
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.rs
@@ -1,4 +1,3 @@
-//@ run-pass
 trait EnumSetType {
     type Repr;
 }
@@ -17,8 +16,7 @@ const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
 
 fn main() {
     match CONST_SET {
-        CONST_SET => { /* ok */ } //~WARN: must implement `PartialEq`
-        //~| previously accepted
+        CONST_SET => { /* ok */ } //~ERROR: must implement `PartialEq`
         _ => panic!("match fell through?"),
     }
 }
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
index a7fc0cfc054..4155586c160 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
@@ -1,23 +1,8 @@
-warning: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
-  --> $DIR/issue-72896-non-partial-eq-const.rs:20:9
+error: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
+  --> $DIR/issue-72896-non-partial-eq-const.rs:19:9
    |
 LL |         CONST_SET => { /* ok */ }
    |         ^^^^^^^^^
-   |
-   = 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 #116122 <https://github.com/rust-lang/rust/issues/116122>
-   = note: `#[warn(const_patterns_without_partial_eq)]` on by default
-
-warning: 1 warning emitted
 
-Future incompatibility report: Future breakage diagnostic:
-warning: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
-  --> $DIR/issue-72896-non-partial-eq-const.rs:20:9
-   |
-LL |         CONST_SET => { /* ok */ }
-   |         ^^^^^^^^^
-   |
-   = 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 #116122 <https://github.com/rust-lang/rust/issues/116122>
-   = note: `#[warn(const_patterns_without_partial_eq)]` on by default
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.rs b/tests/ui/simd/not-out-of-bounds.rs
index 158e9956435..36d7a5865bc 100644
--- a/tests/ui/simd/shuffle-not-out-of-bounds.rs
+++ b/tests/ui/simd/not-out-of-bounds.rs
@@ -1,6 +1,6 @@
 //@ build-fail
 #![allow(non_camel_case_types)]
-#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_simd, core_intrinsics)]
 
 // Test for #73542 to verify out-of-bounds shuffle vectors do not compile.
 
@@ -28,9 +28,7 @@ struct u8x32([u8; 32]);
 #[derive(Copy, Clone)]
 struct u8x64([u8; 64]);
 
-extern "platform-intrinsic" {
-    pub fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
-}
+use std::intrinsics::simd::*;
 
 // Test vectors by lane size. Since LLVM does not distinguish between a shuffle
 // over two f32s and a shuffle over two u64s, or any other such combination,
@@ -70,13 +68,16 @@ fn main() {
     test_shuffle_lanes!(32, u8x32, simd_shuffle);
     test_shuffle_lanes!(64, u8x64, simd_shuffle);
 
-    extern "platform-intrinsic" {
-        fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
-    }
     let v = u8x2([0, 0]);
     const I: [u32; 2] = [4, 4];
     unsafe {
         let _: u8x2 = simd_shuffle(v, v, I);
         //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic
     }
+
+    // also check insert/extract
+    unsafe {
+        simd_insert(v, 2, 0); //~ ERROR invalid monomorphization of `simd_insert` intrinsic
+        let _val: u8 = simd_extract(v, 2); //~ ERROR invalid monomorphization of `simd_extract` intrinsic
+    }
 }
diff --git a/tests/ui/simd/shuffle-not-out-of-bounds.stderr b/tests/ui/simd/not-out-of-bounds.stderr
index 59e5ab85866..5682935c1f1 100644
--- a/tests/ui/simd/shuffle-not-out-of-bounds.stderr
+++ b/tests/ui/simd/not-out-of-bounds.stderr
@@ -1,5 +1,5 @@
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
-  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4)
+  --> $DIR/not-out-of-bounds.rs:49:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
@@ -9,8 +9,8 @@ LL |     test_shuffle_lanes!(2, u8x2, simd_shuffle);
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 8)
-  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 8)
+  --> $DIR/not-out-of-bounds.rs:49:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
@@ -20,8 +20,8 @@ LL |     test_shuffle_lanes!(4, u8x4, simd_shuffle);
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 16)
-  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 16)
+  --> $DIR/not-out-of-bounds.rs:49:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
@@ -31,8 +31,8 @@ LL |     test_shuffle_lanes!(8, u8x8, simd_shuffle);
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 32)
-  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 32)
+  --> $DIR/not-out-of-bounds.rs:49:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
@@ -42,8 +42,8 @@ LL |     test_shuffle_lanes!(16, u8x16, simd_shuffle);
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 64)
-  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 64)
+  --> $DIR/not-out-of-bounds.rs:49:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
@@ -53,8 +53,8 @@ LL |     test_shuffle_lanes!(32, u8x32, simd_shuffle);
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 128)
-  --> $DIR/shuffle-not-out-of-bounds.rs:51:21
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 128)
+  --> $DIR/not-out-of-bounds.rs:49:21
    |
 LL |                     $y(vec1, vec2, ARR)
    |                     ^^^^^^^^^^^^^^^^^^^
@@ -64,12 +64,24 @@ LL |     test_shuffle_lanes!(64, u8x64, simd_shuffle);
    |
    = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4)
-  --> $DIR/shuffle-not-out-of-bounds.rs:79:23
+error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: SIMD index #0 is out of bounds (limit 4)
+  --> $DIR/not-out-of-bounds.rs:74:23
    |
 LL |         let _: u8x2 = simd_shuffle(v, v, I);
    |                       ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `u8` (element of input `u8x2`), found `i32`
+  --> $DIR/not-out-of-bounds.rs:80:9
+   |
+LL |         simd_insert(v, 2, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_extract` intrinsic: SIMD index #1 is out of bounds (limit 2)
+  --> $DIR/not-out-of-bounds.rs:81:24
+   |
+LL |         let _val: u8 = simd_extract(v, 2);
+   |                        ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0511`.